This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

DFU bootloader with Qt - problem for iOS

Hello everyone,

I am working on DFU bootloader application for android  and iOS (using Qt C++).

For android everything works fine, but for iOS I have problems.

In order to enter DFU mode I need to send 0x0104 to control point dfu characteristic and after this device is reset in DFU mode.

After this my app doing next steps: connect to device again > discover services (there is only DFU service now) > write descriptor for  CP characteristic (to enable notifications) > THERE IS A PROBLEM - The delegate for CBPeripheral does not implement -[peripheral:didModifyServices:].

I tried to increment MAC address (device uuid) when enter in DFU mode because I read that devices may be cached by the phone and if they change services list while connected that could cause the problem, but the problem is still there.

Has anyone had a similar problem/experience?

Thanks in advance.

Parents
  • If you want to implement peripheral did modify services then you need to have the service changed enabled (but no need to indicate when services change as iOS will automatically disable caching for this peripheral when it finds the service there).

    However, our implementation depends on the peripheral disconnecting and starting again in bootloader, with MAC address + 1.

    Only then you can reconnect, discover your services, enable notifications and start the flashing process.

    I would suggest that you follow the same steps as the nR/F Connect app as this is the supported way to flash OTA :)

    Note 1:, if you add service change to your peripheral's FW, iOS will not see that because it has already cached the GATT table, so you'll have to put the phone in airplane mode or disable bluetooth from the settings (not control center) for at least 10 seconds to clear the cache. if that doesn't work you should try again, or try to restart the phone. after the new GATT table is fetched and service change is there, iOS will no longer cache this peripheral.

    Note 2: iOS has no access to the peripheral's MAC address, so you can't rely on MAC address + 1 to identity the node, you should just scan for peripherals broadcasting DFU / Secure DFU services. additionally we have implemented a name set feature that allows you to set the broadcasting name of the peripheral upon restart so you can easily identify it, please use one of our DFU libraries for android or iOS to see how that works. Here is how iOS the iOS Library implements it.

    Note 3: Android allows you to get the peripheral's MAC address, so you won't need to scan like you do on iOS, you simply send the jump to bootloader command, then increment the mac address by one, and connect to that peripheral straight away.

    let us know if you have any more issues so we can help out.

  • Hi Mostafa,

    Thanks for your answer! 

    I have service changed characteristic added in Generic Attribute service (that mean it is enabled, right?).

    I tried with increment MAC address, and for android it works fine but for iPhone not. Maybe I didn't clear cache appropriately...I will try to turn off bluetooth, wait more than 10s and than turn on again.

  • Yes, this is totally correct, this is not following the spec, but iOS has this as a workaround to disable caching, so just having the characteristic present will disable caching for iOS. to be able to actually use it properly and indicate changes, you must be bonded, but that's not a requirement for iOS.

    You should still increment the MAC address as this is the correct way to do it. as I mentioned, iOS does not have access to the MAC address, so you will still have to scan one more time for the peripheral again when it's in bootloader, it'll appear as a totally different peripheral on iOS, so you can't hold a reference to the old ones object.

    You are probably hitting a cache issue as you didn't have the service changed from before (You don't actually need it anymore you're incrementing the MAC address.) I would say remove the service changed characteristic, then rely on scanning again when the device has restarted into bootloader. only then it'll work on both platforms.

  • I'll give you feedback after try this. Thanks once again!

  • Hi Mostafa,

    I tried and problem is still there. I also tried to modify small app for mac desktop where I can manually  scan for devices after first restart (when restart into DFU mode), than I connect to DfuTarg, discover services (here is only DFU service present) and when try to write descriptor to enable notification for DFU control point char, then app is crashed.  

    I thing that maybe there is some problem with Qt's writeDescriptor function.

  • Aha, I see your problem I think, to enable notifications on iOS / macOS you can't write to the descriptor, the `CoreBluetooth` api doesn't allow that, what you can do instead is use a `CoreBluetooth` method called `setNotifyValue:(Bool)forCharacteristic:(CBCharacteristic)`, found here

    I guess when you try to write to that descriptor using Qt it will still try to write anyway, causing that issue, do you know if Qt Bluetooth has any way of setting the notify property without writing to descriptor ?

    also, do you have any logs from that crash ?

  • Hi Mostafa,

    As far as I know there is no another way to set notification from Qt.

    When app is crashed, I'm getting next message: 

    [CoreBluetooth] WARNING: The delegate for <CBPeripheral: 0x10174f410, identifier = 42593BBF-40E8-4BED-A813-20540069584A, name = DfuTarg, state = connected> does not implement -[peripheral:didModifyServices:]

    I'm thinking about mixing native code with C++. To call setNotify function somehow from my C++ code.

    I'll continue to investigate.

    Thank you for your time.

    Best regards

Reply
  • Hi Mostafa,

    As far as I know there is no another way to set notification from Qt.

    When app is crashed, I'm getting next message: 

    [CoreBluetooth] WARNING: The delegate for <CBPeripheral: 0x10174f410, identifier = 42593BBF-40E8-4BED-A813-20540069584A, name = DfuTarg, state = connected> does not implement -[peripheral:didModifyServices:]

    I'm thinking about mixing native code with C++. To call setNotify function somehow from my C++ code.

    I'll continue to investigate.

    Thank you for your time.

    Best regards

Children
No Data
Related