3
votes

I am building an iOS Swift app that connects to a BLE device (Redbear Labs Duo).

What works?

  1. I am able to initiate a scan for devices
  2. Connect to the device
  3. Collect services and characteristics of the BLE device - all good

Where is the problem?

  1. The BLE device (Redbear Labs Duo) also has a Wifi controller onboard and is capable of scanning for available networks. The documentation states that to scan for Wifi one must
    • connect to the primary service with UUID 3EC61400-89CD-49C3-A0D9-7A85669E901E
    • find the command characteristic with UUID 3EC61401-89CD-49C3-A0D9-7A85669E901E
    • send a 2 byte command [0x20, 0xA0] to the command characteristic
    • also set a 1 byte status indicator 0xB1 to the scan characteristic with UUID 3EC61402-89CD-49C3-A0D9-7A85669E901E

My code to do the above steps is as below..

func scanWifi() {
    print("[DEBUG] - Scanning for Wifi")

    let command:[UInt8] = [0x02, 0xA0]
    let commandData = NSData(bytes: command, length: command.count)
    BLE.sharedInstance.write(toCharacteristic: BLE.sharedInstance.RBL_CHAR_CMD_UUID, data: commandData, withType: .withResponse)

    let state:[UInt8] = [0xB1]
    let stateData = NSData(bytes: state, length: state.count)
    BLE.sharedInstance.write(toCharacteristic: BLE.sharedInstance.RBL_CHAR_SCN_UUID, data: stateData, withType: .withResponse)

    BLE.sharedInstance.read(fromCharacteristic: BLE.sharedInstance.RBL_CHAR_SCN_UUID)
}

Everything works... but... after writing the above data to the peripheral I was expecting the below method to get called - it never did.. what am I doing wrong?

func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        if error != nil {

            print("[ERROR] Error updating value. \(error!.localizedDescription)")
            return
        }

        if characteristic.uuid.uuidString == RBL_CHAR_CMD_UUID {

            self.delegate?.bleDidReceiveData(data: characteristic.value as NSData?)
        }
    }

Update:

I set a bunch of debug statements and got the following output - from the below it is apparent that

  1. I am able to identify and connect to the right device and characteristics
  2. I am able to set the notification value appropriately

[DEBUG] Connecting to peripheral: 547BC3C9-4823-431C-B888-A8F3E8C699F5
[DEBUG] Connected to peripheral 547BC3C9-4823-431C-B888-A8F3E8C699F5
[DEBUG] Did connect to peripheral
[DEBUG] Found service: 3EC61400-89CD-49C3-A0D9-7A85669E901E for peripheral: 547BC3C9-4823-431C-B888-A8F3E8C699F5
[DEBUG] Found characteristic: 3EC61401-89CD-49C3-A0D9-7A85669E901E for peripheral: 547BC3C9-4823-431C-B888-A8F3E8C699F5
[DEBUG] Found characteristic: 3EC61402-89CD-49C3-A0D9-7A85669E901E for peripheral: 547BC3C9-4823-431C-B888-A8F3E8C699F5
("3EC61402-89CD-49C3-A0D9-7A85669E901E", )
("3EC61401-89CD-49C3-A0D9-7A85669E901E", )
[DEBUG] didUpdateNotification state for characteristic CBCharacteristic: 0x1702a6c60, UUID = 3EC61401-89CD-49C3-A0D9-7A85669E901E, properties = 0x14, value = (null), notifying = YES on peripheral: CBPeripheral: 0x1740fba80, identifier = 547BC3C9-4823-431C-B888-A8F3E8C699F5, name = Duo-ZKBY, state = connected
[DEBUG] didUpdateNotification state for characteristic: CBCharacteristic: 0x1742a3c60, UUID = 3EC61402-89CD-49C3-A0D9-7A85669E901E, properties = 0x10, value = (null), notifying = YES on peripheral: CBPeripheral: 0x1740fba80, identifier = 547BC3C9-4823-431C-B888-A8F3E8C699F5, name = Duo-ZKBY, state = connected

2
From a quick look at the documentation, it seems that the characteristics support notify, not read so you will need to call setNotifyValue on the peripheral.Paulw11
I am calling setNotifyValue - did some more research and my problem is similar to the one here - stackoverflow.com/questions/31275013/… - however the difference is that I tested the device using the iOS app provided by the manufacturer and it does indeed all work. What mistake am I making that doesnt give me a response from the deviceChicagoSky
Have you set your object as the peripheral's delegate?Paulw11
Hello @Paulw11 - yes I have set the object as the peripheral delegate in didConnect peripheral method. Also please see additional debug inputs that i have included aboveChicagoSky
I think I figured it out. The documentation states that when I write 2 bytes to the Command characteristic, it must be written withoutResponse. I was writing withResponse. Also, the Scan characteristic is only meant for notification and nothing else.ChicagoSky

2 Answers

4
votes

Found the solution - posting here for the benefit of others.

Reading through the documentation provided by Redbear Labs, the key thing to note is that the Command characteristic only supports two types of properties - PROPERTY_WRITE_NO_RESPONSE | PROPERTY_NOTIFY

Likewise the Scan characteristic only supports PROPERTY_NOTIFY

Also, to have the device scan all available Wifi - we should only write a 2 byte command [0x20, 0xA0] to the Command characteristic - code for the same is below

func scanWifi() {
        print("[DEBUG] - Scanning for Wifi")

        let command:[UInt8] = [0x02, 0xA0]
        let commandData = NSData(bytes: command, length: command.count)
        BLE.sharedInstance.writeTo(characteristic: BLE.sharedInstance.RBL_CHAR_CMD_UUID, data: commandData, withType: .withoutResponse)
}

Nothing needs to be written to the scan characteristic. When Wifi scanning begins, the Scan characteristic will send a notification with value 0xB1 to indicate start of scanning and then send a notification with value 0xB2 to indicate end of scanning.

The actual Wifi networks scanned will be sent via notifications on the command characteristic itself.

0
votes

After calling

peripheral.writeValue(dataToWrite, for: char, type: .withResponse)

you need to call the read in this delegate function:

func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {

// Call your read functions here. 
     BLE.sharedInstance.read(fromCharacteristic: BLE.sharedInstance.RBL_CHAR_SCN_UUID)

}