0

***** 编辑:我现在正在工作,请参阅下面接受的答案和此问题中的更新代码... *****

好的,我对微控制器代码非常陌生,但对 Objective-c 蓝牙代码也很陌生。

我想要的是

我想用一个 iOS 应用程序连接到我的蓝牙 Bluefruit Friend UART LE(NRF51822 芯片)并向它发送一个 128 位令牌并让它响应一个 HID 消费者代码。

我试过的

目前,我可以使用串行监视器连接到芯片并通过我想要的消费者代码发送,它会通过执行该操作来响应。因此,如果我发送代码以使设备静音或增大/减小音量,它将在我的 iOS 设备中静音/增大/减小音量。这很棒!

现在我需要在笔记本电脑上没有串行监视器的情况下执行此操作,并引入发送令牌而不是 HID 代码的概念,并让它以 HID 代码响应。这非常棘手,似乎向我介绍了服务和渠道等新概念。似乎大多数蓝牙设备都带有许多可用的自定义服务,开发人员可以添加这些服务,并允许将读取与写入操作分开。每个服务都允许许多特征,例如读/写/通知/更新等等。

所以...我假设可以通过这些服务使用我想要的解决方案。如果我有一个用于读取令牌的服务和另一个用于编写 a 的服务,GATT HID Consumer Code那么我应该能够通过 Objective-c 中的蓝牙分别连接到每个服务。这将使我能够区分发送令牌和接收回代码。

问题

正如你所看到的,我在下面的代码中有很多 NSLogs,目前这些日志都没有显示我在盒子上放置的任何服务。服务总是打印为零。如果我使用名为 的应用商店中的 iOS 应用RF Connect,我可以连接到盒子,我可以看到这些服务肯定在那里......

我试过的代码

这是我一直用来尝试检测设备服务的当前代码......我认为这是一个从这里开始的好地方。

蓝牙管理器.h

#import <Foundation/Foundation.h>

@protocol BluetoothMgrDelegate <NSObject>

@optional

- (void)didConnectToDevice;
- (void)didDisconnectFromDevice;

@end

@interface BluetoothMgr : NSObject {

}

@property (nonatomic, weak) id <BluetoothMgrDelegate> delegate;

+ (BluetoothMgr *)sharedInstance;

- (void)scanForPeripherals;
- (void)disconnectDevice;
- (void)connectToDevice;

@end

蓝牙管理器

#define SERVICE_UUID @"0000BBB5-2222-3333-4444-AABBCCDDEEFF"
#define CARACHTERISTIC_UUID @"0000BBB6-1111-2222-3333-AABBCCDDEEFF"

#import "BluetoothMgr.h"
#import <UIkit/UIKit.h>
#import <CoreBluetooth/CoreBluetooth.h>
#import <QuartzCore/QuartzCore.h>

@interface BluetoothMgr () <CBCentralManagerDelegate, CBPeripheralDelegate> {
    int count;
}

@property (nonatomic, strong) CBCentralManager *centralManager;
@property (nonatomic, strong) CBPeripheralManager *peripheralManager;
@property (nonatomic, strong) CBPeripheral *myPeripheral;
@property (nonatomic, strong) CBUUID *deviceUUID;

@property (nonatomic, strong) CBService *functionalityServiceLayer;
@property (nonatomic, strong) CBCharacteristic *characteristic;

@end


@implementation BluetoothMgr

+ (BluetoothMgr *)sharedInstance {
    static BluetoothMgr *_sharedInstance = nil;
    static dispatch_once_t oncePredicate;

    dispatch_once(&oncePredicate, ^{
        _sharedInstance = [[BluetoothMgr alloc] init];
    });

    return _sharedInstance;

}

- (id)init {
    self = [super init];

    if(self) {
        self.centralManager = [[CBCentralManager alloc] initWithDelegate:self
                                                                   queue:nil
                                                                 options:@{ CBCentralManagerOptionRestoreIdentifierKey : @"DriveSafeDevice"}];
    }

    return self;
}

- (void)connectToDevice {
    if(_myPeripheral != nil) {
        [self.centralManager connectPeripheral:self.myPeripheral
                                       options:@{ CBConnectPeripheralOptionNotifyOnConnectionKey: [NSNumber numberWithInt:1] }
         ];
    }
}


- (void)scanForPeripherals {
    NSLog(@"*** scan for Bluetooth peripherals");
    if (_centralManager.state == CBCentralManagerStatePoweredOn) {
        NSLog(@"--- central manager powered on. Start scanning.");

        [self.centralManager scanForPeripheralsWithServices:@[self.deviceUUID] options:nil];
    }
}

- (void)disconnectDevice {
    if (!(self.centralManager == nil || _myPeripheral == nil)) {
        [self.centralManager cancelPeripheralConnection:_myPeripheral];
    }
}



#pragma mark - CBCentralManager delegate methods

- (void)centralManager:(CBCentralManager *)central
      willRestoreState:(NSDictionary<NSString *,id> *)state {

    NSLog(@"--- will restore state.");

}

- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    NSLog(@"centralManagerDidUpdateState invoked...");

    // Determine the state of the peripheral
    if ([central state] == CBCentralManagerStatePoweredOff) {
        NSLog(@"CoreBluetooth BLE hardware is powered off");
    } else if (central.state == CBCentralManagerStatePoweredOn) {
        NSLog(@"CoreBluetooth BLE hardware is powered on.");
        [self.centralManager scanForPeripheralsWithServices:nil options:nil];
    }
}


- (void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    NSLog(@"did discover characteristic! peripheral: %@", peripheral);
    NSLog(@"did discover characteristic! characteristic: %@", characteristic);
    NSLog(@"did discover characteristic! error: %@", error);
}


- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
    NSLog(@"did discover service! peripheral: %@", peripheral);
    NSLog(@"services??: %@", peripheral.services);
    NSLog(@"did discover service! error: %@", error);
}


- (void)centralManager:(CBCentralManager *)central
 didDiscoverPeripheral:(CBPeripheral *)peripheral
     advertisementData:(NSDictionary *)advertisementData
                  RSSI:(NSNumber *)RSSI {

    NSLog(@"peripheral: %@", peripheral);
    NSLog(@"advertisement data: %@", advertisementData);

    if([peripheral.name containsString:@"Adafruit Bluefruit LE"]) {
        NSLog(@"central: %@", central);
        NSLog(@"peripheral: %@", peripheral);
        NSLog(@"advertisement data: %@", advertisementData);
        NSLog(@"RSSI: %@", RSSI);

        NSLog(@"found peripheral services!: %@", peripheral.services);

        self.myPeripheral = peripheral;
        self.myPeripheral.delegate = self;

        //self.serviceUUID = ;
        self.deviceUUID = [CBUUID UUIDWithString:[peripheral.identifier UUIDString]];

        [self connectToDevice];
    }


- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    NSLog(@"--- didConnectPeripheral");

    NSLog(@"peripheral in didConnect function: %@", peripheral);
    NSLog(@"any services??: %@", peripheral.services);

    [peripheral discoverServices:@[self.deviceUUID]];


    if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) {
        NSLog(@"--- connected to peripheral in foreground");
        [[NSNotificationCenter defaultCenter] postNotificationName:@"connectedToDevice" object:self];
        [self triggerLocalNotification];
    } else {
        NSLog(@"--- connected to peripheral in background");
        [[NSNotificationCenter defaultCenter] postNotificationName:@"connectedToDevice" object:self];
        [self triggerLocalNotification];

        //[self.delegate didConnectToDevice];
    }
}


- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(nonnull CBPeripheral *)peripheral error:(nullable NSError *)error {
    NSLog(@"--- did disconnect ConnectPeripheral");        
}


- (void)peripheral:(CBPeripheral *)peripheral didModifyServices:(NSArray<CBService *> *)invalidatedServices {
    NSLog(@"peripheral services: %@", peripheral.services);
    NSLog(@"services invalidated: %@", invalidatedServices);
}


- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
    NSLog(@"Failed to connect");
}


- (void)sendCodeToBTDevice:(NSString *)code
            characteristic:(CBCharacteristic *)characteristic {

    if(code != nil) {
        NSData *data = [code dataUsingEncoding:NSUTF8StringEncoding];
        [self.ourPeripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
    }
}

@end

最后的想法...

我在如何在 Arduino 板/任何 BT 设备中编写自定义服务/特性方面的知识差距显然是这里的问题。我不确定我是否应该在设备或我的 OBJ-C 应用程序中创建服务/特征。

考虑到现在这些是在设备而不是应用程序中创建的,这个概念现在很可笑。

4

2 回答 2

0

是的,这是可能的。在 HID 设备中设置一个您将要更新以通知的特征。然后在应用程序setNotifytrue收听didUpdateValueFor 参考

然后你所做的就是写你想写的CBCharacteristic那个,一旦写给另一个CBCharacteristicdidUpdateValueFor就会被调用。

于 2017-06-23T14:44:55.133 回答
0

对于在 Google 上搜索的任何人,我最终确实在此问题上找到了正确答案。

事实证明,我需要在外围 BT 设备(而不是 iOS 设备)上创建自定义服务/特性。一旦我创建了这些自定义服务来接收 128 位令牌字符串,就很容易让设备在单独的 HID 服务层上做出响应。

我已经更新了上面的代码以反映此答案,因此请查看代码以遵循此答案。

在我didDiscoverPeripheral的蓝牙管理器类的方法中,我确保设备 UUID 与已知设备 UUID 匹配。一旦我通过 UUID 找到了正确的设备,我将外围对象的(默认情况下由本机方法传入)委托设置为self(因为我的类使用外围委托),然后我将self.ourPeripheral类的属性分配给当前外围 obj . 一旦我都设置好了,我启动我的自定义connectToDevice方法,该方法将属性对齐centralManager以与给定的外围设备连接。

didConnectPeripheralcentralManager 委托给定的方法中,我调用[peripheral discoverServices:nil];了哪个启动的委托方法称为didDiscoverServices. 然后我从这里遍历所有发现的服务,寻找我在我构建的 BT 外围设备的自定义服务中设置的预定服务 UUID。一旦我在盒子上找到了自定义服务,我就会调用[peripheral discoverCharacteristics:nil forService:service];. 这也会自动调用委托方法(如您所料)didDiscoverCharacteristicsForService。再一次,更多的迭代,在这个用例中,我改为搜索我在我的服务中编写的用于侦听 BT 串行通信的特征 UUID。

一旦我找到了正确的特征,我就会将它全局保存为类的强属性,然后我可以使用sendCodeToBTDevice上面显示的方法。这会将数据作为文本/字符串通过 BT 写入设备,由盒子通过串行接收,解释为 128 位令牌并经过验证。如果有效,它会在不同的服务层上响应,并根据请求发回符合 HID 的消费者代码。

于 2017-07-10T14:05:01.440 回答