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

Detailed DFU Application Interface Documentation

I need to implement DFU in a Unity3D application. I have tried to integrate the Android SDK library that you have on github. They are not integrating very well.

I have a lot of BLE experience and if I understand exactly the steps to implement sending a ZIP file payload over the DFU service and characteristics then I could probably do it without your library. This would also be good because I need this to work on iOS as well and being able to do it myself in C# code would be great because then I don't have to do native code for each.

The problem is that the documentation all assumes you are using the library you have provided.

Is there anything special that the library does? Does it actually break open the ZIP file and send the different parts over or does it just open a connection and send the ZIP file and have the firmware on the Nordic part do the work? If the previous then I would like to know the simple commands to implement that.

Parents
  • A detailed description of the DFU protocol can be found in the bootloader section of the infocenter.

    Here is a very coarse overview:

    The app opens the zip file and sends the meta information first (which the bootloader can choose to say "nope" to), then the binary firmware data in chunks, checked via CRC32. Once the last checksum is OK, the command to "execute" the update is sent.

  • I have been reading through the bootloader section in infocenter and am still not clear on exactly what to do.

    Maybe I am looking in the wrong place. Just to be clear I am working on SDK 15.3.

    Most of the information I am finding looks to be from the device side and not the mobile app.

    Can you give me some specific pointers? It would be nice to have a detailed description of 1. send these bytes, 2. expect this response or 2, 3. Now send these bytes, etc.

  • I found DFU BLE transport in the SDK documentation to be sufficient in order to be able to implement a DFU host for another language.

    Another solution: Read the source code on github...

  • Well, I will give it a try.

    What I am not sure about is when to send what and what to expect back. I notice my zip file has a bin object and a dat object. The bin object is obviously the firmware. No idea what the dat object is.

    The packet sequence charts show sending 06 01 and getting back 60 06 01 with max size, offset and crc. Well, do I send the 06 01 for the bin or dat or both? How can the 60 06 01 contain a CRC when I haven't given it any data yet?

    Then it says to send 01 01 as a create command, but only if there isn't an init packet. How do I know if there is an init packet or not?

    The questions go on. Where can I find answers?

    I have been looking at the github software, but there are so many different files and everything is so layered and abstracted.

    I can probably figure it out eventually, but have a time limit and would appreciate some help in making this more clear.

  • How can the 60 06 01 contain a CRC when I haven't given it any data yet?

    The idea of the DFU protocol is to be able to continue an update when an error occurred. This can save a lot of time when you e.g. have a disconnect at 90% transferred data.

    You always get a value for the CRC back - it is just not valid in the case where the was no previous data/command object transferred.

    The conditions when to do what are specified in the message sequence charts.

  • Also, my device is set up with the Buttonless DFU characteristic. I don't have the other 2. So how do I use that one? I notice there is a Control Point Characteristic and a Packet Characteristic. Since I don't have those and only have the buttonless, how does this work for me? Where do I send what?

  • The buttonless service is used to reboot your device into DFU bootloader mode. In that mode you device will only have DFU service and DFU Control Point and DFU Packet characteristics inside (except from Generic Attribute and Generic Access, of course).

    How to use this service is explained here: Buttonless Secure DFU Service

    For non-bonded devices, the bootloader will advertise with a different MAC address (+1). The phone needs to scan for it to connect to it. Our libraries take care of it automatically, but you need to make sure you connect to the proper device. Remember, that on iOS you don't have MAC address, so you can't compare it with the previous one. iOS DFU Library is using peripheralSelector, and the selection (starting from DFU from SDK 14) is using "Set advertisement name" feature (see the first link, command 0x02).

    After you jumped to bootloader mode successfully, you need to check in what state your device is. You do this by setting the object to COMMAND. You will get the offset and CRC32 of the object. For fresh update both will be 0. If an update has started and may be resumed, they'll contain the proper values for you to compare (if cry doesn't match, or you don't want to resume, you always may start again by creating new COMMAND object). Then you need to follow the BLE Transport: Device Firmware Update process.

    Regarding your question about the ZIP file. ZIP file contains 3 or 5 files. One is always the manifest.json, which specifies the names of 2 or 4 other files. In one ZIP file there may be an update for App only, or SoftDevice+Bootloader and App. Or any of them alone. The dat file is generated using nrfutil tool. The same tool may be used to read the content for the zip file, including decoding the dat files. The dat files are using Protobuf to encode the firmware size, type, hw type, required soft device(s), signature, crc, etc. They are to be sent prior to the firmware for validation. Bootloader may reject the firmware based on the init packet.

    I would recommend first trying the bootloader using nRF Connect for Android or iOS. Check if your ZIP file is working. Then examine the log. All packets are logged there in a semi-human-readable way. This should give you more momentum. Good luck.

    When you're done, and you'd like to contribute you project, we can always link to your implementation, just like we already have react-native and Flutter wrappers.

    BR, Aleksander

Reply
  • The buttonless service is used to reboot your device into DFU bootloader mode. In that mode you device will only have DFU service and DFU Control Point and DFU Packet characteristics inside (except from Generic Attribute and Generic Access, of course).

    How to use this service is explained here: Buttonless Secure DFU Service

    For non-bonded devices, the bootloader will advertise with a different MAC address (+1). The phone needs to scan for it to connect to it. Our libraries take care of it automatically, but you need to make sure you connect to the proper device. Remember, that on iOS you don't have MAC address, so you can't compare it with the previous one. iOS DFU Library is using peripheralSelector, and the selection (starting from DFU from SDK 14) is using "Set advertisement name" feature (see the first link, command 0x02).

    After you jumped to bootloader mode successfully, you need to check in what state your device is. You do this by setting the object to COMMAND. You will get the offset and CRC32 of the object. For fresh update both will be 0. If an update has started and may be resumed, they'll contain the proper values for you to compare (if cry doesn't match, or you don't want to resume, you always may start again by creating new COMMAND object). Then you need to follow the BLE Transport: Device Firmware Update process.

    Regarding your question about the ZIP file. ZIP file contains 3 or 5 files. One is always the manifest.json, which specifies the names of 2 or 4 other files. In one ZIP file there may be an update for App only, or SoftDevice+Bootloader and App. Or any of them alone. The dat file is generated using nrfutil tool. The same tool may be used to read the content for the zip file, including decoding the dat files. The dat files are using Protobuf to encode the firmware size, type, hw type, required soft device(s), signature, crc, etc. They are to be sent prior to the firmware for validation. Bootloader may reject the firmware based on the init packet.

    I would recommend first trying the bootloader using nRF Connect for Android or iOS. Check if your ZIP file is working. Then examine the log. All packets are logged there in a semi-human-readable way. This should give you more momentum. Good luck.

    When you're done, and you'd like to contribute you project, we can always link to your implementation, just like we already have react-native and Flutter wrappers.

    BR, Aleksander

Children
  • Thank you for the detailed response.

    I have been able to implement DFU in my code with some success, but not final success. I am doing this by trying to follow the Android code and a lot of trial and error.

    First I have to thank whoever wrote the DFU firmware. It is awesome that when I mess up the process the device just times out after a little bit and returns to normal operation. THANK YOU!!!

    I have 2 .zip files with different versions of my firmware that I can verify the version when it is in normal operation.

    I am able to use the iOS DFU app from Nordic to update my device with both of these files and verify that the version is changing when I check it.

    When I do the same thing using my own app, everything seems to work because I don't get any errors and the CRC values all match at every step.

    I do the dat file with no errors. I then do the bin file with no errors. I execute each object at the end with no errors. The offsets are all what I expect.

    When I send the last execute command on the last packet the device response correctly and then automatically reboots all by itself as expected.

    The device then enters normal operation, but when I check the version it is not the one I think I just sent. I have tried both versions of my .zip and the reported version during normal operation never changes.

    What could be going wrong and how do I figure that out?

  • If you get a success from the last execute, when the offset is equal to the fw size, and the device reboots, it should swap banks. You may verify that they were swapped by downloading the fw using nRF Connect for PC and comparing hex files. If they were swapped, try resetting Bluetooth in iPhone. Maybe it's cache? Do you read values to verify, or check services?

  • The other option I can see is that you flash incorrect versions of fw. On version A you flash A again, and on B - B. When doing dfu in our app you flash the right versions.

  • As far as I can tell I am not getting any errors. The last execute is for the full size of the fw and the checksum matches on the last packet.

    I have my own characteristic that I can ask for the internal version of my firmware that I am setting. I am checking this value. It will report an embedded version number that I hard code into the fw. It is not changing.

    When I use the Nordic DFU app to update my device this internal version does change. I am using the same zip file in both cases. That tells me that it has to be something I am doing, but I can't figure out what I am doing wrong or how to figure this out.

    Any more ideas would be greatly appreciated.

  • I have 2 versions of my fw. The only difference is this internal version I have. One I have hard coded version 110 and the other is hard coded version 111.

    If I use the Nordic app to flash 110 in and then use my characteristic to get the version using my app I get 110. If I then flash in 111 using Nordic it changes to 111.

    If I use my own app to do it then the version doesn't change even though I don't get any errors.

Related