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

本文转载自: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: 方法来获取整个数据。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容