我已经为蓝牙BLE整理了一些非常基本的iOS Objective-C代码,旨在连接并从自定义外围设备获取通知。自定义设备每秒更新1x特征值。
更新特征值时,回调方法不会(似乎)触发:
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
尽管以下代码片段的特征是setNotifyValue:YES,但事实如此:
if([aChar.UUID isEqual:[CBUUID UUIDWithString:MW_DEVICE_BREATH_DATA4_CHAR_UUID]])
[peripheral setNotifyValue:YES forCharacteristic:aChar];
定制外围设备在Mac上的LightBlue以及iPhone上的LightBlue Explorer上工作得非常好;收到通知并显示正确的值更新。
此外,最令人困惑的是,当仅改变服务和特征UUID时,相同的精确代码适用于心率监测器外围设备。回调被触发并且特征值被更新。
这个问题似乎非常类似于:
1)iOS Bluetooth LE cant get notification programatically but can in other apps 2)Bluetooth LE notifications not received on iOS 3)How to get notification from Bluetooth LE devices in iOS app
根据上面的问题1),我确实有代表集。 2)或3)的答案似乎没有相关的答案。
我承认我对外围设备的持久性感到有些困惑。我创建了一个属性mwDvcPeripheral,并在各种函数参数中使用了对它的显式引用;它似乎没有积极或消极的影响。
这是一个涉及128位UUID的微妙计时问题吗?什么是LightBlue做的我不是?
我有一种感觉,这个问题的答案是如此明显,以至于我指出它时需要踢自己。
这是Objective-C头文件: // // ViewController.h
#import <UIKit/UIKit.h>
@import CoreBluetooth;
#define MW_DEVICE_INFO_SVC_UUID @"180a"
#define MW_MFG_NAME_CHAR_UUID @"2A29"
// Heart Rate Monitor ***** Use these UUIDs instead of below and everything works ******
//#define MW_DEVICE_MET_SVC_UUID @"180d"
//#define MW_DEVICE_BREATH_DATA4_CHAR_UUID @"2a37"
// MetWear Custom Device
#define MW_DEVICE_MET_SVC_UUID @"11223344-5566-7788-9900-aabbccddeeff"
#define MW_DEVICE_BREATH_DATA4_CHAR_UUID @"01020304-0506-0708-0900-0a0b0c0d0e0f"
@interface ViewController : UIViewController <CBCentralManagerDelegate, CBPeripheralDelegate>
@property (nonatomic, strong) CBCentralManager *centralManager;
@property (nonatomic, strong) CBPeripheral *mwDvcPeripheral;
@property (nonatomic, strong) IBOutlet UITextView *deviceInfo;
@property (nonatomic, strong) IBOutlet UILabel *mwData4Characteristic;
@property (nonatomic, strong) NSString *connected;
@property (nonatomic, strong) NSString *mfgr;
@property (nonatomic, strong) NSString *metWearDvcData;
-(void)getMWData4Characteristic:(CBCharacteristic *)characteristic;
-(void)getMfgNameCharacteristic:(CBCharacteristic *)characteristic;
@end
这是剥离了大多数非必需品的Objective-C代码: // // ViewController.m
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.metWearDvcData = nil;
[self.deviceInfo setText:@""];
[self.deviceInfo setUserInteractionEnabled:NO]; // keep keyboard from popping up.
CBCentralManager *centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
self.centralManager = centralManager;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - CBCentralManagerDelegate
// method called whenever a connection has been established.
-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
[peripheral setDelegate:self];
[peripheral discoverServices:nil];
self.connected = [NSString stringWithFormat:@"Connected: %@", peripheral.state == CBPeripheralStateConnected ? @"YES" : @"NO"];
NSLog(@"%@", self.connected);
}
// CBCentralManagerDelegate - This is called with the CBPeripheral class as its main input parameter. This contains most of the information there is to know about a BLE peripheral.
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
if([localName length] > 0 ){
NSLog(@"Found MetWear Device: %@", localName);
[self.centralManager stopScan];
self.mwDvcPeripheral = peripheral;
peripheral.delegate = self;
[self.centralManager connectPeripheral:peripheral options:nil];
}
}
// method called whenever the device state changes
-(void)centralManagerDidUpdateState:(CBCentralManager *)central
{
if([central state] == CBCentralManagerStatePoweredOff){
NSLog(@"Core Bluetooth BLE hardware powered off");
}
else if([central state] == CBCentralManagerStatePoweredOn){
NSLog(@"Core Bluetooth BLE hardware powered on and ready");
NSArray *services = @[[CBUUID UUIDWithString:MW_DEVICE_INFO_SVC_UUID],[CBUUID UUIDWithString:MW_DEVICE_MET_SVC_UUID]];
[self.centralManager scanForPeripheralsWithServices:services options:nil];
}
else if([central state] == CBCentralManagerStateUnauthorized){
NSLog(@"Core Bluetooth BLE state is unauthorized");
}
else if ([central state] == CBCentralManagerStateUnknown){
NSLog(@"Core Bluetooth BLE state is unknown");
}
else if ([central state] == CBCentralManagerStateUnsupported){
NSLog(@"Core Bluetooth BLE state is unsupported");
}
}
#pragma mark - CBPeripheralDelegate
// CBPeripheralDelegate - Invoked when you discover the peripheral's available services
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
for(CBService *service in peripheral.services){
NSLog(@"Discovered Service: %@", service.UUID);
[peripheral discoverCharacteristics:nil forService:service];
}
}
// Invoked when you discover characteristics of the spec'd service
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
if([service.UUID isEqual:[CBUUID UUIDWithString:MW_DEVICE_MET_SVC_UUID]]){
for(CBCharacteristic *aChar in service.characteristics) {
if([aChar.UUID isEqual:[CBUUID UUIDWithString:MW_DEVICE_BREATH_DATA4_CHAR_UUID]]){
[peripheral setNotifyValue:YES forCharacteristic:aChar];
NSLog(@"Discovered MetWear Data4 Characteristic: %@", aChar);
[self getMWData4Characteristic:aChar];
}
}
}
if([service.UUID isEqual:[CBUUID UUIDWithString:MW_DEVICE_INFO_SVC_UUID]]){
for(CBCharacteristic *aChar in service.characteristics) {
[peripheral readValueForCharacteristic:aChar];
NSLog(@"Discovered MetWear mfgr name Characteristic: %@", aChar);
}
}
}
// Invoked when a spec'd characteristic's state changes
-(void)peripheral:(CBPeripheral *)peripheral didUpdateStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
NSLog(@"Peripheral State Changed");
}
// Invoked when you retrieve a spec'd characteristic's value, or when the peripheral device notifies the app that the characteristic's value has changed
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if([characteristic.UUID isEqual:[CBUUID UUIDWithString:MW_DEVICE_BREATH_DATA4_CHAR_UUID]]){
[self getMWData4Characteristic:characteristic];
NSLog(@"Data4 Characteristic is: %@", characteristic);
}
if([characteristic.UUID isEqual:[CBUUID UUIDWithString:MW_MFG_NAME_CHAR_UUID]]){
[self getMfgNameCharacteristic:characteristic];
NSLog(@"Mfgr is: %@", characteristic);
}
}
// Characteristic helpers
- (void)getMWData4Characteristic:(CBCharacteristic *)characteristic {
NSLog(@"Data4: %@", [characteristic value]);
}
- (void)getMfgNameCharacteristic:(CBCharacteristic *)characteristic {
NSString *mfgrName = [[NSString alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
self.deviceInfo.text = [NSString stringWithFormat:@"%@\n%@\n", self.connected, mfgrName];
}
@end
最后,这是与上述代码的输出相关联的控制台输出:
2016-07-31 21:01:26.042 MetWear[551:99182] Core Bluetooth BLE hardware powered on and ready
2016-07-31 21:01:26.256 MetWear[551:99182] Found MetWear Device: METWR1
2016-07-31 21:01:26.421 MetWear[551:99182] Connected: YES
2016-07-31 21:01:26.488 MetWear[551:99182] Discovered Service: Device Information
2016-07-31 21:01:26.488 MetWear[551:99182] Discovered Service: 11223344-5566-7788-9900-AABBCCDDEEFF
2016-07-31 21:01:26.489 MetWear[551:99182] Discovered Service: Battery
2016-07-31 21:01:26.493 MetWear[551:99182] Discovered MetWear mfgr name Characteristic: <CBCharacteristic: 0x17e39f20, UUID = Serial Number String, properties = 0x2, value = <31323334>, notifying = NO>
2016-07-31 21:01:26.493 MetWear[551:99182] Discovered MetWear mfgr name Characteristic: <CBCharacteristic: 0x17e3a040, UUID = Hardware Revision String, properties = 0x2, value = <312e30>, notifying = NO>
2016-07-31 21:01:26.494 MetWear[551:99182] Discovered MetWear mfgr name Characteristic: <CBCharacteristic: 0x17e3a120, UUID = Firmware Revision String, properties = 0x2, value = <312e30>, notifying = NO>
2016-07-31 21:01:26.494 MetWear[551:99182] Discovered MetWear mfgr name Characteristic: <CBCharacteristic: 0x17e3a160, UUID = Software Revision String, properties = 0x2, value = <312e30>, notifying = NO>
2016-07-31 21:01:26.494 MetWear[551:99182] Discovered MetWear mfgr name Characteristic: <CBCharacteristic: 0x17e3a1a0, UUID = Manufacturer Name String, properties = 0x2, value = <4a617276 6973204c 616273>, notifying = NO>
2016-07-31 21:01:26.495 MetWear[551:99182] Discovered MetWear mfgr name Characteristic: <CBCharacteristic: 0x17e3a0c0, UUID = Model Number String, properties = 0x2, value = <4d657457 6561724f 6e65>, notifying = NO>
2016-07-31 21:01:26.496 MetWear[551:99182] Discovered MetWear Data4 Characteristic: <CBCharacteristic: 0x17d3cee0, UUID = 01020304-0506-0708-0900-0A0B0C0D0E0F, properties = 0x12, value = (null), notifying = NO>
2016-07-31 21:01:26.496 MetWear[551:99182] Data4: (null)
2016-07-31 21:01:26.793 MetWear[551:99182] Mfgr is: <CBCharacteristic: 0x17e3a1a0, UUID = Manufacturer Name String, properties = 0x2, value = <4a617276 6973204c 616273>, notifying = NO>
我成功地使这个代码工作;但是只有蛮力。我发现使用&#34; for循环的#(长)延迟&#34;之后添加: [self.centralManager connectPeripheral:peripheral options:nil]; 那是成功的。
我有点困惑为什么这是有效的,并且首先需要。我想假设回调存在同步问题或者RN4020 BLE模块存在细微的时序问题,但这只是猜测。我当然有更多的探索要做。