8

まず最初に: OSX 10.10.4、iOS 4、Xcode 6.3.2、iPhone 6、Swift を実行していること

短い話: ここに特定の Bluetooth LE デバイスがあり、たとえばユーザー入力によって Characteristic の値が変化したときに通知を受け取りたいと考えています。サブスクライブしようとしても成功せず、むしろエラーが発生しますError Domain=CBATTErrorDomain Code=10 "The attribute could not be found."

長い話: だから、私は BluetoothManager クラスを持ってい$CBCentralManager.stateます.PoweredOn。それは簡単です。私は善良な市民でもあり、私が望むサービスを持っている人を特別にスキャンします

centralManager.scanForPeripheralsWithServices([ServiceUUID], options: nil)

これが成功することを期待して、次のデリゲート メソッドを実装しました。

func centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: [NSObject : AnyObject]!, RSSI: NSNumber!) {

    if *this is a known device* {
        connectToPeripheral(peripheral)
        return
    }

    [...] // various stuff to make something a known device, this works
}

先に進むと、次のようになります。

func connectToPeripheral(peripheral: CBPeripheral) {
    println("connecting to \(peripheral.identifier)")

    [...] // saving the peripheral in an array along the way so it is being retained

    centralManager.connectPeripheral(peripheral, options: nil)
}

うん、これは成功したので、確認を取得し、サービスの検出を開始します。

func centralManager(central: CBCentralManager!, didConnectPeripheral peripheral: CBPeripheral!) {        
    println("Connected \(peripheral.name)")

    peripheral.delegate = self

    println("connected to \(peripheral)")
    peripheral.discoverServices([BluetoothConstants.MY_SERVICE_UUID])
}

そのデリゲート メソッドも呼び出されるため、これも機能します。

func peripheral(peripheral: CBPeripheral!, didDiscoverServices error: NSError!) {

    if peripheral.services != nil {
        for service in peripheral.services {
            println("discovered service \(service)")
            let serviceObject = service as! CBService

            [...] // Discover the Characteristic to send controls to, this works
            peripheral.discoverCharacteristics([BluetoothConstants.MY_CHARACTERISTIC_NOTIFICATION_UUID], forService: serviceObject)

           [...] // Some unneccessary stuff about command caches
        }
    }
}

そして、何を知っていますか: 特性発見されます!

func peripheral(peripheral: CBPeripheral!, didDiscoverCharacteristicsForService service: CBService!, error: NSError!) {
    for characteristic in service.characteristics {
        let castCharacteristic = characteristic as! CBCharacteristic

        characteristics.append(castCharacteristic) // Retaining the characteristic in an Array as well, not sure if I need to do this

        println("discovered characteristic \(castCharacteristic)")
        if *this is the control characteristic* {
            println("control")
        } else if castCharacteristic.UUID.UUIDString == BluetoothConstants.MY_CHARACTERISTIC_NOTIFICATION_UUID.UUIDString {
            println("notification")
            peripheral.setNotifyValue(true, forCharacteristic: castCharacteristic)
        } else {
            println(castCharacteristic.UUID.UUIDString) // Just in case
        }
        println("following properties:")

        // Just to see what we are dealing with
        if (castCharacteristic.properties & CBCharacteristicProperties.Broadcast) != nil {
            println("broadcast")
        }
        if (castCharacteristic.properties & CBCharacteristicProperties.Read) != nil {
            println("read")
        }
        if (castCharacteristic.properties & CBCharacteristicProperties.WriteWithoutResponse) != nil {
            println("write without response")
        }
        if (castCharacteristic.properties & CBCharacteristicProperties.Write) != nil {
            println("write")
        }
        if (castCharacteristic.properties & CBCharacteristicProperties.Notify) != nil {
            println("notify")
        }
        if (castCharacteristic.properties & CBCharacteristicProperties.Indicate) != nil {
            println("indicate")
        }
        if (castCharacteristic.properties & CBCharacteristicProperties.AuthenticatedSignedWrites) != nil {
            println("authenticated signed writes ")
        }
        if (castCharacteristic.properties & CBCharacteristicProperties.ExtendedProperties) != nil {
            println("indicate")
        }
        if (castCharacteristic.properties & CBCharacteristicProperties.NotifyEncryptionRequired) != nil {
            println("notify encryption required")
        }
        if (castCharacteristic.properties & CBCharacteristicProperties.IndicateEncryptionRequired) != nil {
            println("indicate encryption required")
        }

        peripheral.discoverDescriptorsForCharacteristic(castCharacteristic) // Do I need this?
    }
}

ここまでのコンソール出力は次のようになります。

connected to <CBPeripheral: 0x1740fc780, identifier = $FOO, name = $SomeName, state = connected>
discovered service <CBService: 0x170272c80, isPrimary = YES, UUID = $BAR>
[...]
discovered characteristic <CBCharacteristic: 0x17009f220, UUID = $BARBAR properties = 0xA, value = (null), notifying = NO>
control
following properties:
read
write
[...]
discovered characteristic <CBCharacteristic: 0x17409d0b0, UUID = $BAZBAZ, properties = 0x1A, value = (null), notifying = NO>
notification
following properties:
read
write
notify
[...]
discovered DescriptorsForCharacteristic
[]
updateNotification: false

おい!と書いてupdateNotificationありfalseます。それはどこから来たのですか?なぜ、それは私のコールバックですsetNotify...:

func peripheral(peripheral: CBPeripheral!, didUpdateNotificationStateForCharacteristic characteristic: CBCharacteristic!, error: NSError!) {

    println("updateNotification: \(characteristic.isNotifying)")
}

何を与える?通知するように言いました!なぜ通知されないのですか?println のある行にブレークポイントを設定して、エラー オブジェクトをチェックしてみましょう。

(lldb) po error
Error Domain=CBATTErrorDomain Code=10 "The attribute could not be found." UserInfo=0x17026eac0 {NSLocalizedDescription=The attribute could not be found.}

OK、これで私はアイデアを失います。そのエラー コードに関連する手がかりを見つけることができませんでした。以前に発見した特性の通知を設定しようとしたため、説明自体を理解できません。したがって、存在するに違いありません。また、Android では通知を購読することもできるようですので、デバイスの問題を除外できると思います... それともできますか? これに関する手がかりは本当にありがたいです!

4

3 に答える 3

3

製造元から詳細な情報を入手したところ、特性の通知状態に関係なく、デバイスが接続され、通知が送信されていることがわかりました。これはperipheral(_, didUpdateNotificationStateForCharacteristic, error)、Characteristic が通知していないことを通知しているにもかかわらずperipheral(_, didUpdateValueForCharacteristic, error)、デバイスが送信したときにデータが呼び出されて配信されていることを意味します。この状態でデータが送信されるとは予想していなかったため、以前はそのコールバックを実装していませんでした。

基本的に、私の問題は解決したようです。とはいえ、デバイスの動作が Bluetooth LE の仕様に準拠しているかどうかについては、まだ関心があります。これらの低レベルの実装については洞察がありませんが、何らかの理由で Apple がドキュメントを書いて、キャラクタリスティックの状態の変化がデータの受信に先行することを少なくとも強く示唆していると思います。

于 2015-07-22T12:26:29.680 に答える