美文网首页iOS 蓝牙开发学习笔记
ios蓝牙开发学习笔记(三)peripheral角色的实现

ios蓝牙开发学习笔记(三)peripheral角色的实现

作者: idiot_lin | 来源:发表于2016-12-01 09:24 被阅读149次

    本文转载自:http://blog.csdn.net/swibyn/article/details/52096475

    Performing Common Peripheral Role Tasks

    peripheral角色的实现

    • Start up a peripheral manager object
    • Set up services and characteristics on your local peripheral
    • Publish your services and characteristics to your device’s local database
    • Advertise your services
    • Respond to read and write requests from a connected central
    • Send updated characteristic values to subscribed centrals

    作为peripheral模式使用的操作步骤
    1,创建peripheral manager 对象
    2,构建services和characteristics
    3,发布services和characteristics 到数据库
    4,广播你的服务
    5,响应读和写请求
    6,发送数据给centrals订阅者

    Starting Up a Peripheral Manager

    创建外设管理器

    myPeripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil options:nil];

    创建的时候,peripheral manager将调用代理对象的peripheralManagerDidUpdateState:方法

    Setting Up Your Services and Characteristics

    构建服务和特征值

    services 和 characteristic是树形结构组织的

    服务和特征值使用uuid标识

    CBUUID *heartRateServiceUUID = [CBUUID UUIDWithString: @"180D"];

    为services和characteristics创建你自己的UUID

    CBUUID *myCustomServiceUUID = [CBUUID UUIDWithString:@"71DA3FD1-7E10-41C1-B16F-4430B506CDE7"];

    构建services和characteritics树

    myCharacteristic = [[CBMutableCharacteristic alloc] initWithType:myCharacteristicUUID properties:CBCharacteristicPropertyRead value:myValue permissions:CBAttributePermissionsReadable];

    propeties和permissions的设置决定了这个characteristic是否可读,是否可写,是否可订阅。上例中我们把它设置成可读。

    注意:如果你设置value的值,这个值将被缓存,并且properties和permissions将是只读的。因此,如果你希望value是可写的,或value值根据具体情况呈不同的值时,你必须把它设置成nil。这样才能使它被动态赋值。才能响应peripheral manager的请求。

    创建service

    myService = [[CBMutableService alloc] initWithType:myServiceUUID primary:YES];

    这里的第二个参数设置为YES,标明这个服务值主要的。主要服务体现了主要的功能,并能够被其它服务引用。次要服务只用来描述其引用的服务的相关的信息。比如,心率监控的主要服务用来显示心率数据,这时次要服务可能就用来显示电池数据。

    关联characteristics

    myService.characteristics = @[myCharacteristic];

    Publishing Your Services and Characteristics

    发布服务和特征值

    [myPeripheralManager addService:myService];

    这里会触发代理消息

    • (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error{
      if (error){
      NSLog(@"Error publishing service: %@", [error localizedDescription]);
      }

    ...

    如果有异常,请通过error查询。
    注意:服务和特征值一旦发布,不能更改。

    Advertising Your Services

    广播你的服务

    [myPeripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey :@[myFirstService.UUID, mySecondService.UUID] }];

    例子中参数是dictionary,不是array。并且只有一个key。在这里只支持两个key,CBAdvertisementDataLocalNameKey 和 CBAdvertisementDataServiceUUIDsKey。详情参见Advertisement Data Retrieval Keys in CBCentralManagerDelegate Protocol Reference.

    当你开始广播你的服务,peripheral manager就会通知代理peripheralManagerDidStartAdvertising:error:
    。如果有异常将不会发出广播,并在代理中可查到异常的原因:

    • (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error {
      if (error) {
      NSLog(@"Error advertising: %@", [error localizedDescription]);
      }
      ...

    当你发出广播后,远程的centrals将可发现并初始化来取得连接。

    Responding to Read and Write Requests from a Central

    在连接到remote centrals之后,你就可以开始接收读或写请求。
    当central有读请求时,peripheral manager调用 peripheralManager:didReceiveReadRequest: 代理方法。并把请求信息通过CBATTRequest传过来。
    比如当你收到一个读请求时,CBATTRequest对象的属性可以确保设备的数据库中的特征值能匹配central所标记的那个特征值。代理的方法实现类似如下:

    • (void)peripheralManager:(CBPeripheralManager *)peripheral
      didReceiveReadRequest:(CBATTRequest *)request {
      if ([request.characteristic.UUID isEqual:myCharacteristic.UUID]) {
      ...

    如果特征值的UUID匹配,下一步就是确保请求所读的数据不越界

    if (request.offset > myCharacteristic.value.length) {
    [myPeripheralManager respondToRequest:request
    withResult:CBATTErrorInvalidOffset];
    return;
    }

    如果请求的偏移量没有越界,那么设置请求的值

    request.value = [myCharacteristic.value subdataWithRange:NSMakeRange(request.offset,myCharacteristic.value.length - request.offset)];

    设置好返回值之后,使用respondToRequest:withResult: 方法来返回数据,类似如下:

    [myPeripheralManager respondToRequest:request withResult:CBATTErrorSuccess];

    每次收到的请求peripheralManager:didReceiveReadRequest: 都应该有相应的返回respondToRequest:withResult: 方法。

    注意:假如特征值的UUID不匹配,或是读请求由于某些原因无法完成。你也应该调用respondToRequest:withResult: 方法来返回失败结果。失败结果列表参见CBATTError Constants enumeration in Core Bluetooth Constants Reference

    写请求的处理也很简单。当central发送请求要求写数据时,peripheral manager调用peripheralManager:didReceiveWriteRequests:代理方法,数据通过参数CBATTRequest传递给你,每一个代表一次写请求,当写请求可被处理,你就可以设置特征值的值,如下:

    myCharacteristic.value = request.value;

    这里同样需要注意请求的偏移量问题,虽然上例中未体现。

    跟读请求相似,每次都要调用respondToRequest:withResult: 方法来回应消息。也就是说,虽然代理中入参是array,可能包含多个CBATTRequest,但是回应时是单个的CBATTRequest对象。你必须传入array中的第一个对象。如下:

    [myPeripheralManager respondToRequest:[requests objectAtIndex:0] withResult:CBATTErrorSuccess];

    注意:把多个请求看成一个对待,如果其中有一个请求无法实现,那么所有的请求就将无法实现。同时,调用respondToRequest:withResult: 方法回应,并提供失败的原因。

    Sending Updated Characteristic Values to Subscribed Centrals

    通常,centrals可以订阅一个或多个特征值,这在Subscribing to a Characteristic’s Value. 中也有描述。这种情况下如果他们订阅的特征值的值有变化,你应该要能够给他们发消息。

    当一个central订阅某个特征值,peripheral manager将通知代理peripheralManager:central:didSubscribeToCharacteristic: 方法

    • (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic {
      NSLog(@"Central subscribed to characteristic %@", characteristic);
      。。。

    下一步就是获取更新的值并发送给central.

    NSData *updatedValue = // fetch the characteristic's new value
    BOOL didSendValue = [myPeripheralManager updateValue:updatedValue forCharacteristic:characteristic onSubscribedCentrals:nil];

    在你调用这个方法来发送数据给订阅者时,你可以在最后一个参数标明哪个central,如上。如果你写nil,所有连接着的有订阅的centrals都将收到信息,当然有连接但没订阅的会被忽略。

    updateValue:forCharacteristic:onSubscribedCentrals: 这个方法返回Boolean值,指明数据是否成功发送。如果底层的队列正在传输数据,这个方法就会返回NO。当传输队列重新变为空闲时,则会调用peripheral manager的代理方法peripheralManagerIsReadyToUpdateSubscribers: ,这时你就可以利用这个代理重新发送数据,而不需要重新调用updateValue:forCharacteristic:onSubscribedCentrals: 方法。

    注意:使用通知来发送一个数据包给central订阅者。也就是说,当你需要给订阅者更新数据时,你应该在通知中发送整个数据,通过一次调用updateValue:forCharacteristic:onSubscribedCentrals: 方法来实现。局限于特征值数据大小的限制,并不是所有数据都能用通知来传递。这种情况下,应该由central端通过调用CBPeripheral的readValueForCharacteristic: 方法来获取整个数据。

    相关文章

      网友评论

        本文标题:ios蓝牙开发学习笔记(三)peripheral角色的实现

        本文链接:https://www.haomeiwen.com/subject/hootmttx.html