zoukankan      html  css  js  c++  java
  • ble编程-外设发送数据到中心

    一、外设

    1.在外设的.h文件中定义如下

     
     1 //周边管理者
     2 
     3 @property (nonatomic , strong) CBPeripheralManager      *peripheralManager;
     4 
     5 // 中心
     6 
     7 @property (nonatomic,strong) CBCentral                  *central;
     8 
     9 // 特征
    10 
    11 @property (nonatomic , strong) CBMutableCharacteristic  *customCharacteristic;
    12 
    13 // 服务
    14 
    15 @property (nonatomic , strong) CBMutableService         *customService;
    16 
    17 // 向中心发送的数据
    18 
    19 @property (strong, nonatomic) NSData                    *dataToSend;
    20 
    21 @property (nonatomic, readwrite) NSInteger              sendDataIndex;
     
     

    2.然后在.m文件中进行如下操作

    2.1在viewDidLoad方法中初始化外设和要发送的数据

    1 // 初始化外设
    2 self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
    3 // 初始化数据
    4 self.dataToSend = [@"snadjfkhaw加大困难的是咖啡euijferlfmn ksxncjxznvjeajfrnjadnfjasfndsafnjsadkfnjsa" dataUsingEncoding:NSUTF8StringEncoding];

    2.2 Peripheral Manager被创建,状态改变时调用

           CBPeripheralManagerStatePoweredOff 设备关闭状态

           CBPeripheralManagerStateUnauthorized 未授权

           CBPeripheralManagerStateUnsupported 您的设备不支持蓝牙4.0

           CBPeripheralManagerStateResetting 重置状态

           CBPeripheralManagerStateUnknown 未知状态

     
     1 - (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral
     2 
     3 {
     4 
     5     switch (peripheral.state) {
     6 
     7         case CBPeripheralManagerStatePoweredOn: 
     8 
     9             NSLog(@"蓝牙设备已经打开,可以扫描外设");
    10 
    11             [self setupService];
    12 
    13             break;
    14 
    15         default:
    16 
    17             NSLog(@"外设改变状态");
    18 
    19             break;
    20 
    21     }
    22 
    23 }
    24 
    25 - (void)setupService
    26 
    27 {
    28 
    29     //creates the characteristic UUID
    30 
    31     CBUUID *characteristicUUID = [CBUUID UUIDWithString:kCharacteristicUUID];
    32 
    33     //create the characteristic
    34 
    35     self.customCharacteristic = [[CBMutableCharacteristic alloc] initWithType:characteristicUUID
    36 
    37                                                                    properties:CBCharacteristicPropertyNotify
    38 
    39                                                                         value:nil
    40 
    41                                                                   permissions:CBAttributePermissionsReadable];
    42 
    43     //create the service UUID
    44 
    45     CBUUID *servieceUUID = [CBUUID UUIDWithString:kServiceUUID];
    46 
    47     //creates the service and adds the charecteristic to it
    48 
    49     self.customService = [[CBMutableService alloc] initWithType:servieceUUID primary:YES];
    50 
    51     //sets the characteristics for this service
    52 
    53     [self.customService setCharacteristics:@[self.customCharacteristic]];
    54 
    55     // And add it to the peripheral manager
    56 
    57     [self.peripheralManager addService:self.customService];
    58 
    59 }
     

     2.3 当你执行addService方法后执行如下回调

     
     1 - (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error {
     2     if (error != nil) {
     3         NSLog(@"%s,error = %@",__PRETTY_FUNCTION__, error.localizedDescription);
     4     } else {
     5         //starts advertising the service
     6         [self.peripheralManager startAdvertising:@{CBAdvertisementDataLocalNameKey:@"服务门店",
     7                                                CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:kServiceUUID]]}];
     8 
     9     }
    10 }
     
     

     2.4 central订阅了characteristic的值,当更新值的时候peripheral会调用

     
     1 - (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic
     2 {
     3     self.central = central;
     4     if (_lastDeviceUUID == central.identifier) {
     5         return;
     6     }
     7     _lastDeviceUUID = central.identifier;
     8     self.sendDataIndex = 0;
     9      [self sendData];
    10 }
    11 
    12 
    13 #pragma mark - 向客户端发消息
    14 - (void)sendData {
    15     
    16     //   标记是否为最后一次发送
    17     static BOOL sendingEOM = NO;
    18     //    1. 如果是最后一次发送
    19     if (sendingEOM) {
    20         //        只发送 "EOM" 表示结束
    21         BOOL didSend = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.customCharacteristic onSubscribedCentrals:@[self.central]];
    22         
    23         //        1.1. 最后一次发送成功
    24         if (didSend) {
    25             sendingEOM = NO;
    26             NSLog(@"Sent: EOM");
    27         }
    28         return;
    29     }
    30     //    2. 不是最后一次发送,且数据为空,则返回
    31     if (self.sendDataIndex >= self.dataToSend.length) {
    32         return;
    33     }
    34     //    3. 数据尚未发送完成,继续发送直到完成
    35     BOOL didSend = YES;
    36     while (didSend) {
    37         //        3.1. 计算剩余多大数据量需要发送
    38         NSInteger amountToSend = self.dataToSend.length - self.sendDataIndex;
    39         //           不能大于20个字节
    40         if (amountToSend > NOTIFY_MTU)
    41             amountToSend = NOTIFY_MTU;
    42         //        3.2. copy出我们想要发送的数据
    43         NSData *chunk = [NSData dataWithBytes:self.dataToSend.bytes+self.sendDataIndex length:amountToSend];
    44         //        3.3. 发送
    45         didSend = [self.peripheralManager updateValue:chunk forCharacteristic:self.customCharacteristic onSubscribedCentrals:@[self.central]];
    46         //        3.4. 如果没有发送成功,重新发送
    47          // If it didn't work, drop out and wait for the callback
    48         if (!didSend) {
    49             NSLog(@"SEND ERROR");
    50             return;
    51         }
    52         NSString *stringFromData = [[NSString alloc] initWithData:chunk encoding:NSUTF8StringEncoding];
    53         NSLog(@"Sent: %@", stringFromData);
    54         //        3.5. 发送成功,修改已经发送成功数据index值
    55         self.sendDataIndex += amountToSend;
    56         //        3.6. 如果是最后一次需要发送
    57         if (self.sendDataIndex >= self.dataToSend.length) {
    58             // 3.6.1. 把 标识是否为最后一次发送 改为YES
    59             sendingEOM = YES;
    60             // 3.6.2. 发送
    61             BOOL eomSent = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.customCharacteristic onSubscribedCentrals:@[self.central]];
    62             if (eomSent) {
    63                 // 3.6.3. 发送成功,则我们已经完成这个功能
    64                 sendingEOM = NO;
    65                 NSLog(@"Sent: EOM");
    66             }
    67             return;
    68         }
    69     }
    70 }
     

     2.5 peripheral再次准备好发送Characteristic值的更新时候调用

    1 - (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral
    2 {
    3     [self sendData];
    4 }

     2.6 当central取消订阅characteristic这个特征的值后调用方法

    1 - (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic
    2 {
    3     NSLog(@"central=%@设备拒绝请求,%s,",central,__PRETTY_FUNCTION__);
    4 }
     

    二、中心

    1.在中心的.h文件中定义如下

     
    1 /**
    2  * 中心角色
    3  */
    4 @property (nonatomic , strong) CBCentralManager *centralManager;
    5 @property (nonatomic , strong) CBPeripheral *peripheral;
    6 @property (nonatomic, strong) CBCharacteristic *character;
    7 @property (nonatomic , strong) NSMutableData *data;
     

    2.然后在.m文件中进行如下操作

    2.1在viewDidLoad方法中初始化中心和要发送的数据

    1     //    1.建立中心角色,queue为执行队列,默认为主线程
    2     self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
    3     //    2.初始化显示控件
    4     [self setupUI];
    5     //    3.初始化data
    6     _data = [[NSMutableData alloc] init];
     

    2.2 CBCentralManagerDelegate代理方法

     回调,返回当前设备蓝牙状态

     
     1 #pragma mark - CBCentralManagerDelegate 
     2 #pragma mark 回调,返回当前设备蓝牙状态
     3 - (void)centralManagerDidUpdateState:(CBCentralManager *)central {
     4 
     5     switch (central.state) {
     6         case CBCentralManagerStatePoweredOn:{
     7             // 扫描外设(discover)
     8             _messageLabel.text = @"蓝牙设备已经打开,可以扫描外设";
     9             [self scan];
    10         }
    11             break;
    12         default:
    13             break;
    14     }
    15 }
    16 
    17 #pragma mark - 扫描外设(discover) 超时停止扫描
    18 - (void)scan{
    19     /**
    20      * 第一个参数指定了要搜寻的服务,如果传nil,表示搜寻搜所有的服务
    21      * 第二个参数指定了CBCentralManagerScanOptionAllowDuplicatesKey为已发现的设备是否重复扫描,
    22      *      如果是同一设备不会多次回调。
    23      */
    24     [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:kServiceUUID]]                                        options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}];
    25 
    26 }
    27  
     

     发现外设,回调

     
     1 - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
     2 
     3     NSLog(@"找到了服务:%@,信号质量:%@",advertisementData,RSSI);
     4     self.serviceName = [advertisementData objectForKey:@"kCBAdvDataLocalName"];
     5 
     6     if (self.peripheral != peripheral) {
     7         self.peripheral = peripheral;
     8         NSLog(@"开始连接blueServer:%@",peripheral);
     9         [self.centralManager connectPeripheral:self.peripheral options:nil];
    10     }
    11 }
     

     连接失败,回调

    1 - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    2     NSLog(@"Failed to connect to %@. (%@)", peripheral, [error localizedDescription]);
    3     [self cleanup];
    4 }

     连接成功,回调 

     
     1 - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
     2     //因为一个peripheral可能不止提供一个service
     3     NSLog(@"连接成功,进一步获取peripheral的service");
     4     [self.centralManager stopScan];
     5 
     6     //    每过 0.1 秒钟执行一次 readBLEServiceRSSI 方法
     7     self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(readBLEServiceRSSI) userInfo:nil repeats:YES];
     8 
     9     [self.data setLength:0];
    10 
    11     //    设置代理
    12     self.peripheral.delegate = self;
    13 
    14     //查询符合条件的外设
    15     [self.peripheral discoverServices:@[[CBUUID UUIDWithString:kServiceUUID]]];
    16 }
    17 
    18  
     

     失去连接,回调

    1 - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    2     NSLog(@"Failed to connect to %@. (%@)", peripheral, [error localizedDescription]);
    3     [self cleanup];
    4 }

     2.3 CBPeripheralDelegate代理方法

      读取到RSSI值后的操作

     
    1 - (void)peripheralDidUpdateRSSI:(CBPeripheral *)peripheral error:(NSError *)error {
    2     NSLog(@"%s,%@",__PRETTY_FUNCTION__,peripheral);
    3     int rssi = abs([peripheral.RSSI intValue]);
    4     CGFloat ci = (rssi - 49) / (10 * 4.);
    5 
    6     self.messageLabel.text = [NSString stringWithFormat:@"发现BLT4.0热点:%@,距离:%.1fm",self.serviceName,pow(10,ci)];
    7 }
     

      找到我们刚刚指定的服务

     
     1 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
     2     if (error) {
     3         NSLog(@"%s,error=%@", __PRETTY_FUNCTION__, error.localizedDescription);
     4         [self cleanup];
     5         return;
     6     } else {
     7         for (CBService *service in peripheral.services) {
     8             NSLog(@"发现UUID=%@的服务",service.UUID);
     9             NSLog(@"开始检测这个服务的特征码...");
    10             if ([service.UUID isEqual:[CBUUID UUIDWithString:kServiceUUID]]) {
    11                 [self.peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:kCharacteristicUUID]] forService:service];
    12             }
    13         }
    14     }
    15 }
     

      如果一个特征被检测到,回调

     
     1 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
     2     if (error) {
     3         NSLog(@"%s,%@",__PRETTY_FUNCTION__,error);
     4         [self cleanup];
     5         return;
     6     } else {
     7         if ([service.UUID isEqual:[CBUUID UUIDWithString:kServiceUUID]]) {
     8             for (CBCharacteristic *characteristic in service.characteristics) {
     9                 if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]]) {
    10                     [peripheral setNotifyValue:YES
    11                              forCharacteristic:characteristic];
    12                     self.character=characteristic;
    13                 }
    14             }
    15         }
    16     }
    17 }
     

      处理蓝牙发过来的数据 

     
     1 - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
     2     if (error) {
     3         NSLog(@"didUpdateValueForCharacteristic - Error discovering characteristics: %@", [error localizedDescription]);
     4         return;
     5     }
     6     NSString *stringFromData = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
     7     // 如果我们获得了所有的数据
     8     if ([stringFromData isEqualToString:@"EOM"]) {
     9         // 显示数据
    10         [self alarm:self.data];
    11         // 取消订阅
    12         [peripheral setNotifyValue:NO forCharacteristic:characteristic];
    13         // 让中心失去和设备的连接
    14         [self.centralManager cancelPeripheralConnection:peripheral];
    15     }
    16     // 否则,拼接数据
    17     [self.data appendData:characteristic.value];
    18     // Log it
    19     NSLog(@"Received: %@", stringFromData);
    20 }
     

     外围设备是否被注销

     
     1 - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
     2     if (error) {
     3         NSLog(@"%s,%@",__PRETTY_FUNCTION__,error.localizedDescription);
     4     }
     5     if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]]) {
     6         return;
     7     }
     8     //已经发送通知
     9     if (characteristic.isNotifying) {
    10         NSLog(@"Notification began on %@",characteristic);
    11     } else {
    12         //Notification has stopped
    13         //so disconnect from the peripheral
    14         NSLog(@"Notification stopped on %@ Disconnecting",characteristic);
    15         [self.centralManager cancelPeripheralConnection:self.peripheral];
    16     }
    17 }
     

    2.4 出现错误或者结束连接时调用(私有方法)

     
     1 #pragma mark - Call this when things either go wrong, or you're done with the connection.
     2 - (void)cleanup {
     3     // Don't do anything if we're not connected
     4     if (!self.peripheral.isConnected) {
     5         return;
     6     }
     7     // See if we are subscribed to a characteristic on the peripheral
     8     if (self.peripheral.services != nil) {
     9         for (CBService *service in self.peripheral.services) {
    10             if (service.characteristics != nil) {
    11                 for (CBCharacteristic *characteristic in service.characteristics) {
    12                     if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:kCharacteristicUUID]]) {
    13                         if (characteristic.isNotifying) {
    14                             // It is notifying, so unsubscribe
    15                             [self.peripheral setNotifyValue:NO forCharacteristic:characteristic];
    16                             // And we're done.
    17                             return;
    18                         }
    19                     }
    20                 }
    21             }
    22         }
    23     }
    24     // If we've got this far, we're connected, but we're not subscribed, so we just disconnect
    25     [self.centralManager cancelPeripheralConnection:self.peripheral];
    26 }
  • 相关阅读:
    Lookup 组件用法全解
    将字符串转换成表
    处于同一域中的两台SQL Server 实例无法连接
    在SSIS中的不同组件间使用局部临时表
    SSIS的CheckPoint用法
    控制流如何处理错误
    SSIS 对数据排序
    SSIS 数据输出列因为字符截断而失败
    SQL Server 的本地时间和UTC时间
    TSQL Merge 用法
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/11213819.html
Copyright © 2011-2022 走看看