leachim
leachim

Reputation: 332

CoreBluetooth: didWriteValueFor() is not called after writeValue()

According to Apple Developer Documentation the function didWriteValueFor() is called after the writeValue() function is called. (see https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1518823-peripheral)

I have a writeable Characteristic, I looked up the property as mentioned in https://developer.apple.com/documentation/corebluetooth/cbcharacteristicproperties/1519089-write

Now when I call the writeValue() function, the didWriteValueFor() function is never called, why? I think it's the same structure like the readValue() function which calls the didUpdateValueFor() function, which is working fine for me. Here is my Code:

        func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
    for characteristic in service.characteristics!{
        print(characteristic)
        if(characteristic.uuid == TX_CHARACTERISTIC){
            elsa.writeValue(dataWithHexString(hex: VALID_GET_VERSION_REQUEST), for: characteristic, type: CBCharacteristicWriteType.withResponse)//calls didWriteValueFor if Type = withResponse
        }
        if(characteristic.uuid == RX_CHARACTERISTIC){
            elsa.setNotifyValue(true, for: characteristic)//calls didUpdateNotificationStateFor
        }
    }
}

func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
    guard let data = characteristic.value else { return }
    print("\nValue: \(data.toHexEncodedString()) \nwas written to Characteristic:\n\(characteristic)")
    if(error != nil){
        print("\nError while writing on Characteristic:\n\(characteristic). Error Message:")
        print(error as Any)
    }
}

Upvotes: 2

Views: 3168

Answers (2)

leachim
leachim

Reputation: 332

As @Paulw11 mentioned, the value is only written after it is explicitly read. I fixed this by calling a readValue() inside the didWrite() function.

Updated Solution:

func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
    elsa.readValue(for: characteristic)
    guard let data = characteristic.value else { return }
    print("\nValue: \(data.toHexEncodedString()) \nwas written to Characteristic:\n\(characteristic)")
    if(error != nil){
        print("\nError while writing on Characteristic:\n\(characteristic). Error Message:")
        print(error as Any)
    }
}

Upvotes: 2

ehmjaysee
ehmjaysee

Reputation: 167

When you call writeValue() you can specify if you want a response from the remote device or not. In your case you specified CBCharacteristicWriteType.withResponse which tells the remote device it needs to send a response back and indicate if the write was successful or not. When the remote device sends the response message this will trigger the call to didWriteValueFor(). If your device does NOT send the response then didWriteValueFor() is not called. You can read about this in the apple documentation here. You would need to run a bluetooth sniffer capture to confirm this, but I suspect your bluetooth device is not responding properly to the writeValue() request.

Note that each BLE characteristic has a set of properties which govern how the characteristic will behave. Some of those properties include: rear, write, write without response, notify, inform. Check the properties for the characteristic you are using and make sure it supports the 'write' property. If your characteristic supports 'write without response' but does not support 'write' then your device will not send the needed message back to your app and therefore didWriteValuefor() will not get called. Normally you can find this in the documentation, or use a bluetooth app such as "LightBlue Explorer" to view this information for your device.

Upvotes: 3

Related Questions