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

How to add buttonless_dfu and serial_dfu functions at the same time.

Now the code in the application part has added the buttonless_dfu function, which has also been successfully implemented. But I ’m not familiar with serial_dfu, I don’t know how to continue to add serial_dfu function. And how to achieve coexistence of ble_dfu and serial_dfu in bootload code?

Parents
  • Hi June, 

    You can have a look at this case: https://devzone.nordicsemi.com/f/nordic-q-a/35431/dfu-over-ble-and-usb

    I have an example for SDK v15.2 there. To find how to enter DFU bootloader mode from application, please study the ble_app_buttonless_dfu example. Check function enter_bootloader() and then ble_dfu_buttonless_bootloader_start_prepare(). The GPREGRET register is written before the application reset and enter bootloader. 

  • Hi Hung Bui,

    I have added the serial_dfu code with reference to this routine, and now I have a few questions:

    1、Does uart need flow control during serial dfu? I am currently turning off serial port flow control because my hardware does not have two pins for flow control

    2、In normal application operation, in addition to the buttonless method, I can also enter the upgrade mode by pressing the button. After pressing the button, I performed the following operations:

    err_code = sd_power_gpregret_clr(0, 0xffffffff);
    VERIFY_SUCCESS(err_code);
    
    err_code = sd_power_gpregret_set(0, BOOTLOADER_DFU_START);
    VERIFY_SUCCESS(err_code);
    
    // Signal that DFU mode is to be enter to the power management module
    nrf_pwr_mgmt_shutdown(NRF_PWR_MGMT_SHUTDOWN_GOTO_DFU);

    Is this correct?

    3、After entering the upgrade mode, what nrfutil command is used to upgrade the zip package into the chip?

  • Hi, Hung

    Now, when the HWFC is turned on, the DFU can be normal, but once the HWFC is turned off, the DFU will fail.

    Failure information is as follows:

    Traceback (most recent call last):
      File "D:\Application\Python38\Scripts\nrfutil-script.py", line 11, in <module>
        load_entry_point('nrfutil==6.0.1', 'console_scripts', 'nrfutil')()
      File "D:\Application\Python38\lib\site-packages\click-7.1.1-py3.8.egg\click\core.py", line 829, in __call__
        return self.main(*args, **kwargs)
      File "D:\Application\Python38\lib\site-packages\click-7.1.1-py3.8.egg\click\core.py", line 782, in main
        rv = self.invoke(ctx)
      File "D:\Application\Python38\lib\site-packages\click-7.1.1-py3.8.egg\click\core.py", line 1259, in invoke
        return _process_result(sub_ctx.command.invoke(sub_ctx))
      File "D:\Application\Python38\lib\site-packages\click-7.1.1-py3.8.egg\click\core.py", line 1259, in invoke
        return _process_result(sub_ctx.command.invoke(sub_ctx))
      File "D:\Application\Python38\lib\site-packages\click-7.1.1-py3.8.egg\click\core.py", line 1066, in invoke
        return ctx.invoke(self.callback, **ctx.params)
      File "D:\Application\Python38\lib\site-packages\click-7.1.1-py3.8.egg\click\core.py", line 610, in invoke
        return callback(*args, **kwargs)
      File "D:\Application\Python38\lib\site-packages\nrfutil-6.0.1-py3.8.egg\nordicsemi\__main__.py", line 1055, in serial
        do_serial(package, port, connect_delay, flow_control, packet_receipt_notification, baud_rate, serial_number, True,
      File "D:\Application\Python38\lib\site-packages\nrfutil-6.0.1-py3.8.egg\nordicsemi\__main__.py", line 970, in do_serial
        dfu.dfu_send_images()
      File "D:\Application\Python38\lib\site-packages\nrfutil-6.0.1-py3.8.egg\nordicsemi\dfu\dfu.py", line 127, in dfu_send_images
        self._dfu_send_image(self.manifest.application)
      File "D:\Application\Python38\lib\site-packages\nrfutil-6.0.1-py3.8.egg\nordicsemi\dfu\dfu.py", line 100, in _dfu_send_image
        self.dfu_transport.send_firmware(data)
      File "D:\Application\Python38\lib\site-packages\nrfutil-6.0.1-py3.8.egg\nordicsemi\dfu\dfu_transport_serial.py", line 301, in send_firmware
        response['crc'] = self.__stream_data(data=data, crc=response['crc'], offset=i)
      File "D:\Application\Python38\lib\site-packages\nrfutil-6.0.1-py3.8.egg\nordicsemi\dfu\dfu_transport_serial.py", line 474, in __stream_data
        response = self.__calculate_checksum()
      File "D:\Application\Python38\lib\site-packages\nrfutil-6.0.1-py3.8.egg\nordicsemi\dfu\dfu_transport_serial.py", line 412, in __calculate_checksum
        raise NordicSemiException('Did not receive checksum response from DFU target. '
    pc_ble_driver_py.exceptions.NordicSemiException: Did not receive checksum response from DFU target. If MSD is enabled on the target device, try to disable it ref. https://wiki.segger.com/index.php?title=J-Link-OB_SAM3U

    The LOG during the DFU upgrade process is as follows:

    <info> nrf_dfu_serial_uart: Allocated buffer 2000B08C
    <debug> nrf_dfu_req_handler: Handle NRF_DFU_OP_PING
    <debug> nrf_dfu_req_handler: Request handling complete. Result: 0x1
    <debug> : Sending Response: [0x9, 0x1]
    <debug> : 
    <info> nrf_dfu_serial_uart: Allocated buffer 2000B08C
    <debug> nrf_dfu_req_handler: Handle NRF_DFU_OP_RECEIPT_NOTIF_SET
    <debug> nrf_dfu_req_handler: Request handling complete. Result: 0x1
    <debug> : Sending Response: [0x2, 0x1]
    <debug> : 
    <info> nrf_dfu_serial_uart: Allocated buffer 2000B08C
    <debug> nrf_dfu_req_handler: Handle NRF_DFU_OP_MTU_GET
    <debug> nrf_dfu_req_handler: Request handling complete. Result: 0x1
    <debug> : Sending Response: [0x7, 0x1]
    <info> nrf_dfu_serial_uart: Allocated buffer 2000B08C
    <debug> nrf_dfu_req_handler: Handle NRF_DFU_OP_OBJECT_SELECT (command)
    <debug> nrf_dfu_req_handler: Request handling complete. Result: 0x1
    <debug> : Sending Response: [0x6, 0x1]
    <debug> app: Shutting down transports (found: 2)
    <debug> nrf_dfu_ble: Shutting down BLE transport.
    <info> nrf_dfu_serial_uart: Allocated buffer 2000B08C
    <debug> nrf_dfu_req_handler: Handle NRF_DFU_OP_OBJECT_CREATE (command)
    <debug> app: timer_stop (0x200057D4)
    <debug> app: timer_activate (0x200057D4)
    <debug> nrf_dfu_req_handler: Request handling complete. Result: 0x1
    <debug> : Sending Response: [0x1, 0x1]
    <info> nrf_dfu_serial_uart: Allocated buffer 2000B110
    <debug> nrf_dfu_req_handler: Handle NRF_DFU_OP_OBJECT_WRITE (command)
    <debug> nrf_dfu_req_handler: Request handling complete. Result: 0x1
    <info> nrf_dfu_serial_uart: Allocated buffer 2000B08C
    <debug> nrf_dfu_req_handler: Handle NRF_DFU_OP_OBJECT_WRITE (command)
    <debug> nrf_dfu_req_handler: Request handling complete. Result: 0x1
    <info> nrf_dfu_serial_uart: Allocated buffer 2000B110
    <debug> nrf_dfu_req_handler: Handle NRF_DFU_OP_OBJECT_WRITE (command)
    <debug> nrf_dfu_req_handler: Request handling complete. Result: 0x1
    <info> nrf_dfu_serial_uart: Allocated buffer 2000B110
    <debug> nrf_dfu_req_handler: Handle NRF_DFU_OP_CRC_GET (command)
    <debug> nrf_dfu_req_handler: Request handling complete. Result: 0x1
    <debug> : Sending Response: [0x3, 0x1]
    <info> nrf_dfu_serial_uart: Allocated buffer 2000B110
    <debug> nrf_dfu_req_handler: Handle NRF_DFU_OP_OBJECT_EXECUTE (command)
    <debug> nrf_dfu_validation: PB: Init packet data len: 64
    <info> nrf_dfu_validation: Signature required. Checking signature.
    <info> nrf_dfu_validation: Calculating hash (len: 64)
    <info> nrf_dfu_validation: Verify signature
    <info> nrf_dfu_validation: Image verified
    <debug> app: Enter nrf_dfu_cache_prepare()
    <debug> app: required_size: 0x5788.
    <debug> app: single_bank: false.
    <debug> app: keep_app: false.
    <debug> app: keep_softdevice: true.
    <debug> app: SD_PRESENT: true.
    <debug> app: Bank contents:
    <debug> app: Bank 0 code: 0x00: Size: 0x0
    <debug> app: Bank 1 code: 0x00: Size: 0x0
    <debug> app: pass: 0.
    <debug> app: cache_address: 0x26000.
    <debug> app: cache_too_small: false.
    <debug> app: keep_firmware: false.
    <debug> app: delete_more: false.
    <debug> nrf_dfu_validation: Write address set to 0x00026000
    <debug> nrf_dfu_settings: Writing settings...
    <debug> nrf_dfu_settings: Erasing old settings at: 0x000FF000
    <debug> nrf_dfu_flash: nrf_fstorage_erase(addr=0x0x000FF000, len=1 pages), queue usage: 1
    <debug> nrf_dfu_flash: nrf_fstorage_write(addr=0x000FF000, src=0x2000A1F0, len=896 bytes), queue usage: 2
    <info> nrf_dfu_settings: Backing up settings page to address 0xFE000.
    <debug> nrf_dfu_settings: Writing settings...
    <debug> nrf_dfu_settings: Erasing old settings at: 0x000FE000
    <debug> nrf_dfu_flash: nrf_fstorage_erase(addr=0x0x000FE000, len=1 pages), queue usage: 3
    <debug> nrf_dfu_flash: nrf_fstorage_write(addr=0x000FE000, src=0x2000A570, len=896 bytes), queue usage: 4
    <debug> nrf_dfu_req_handler: Writing valid init command to flash.
    <debug> nrf_dfu_req_handler: Request handling complete. Result: 0x1
    <debug> : Sending Response: [0x4, 0x1]
    <debug> nrf_dfu_flash: Flash erase success: addr=0x000FF000, pending 4
    <info> nrf_dfu_serial_uart: Allocated buffer 2000B110
    <debug> nrf_dfu_req_handler: Handle NRF_DFU_OP_OBJECT_SELECT (data)
    <debug> nrf_dfu_req_handler: crc = 0x0, offset = 0x0, max_size = 0x1000
    <debug> nrf_dfu_req_handler: Request handling complete. Result: 0x1
    <debug> : Sending Response: [0x6, 0x1]
    <debug> nrf_dfu_flash: Flash write success: addr=0x000FF000, pending 3
    <info> nrf_dfu_serial_uart: Allocated buffer 2000B110
    <debug> nrf_dfu_flash: Flash erase success: addr=0x000FE000, pending 2
    <debug> nrf_dfu_req_handler: Handle NRF_DFU_OP_OBJECT_CREATE (data)
    <debug> nrf_dfu_flash: nrf_fstorage_erase(addr=0x0x00026000, len=1 pages), queue usage: 2
    <debug> nrf_dfu_req_handler: Creating object with size: 4096. Offset: 0x00000000, CRC: 0x00000000
    <debug> nrf_dfu_req_handler: Request handling complete. Result: 0x1
    <debug> ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ1]
    <debug> nrf_dfu_flash: Flash write success: addr=0x000FE000, pending 2
    <error> app: Received an error: 0x00000001!

  • Now I can be sure that this must not be a hardware problem, nor a problem with the nrfutil tool. I also made sure that I implemented MSDDisable. And when the HWFC is closed, the baud rate is reduced to 9600, and the DFU will fail. Then turn on HWFC, DFU can succeed again.

  • Do you have a solution to this problem? I've been knocked out by this problem...

  • Hi June, 
    I'm not sure what could be wrong here as the test here worked fine. 

    I have modified the nrf_dfu_serial_uart.c a little bit but I don't think it would help much. Please try using the file I provided here. 

    I can see in the log there is a printing of a long "ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ" could you check why ? Did you modify anything creating that ? 

    THere is an error "0x00001" that we need to investigate. 

    Please add DEBUG into the preprocessor definition in the project setting so that we can have more logging information. If there is a complain about app_error_save_and_stop() you can just change it to "while(1);"

    /**
     * Copyright (c) 2016 - 2019, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    
    #include "nrf_dfu_serial.h"
    
    #include <string.h>
    #include "boards.h"
    #include "app_util_platform.h"
    #include "nrf_dfu_transport.h"
    #include "nrf_dfu_req_handler.h"
    #include "slip.h"
    #include "nrf_balloc.h"
    #include "nrf_drv_uart.h"
    
    #define NRF_LOG_MODULE_NAME nrf_dfu_serial_uart
    #include "nrf_log.h"
    NRF_LOG_MODULE_REGISTER();
    
    /**@file
     *
     * @defgroup nrf_dfu_serial_uart DFU Serial UART transport
     * @ingroup  nrf_dfu
     * @brief    Device Firmware Update (DFU) transport layer using UART.
     */
     
    #define NRF_SERIAL_OPCODE_SIZE          (sizeof(uint8_t))
    #define NRF_UART_MAX_RESPONSE_SIZE_SLIP (2 * NRF_SERIAL_MAX_RESPONSE_SIZE + 1)
    #define RX_BUF_SIZE                     (64) //to get 64bytes payload
    #define OPCODE_OFFSET                   (sizeof(uint32_t) - NRF_SERIAL_OPCODE_SIZE)
    #define DATA_OFFSET                     (OPCODE_OFFSET + NRF_SERIAL_OPCODE_SIZE)
    #define UART_SLIP_MTU                   (2 * (RX_BUF_SIZE + 1) + 1)
    #define BALLOC_BUF_SIZE                 ((CEIL_DIV((RX_BUF_SIZE+OPCODE_SIZE),sizeof(uint32_t))*sizeof(uint32_t)))
    
    NRF_BALLOC_DEF(m_payload_pool, (UART_SLIP_MTU + 1), NRF_DFU_SERIAL_UART_RX_BUFFERS);
    
    static nrf_drv_uart_t m_uart =  NRF_DRV_UART_INSTANCE(0);
    static uint8_t m_rx_byte;
    
    static nrf_dfu_serial_t m_serial;
    static slip_t m_slip;
    static uint8_t m_rsp_buf[NRF_UART_MAX_RESPONSE_SIZE_SLIP];
    static bool m_active;
    
    static nrf_dfu_observer_t m_observer;
    
    static uint32_t uart_dfu_transport_init(nrf_dfu_observer_t observer);
    static uint32_t uart_dfu_transport_close(nrf_dfu_transport_t const * p_exception);
    
    DFU_TRANSPORT_REGISTER(nrf_dfu_transport_t const uart_dfu_transport) =
    {
        .init_func  = uart_dfu_transport_init,
        .close_func = uart_dfu_transport_close,
    };
    
    static void payload_free(void * p_buf)
    {
        uint8_t * p_buf_root = (uint8_t *)p_buf - DATA_OFFSET; //pointer is shifted to point to data
        nrf_balloc_free(&m_payload_pool, p_buf_root);
    }
    
    static ret_code_t rsp_send(uint8_t const * p_data, uint32_t length)
    {
        uint32_t slip_len;
        (void) slip_encode(m_rsp_buf, (uint8_t *)p_data, length, &slip_len);
    
        return nrf_drv_uart_tx(&m_uart, m_rsp_buf, slip_len);
    }
    static uint8_t close_transport_flag=1;
    static __INLINE void on_rx_complete(nrf_dfu_serial_t * p_transport, uint8_t * p_data, uint8_t len)
    {
        ret_code_t ret_code;
    
        ret_code = slip_decode_add_byte(&m_slip, p_data[0]);
        (void) nrf_drv_uart_rx(&m_uart, &m_rx_byte, 1);
    
        if (ret_code == NRF_SUCCESS)
        {
                if (close_transport_flag)
            {
                UNUSED_RETURN_VALUE(nrf_dfu_transports_close(&uart_dfu_transport));
                close_transport_flag=0;
            }
            nrf_dfu_serial_on_packet_received(p_transport,
                                             (uint8_t const *)m_slip.p_buffer,
                                             m_slip.current_index);
    
            uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool);
            if (p_rx_buf == NULL)
            {
                NRF_LOG_ERROR("Failed to allocate buffer");
                return;
            }
            NRF_LOG_INFO("Allocated buffer %x", p_rx_buf);
            // reset the slip decoding
            m_slip.p_buffer      = &p_rx_buf[OPCODE_OFFSET];
            m_slip.current_index = 0;
            m_slip.state         = SLIP_STATE_DECODING;
        }
    
    }
    
    static void uart_event_handler(nrf_drv_uart_event_t * p_event, void * p_context)
    {
        switch (p_event->type)
        {
            case NRF_DRV_UART_EVT_RX_DONE:
                on_rx_complete((nrf_dfu_serial_t*)p_context,
                               p_event->data.rxtx.p_data,
                               p_event->data.rxtx.bytes);
                break;
    
            case NRF_DRV_UART_EVT_ERROR:
                APP_ERROR_HANDLER(p_event->data.error.error_mask);
                break;
    
            default:
                // No action.
                break;
        }
    }
    
    static uint32_t uart_dfu_transport_init(nrf_dfu_observer_t observer)
    {
        uint32_t err_code = NRF_SUCCESS;
    
        if (m_active)
        {
            return err_code;
        }
    
        NRF_LOG_DEBUG("serial_dfu_transport_init()");
    
        m_observer = observer;
    
        err_code = nrf_balloc_init(&m_payload_pool);
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }
    
        uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool);
    
        m_slip.p_buffer      =  &p_rx_buf[OPCODE_OFFSET];
        m_slip.current_index = 0;
        m_slip.buffer_len    = UART_SLIP_MTU;
        m_slip.state         = SLIP_STATE_DECODING;
    
        m_serial.rsp_func           = rsp_send;
        m_serial.payload_free_func  = payload_free;
        m_serial.mtu                = UART_SLIP_MTU;
        m_serial.p_rsp_buf          = &m_rsp_buf[NRF_UART_MAX_RESPONSE_SIZE_SLIP -
                                                NRF_SERIAL_MAX_RESPONSE_SIZE];
        m_serial.p_low_level_transport = &uart_dfu_transport;
    
        nrf_drv_uart_config_t uart_config = NRF_DRV_UART_DEFAULT_CONFIG;
    
        uart_config.pseltxd   = TX_PIN_NUMBER;
        uart_config.pselrxd   = RX_PIN_NUMBER;
        uart_config.pselcts   = CTS_PIN_NUMBER;
        uart_config.pselrts   = RTS_PIN_NUMBER;
        uart_config.hwfc      = NRF_DFU_SERIAL_UART_USES_HWFC ?
                                    NRF_UART_HWFC_ENABLED : NRF_UART_HWFC_DISABLED;
        uart_config.p_context = &m_serial;
    
        err_code =  nrf_drv_uart_init(&m_uart, &uart_config, uart_event_handler);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Failed initializing uart");
            return err_code;
        }
    
        err_code = nrf_drv_uart_rx(&m_uart, &m_rx_byte, 1);
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Failed initializing rx");
        }
    
        NRF_LOG_DEBUG("serial_dfu_transport_init() completed");
    
        m_active = true;
    
        if (m_observer)
        {
            m_observer(NRF_DFU_EVT_TRANSPORT_ACTIVATED);
        }
    
        return err_code;
    }
    
    
    static uint32_t uart_dfu_transport_close(nrf_dfu_transport_t const * p_exception)
    {
        if ((m_active == true) && (p_exception != &uart_dfu_transport))
        {
            nrf_drv_uart_uninit(&m_uart);
            m_active = false;
        }
    
        return NRF_SUCCESS;
    }
    
    

  • Is the DFU normal after you shut down hwfc? As long as I don't close hwfc, everything is normal. After shutting down hwfc, DFU will fail

Reply Children
  • OK, I tested again here with the HWFC for DFU serial changed in sdkconfig.h and saw the same issue as yours. 
    Could you try using the default nrf_dfu_ble.c file in the SDK, not the file I provided in the example .zip folder. 
    After I reverted it to the original one it worked. (but please still use the nrf_dfu_serial_uart.c that I sent you) 
    I attached the original nrf_dfu_ble.c file just in case. 

    /**
     * Copyright (c) 2016 - 2019, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    #include "nrf_dfu_ble.h"
    
    #include <stddef.h>
    #include "sdk_common.h"
    #include "nrf_dfu_transport.h"
    #include "nrf_dfu_types.h"
    #include "nrf_dfu_req_handler.h"
    #include "nrf_dfu_handling_error.h"
    #include "nrf_sdm.h"
    #include "nrf_dfu_mbr.h"
    #include "nrf_bootloader_info.h"
    #include "ble.h"
    #include "ble_srv_common.h"
    #include "ble_hci.h"
    #include "nrf_sdh.h"
    #include "nrf_sdh_ble.h"
    #include "nrf_balloc.h"
    #include "nrf_delay.h"
    #include "nrf_dfu_settings.h"
    #include "nrf_dfu_ble.h"
    
    #define NRF_LOG_MODULE_NAME nrf_dfu_ble
    #include "nrf_log.h"
    NRF_LOG_MODULE_REGISTER();
    
    #ifndef NRF_DFU_BLE_ADV_INTERVAL
    #define NRF_DFU_BLE_ADV_INTERVAL 40 /* 40 * 0,625ms = 25ms */
    #warning "sdk_config.h is not up to date."
    #endif
    
    #define APP_BLE_CONN_CFG_TAG                1                                                       /**< A tag identifying the SoftDevice BLE configuration. */
    
    #define APP_ADV_DATA_HEADER_SIZE            9                                                       /**< Size of encoded advertisement data header (not including device name). */
    #define APP_ADV_DURATION                    BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED                   /**< The advertising duration in units of 10 milliseconds. This is set to @ref BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED so that the advertisement is done as long as there there is a call to @ref dfu_transport_close function.*/
    
    #define GATT_HEADER_LEN                     3                                                       /**< GATT header length. */
    #define GATT_PAYLOAD(mtu)                   ((mtu) - GATT_HEADER_LEN)                               /**< Length of the ATT payload for a given ATT MTU. */
    #define MAX_DFU_PKT_LEN                     (NRF_SDH_BLE_GATT_MAX_MTU_SIZE - GATT_HEADER_LEN)       /**< Maximum length (in bytes) of the DFU Packet characteristic (3 bytes are used for the GATT opcode and handle). */
    #define MAX_RESPONSE_LEN                    17                                                      /**< Maximum length (in bytes) of the response to a Control Point command. */
    #define RESPONSE_HEADER_LEN                 3                                                       /**< The length of the header of a response. I.E. the index of the opcode-specific payload. */
    
    #define DFU_BLE_FLAG_INITIALIZED            (1 << 0)                                                /**< Flag to check if the DFU service was initialized by the application.*/
    #define DFU_BLE_FLAG_USE_ADV_NAME           (1 << 1)                                                /**< Flag to indicate that advertisement name is to be used. */
    #define DFU_BLE_RESETTING_SOON              (1 << 2)                                                /**< Flag to indicate that the device will reset soon. */
    
    #define BLE_OBSERVER_PRIO                   2                                                       /**< BLE observer priority. Controls the priority for BLE event handler. */
    
    #if (NRF_DFU_BLE_BUFFERS_OVERRIDE)
    /* If selected, use the override value. */
    #define MAX_DFU_BUFFERS     NRF_DFU_BLE_BUFFERS
    #else
    #define MAX_DFU_BUFFERS     ((CODE_PAGE_SIZE / MAX_DFU_PKT_LEN) + 1)
    #endif
    
    #if (NRF_DFU_BLE_REQUIRES_BONDS) && (!NRF_SDH_BLE_SERVICE_CHANGED)
    #error NRF_DFU_BLE_REQUIRES_BONDS requires NRF_SDH_BLE_SERVICE_CHANGED.   \
           Please update the SoftDevice BLE stack configuration in sdk_config.h
    #endif
    
    #if (MAX_DFU_PKT_LEN % 4)
    #error Payload length should be a multiple of four. \
           Payload length is set to NRF_SDH_BLE_GATT_MAX_MTU_SIZE - 3.
    #endif
    
    
    DFU_TRANSPORT_REGISTER(nrf_dfu_transport_t const ble_dfu_transport) =
    {
        .init_func  = ble_dfu_transport_init,
        .close_func = ble_dfu_transport_close,
    };
    
    #if (NRF_DFU_BLE_REQUIRES_BONDS)
    static nrf_dfu_peer_data_t m_peer_data;
    #else
    static nrf_dfu_adv_name_t  m_adv_name;
    #endif
    
    static uint32_t           m_flags;
    static ble_dfu_t          m_dfu;                                                                    /**< Structure used to identify the Device Firmware Update service. */
    static uint16_t           m_pkt_notif_target;                                                       /**< Number of packets of firmware data to be received before transmitting the next Packet Receipt Notification to the DFU Controller. */
    static uint16_t           m_pkt_notif_target_cnt;                                                   /**< Number of packets of firmware data received after sending last Packet Receipt Notification or since the receipt of a @ref BLE_DFU_PKT_RCPT_NOTIF_ENABLED event from the DFU service, which ever occurs later.*/
    static uint16_t           m_conn_handle = BLE_CONN_HANDLE_INVALID;                                  /**< Handle of the current connection. */
    static uint8_t            m_adv_handle  = BLE_GAP_ADV_SET_HANDLE_NOT_SET;                           /**< Advertising handle used to identify an advertising set. */
    static nrf_dfu_observer_t m_observer;                                                               /**< Observer function called on certain events. */
    
    static ble_gap_conn_params_t const m_gap_conn_params =
    {
        .min_conn_interval = NRF_DFU_BLE_MIN_CONN_INTERVAL,
        .max_conn_interval = NRF_DFU_BLE_MAX_CONN_INTERVAL,
        /* This value is expressed in units of 10 ms, rather than 1 ms. */
        .conn_sup_timeout  = NRF_DFU_BLE_CONN_SUP_TIMEOUT_MS / 10,
        .slave_latency     = 0,
    };
    
    NRF_BALLOC_DEF(m_buffer_pool, MAX_DFU_PKT_LEN, MAX_DFU_BUFFERS);
    
    
    /**@brief     Function for the Advertising functionality initialization.
     *
     * @details   Encodes the required advertising data and passes it to the stack.
     *            The advertising data encoded here is specific for DFU.
     */
    static uint32_t advertising_init(uint8_t adv_flags, ble_gap_adv_params_t const * const p_adv_params)
    {
        uint32_t err_code;
        uint16_t actual_device_name_length = BLE_GAP_ADV_SET_DATA_SIZE_MAX - APP_ADV_DATA_HEADER_SIZE;
    
        /* This needs to be static because of SoftDevice API requirements. */
        static uint8_t m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX];
    
        ble_gap_adv_data_t m_adv_data =
        {
            .adv_data =
            {
                .p_data = m_enc_advdata,
                .len    = APP_ADV_DATA_HEADER_SIZE,
            }
        };
    
        /* Encode flags. */
        m_enc_advdata[0] = 0x2;
        m_enc_advdata[1] = BLE_GAP_AD_TYPE_FLAGS;
        m_enc_advdata[2] = adv_flags;
    
        /* Encode 'more available' UUID list. */
        m_enc_advdata[3] = 0x3;
        m_enc_advdata[4] = BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE;
        m_enc_advdata[5] = LSB_16(BLE_DFU_SERVICE_UUID);
        m_enc_advdata[6] = MSB_16(BLE_DFU_SERVICE_UUID);
    
        /* Get GAP device name and length. */
        err_code = sd_ble_gap_device_name_get(&m_enc_advdata[9], &actual_device_name_length);
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }
    
        // Set GAP device in advertising data.
        m_enc_advdata[7] = actual_device_name_length + 1; // (actual_length + ADV_AD_TYPE_FIELD_SIZE(1))
        m_enc_advdata[8] = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME;
    
        m_adv_data.adv_data.len += actual_device_name_length;
    
        return sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, p_adv_params);
    }
    
    
    /**@brief Function for starting advertising.
     */
    static uint32_t advertising_start(void)
    {
        uint32_t err_code;
        uint8_t  adv_flag = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
    
        ble_gap_adv_params_t adv_params =
        {
            .properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED,
            .p_peer_addr     = NULL,
            .filter_policy   = BLE_GAP_ADV_FP_ANY,
            .interval        = NRF_DFU_BLE_ADV_INTERVAL,
            .duration        = APP_ADV_DURATION,
            .primary_phy     = BLE_GAP_PHY_1MBPS,
        };
    
        NRF_LOG_DEBUG("Advertising...");
    
    #if (NRF_DFU_BLE_REQUIRES_BONDS)
        ble_gap_irk_t empty_irk = {{0}};
    
        if (memcmp(m_peer_data.ble_id.id_info.irk, empty_irk.irk, sizeof(ble_gap_irk_t)) != 0)
        {
            adv_flag                 = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED;
            adv_params.filter_policy = BLE_GAP_ADV_FP_FILTER_CONNREQ;
    
            ble_gap_addr_t   const * const p_gap_addr   = &m_peer_data.ble_id.id_addr_info;
            ble_gap_id_key_t const * const p_gap_id_key = &m_peer_data.ble_id;
    
            err_code = sd_ble_gap_whitelist_set(&p_gap_addr, 1);
            if (err_code != NRF_SUCCESS)
            {
                NRF_LOG_WARNING("sd_ble_gap_whitelist_set() returned %s",
                                NRF_LOG_ERROR_STRING_GET(err_code));
            }
    
            err_code = sd_ble_gap_device_identities_set(&p_gap_id_key, NULL, 1);
            if (err_code != NRF_SUCCESS)
            {
                NRF_LOG_WARNING("sd_ble_gap_device_identities_set() returned %s",
                                NRF_LOG_ERROR_STRING_GET(err_code));
            }
        }
    #endif /* NRF_DFU_BLE_REQUIRES_BONDS */
    
        err_code = advertising_init(adv_flag, &adv_params);
        VERIFY_SUCCESS(err_code);
    
        err_code = sd_ble_gap_adv_stop(m_adv_handle);
        UNUSED_RETURN_VALUE(err_code);
    
        return sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG);
    }
    
    
    static bool is_cccd_configured(ble_dfu_t * p_dfu)
    {
        uint8_t cccd_val_buf[BLE_CCCD_VALUE_LEN];
    
        ble_gatts_value_t gatts_value =
        {
            .len     = BLE_CCCD_VALUE_LEN,
            .p_value = cccd_val_buf
        };
    
        /* Check the CCCD Value of DFU Control Point. */
        uint32_t err_code = sd_ble_gatts_value_get(m_conn_handle,
                                                   p_dfu->dfu_ctrl_pt_handles.cccd_handle,
                                                   &gatts_value);
        VERIFY_SUCCESS(err_code);
    
        return ble_srv_is_notification_enabled(cccd_val_buf);
    }
    
    
    static ret_code_t response_send(uint8_t * p_buf, uint16_t len)
    {
        ble_gatts_hvx_params_t hvx_params =
        {
            .handle = m_dfu.dfu_ctrl_pt_handles.value_handle,
            .type   = BLE_GATT_HVX_NOTIFICATION,
            .p_data = (uint8_t *)(p_buf),
            .p_len  = &len,
        };
    
        return sd_ble_gatts_hvx(m_conn_handle, &hvx_params);
    }
    
    
    #if (NRF_DFU_BLE_REQUIRES_BONDS)
    static uint32_t service_changed_send(void)
    {
        uint32_t err_code;
    
        NRF_LOG_DEBUG("Sending Service Changed indication");
    
        err_code = sd_ble_gatts_sys_attr_set(m_conn_handle,
                                             m_peer_data.sys_serv_attr,
                                             sizeof(m_peer_data.sys_serv_attr),
                                             BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
        VERIFY_SUCCESS(err_code);
    
        err_code = sd_ble_gatts_sys_attr_set(m_conn_handle,
                                             NULL,
                                             0,
                                             BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS);
        VERIFY_SUCCESS(err_code);
    
        err_code = sd_ble_gatts_service_changed(m_conn_handle, m_dfu.service_handle, 0xFFFF);
    
        if (   (err_code == BLE_ERROR_INVALID_CONN_HANDLE)
            || (err_code == NRF_ERROR_INVALID_STATE)
            || (err_code == NRF_ERROR_BUSY))
        {
            /* These errors can be expected when trying to send a Service Changed indication */
            /* if the CCCD is not set to indicate. Thus, set the returning error code to success. */
            NRF_LOG_WARNING("Client did not have the Service Changed indication set to enabled."
                            "Error: 0x%08x", err_code);
            err_code = NRF_SUCCESS;
        }
    
        return err_code;
    }
    #endif
    
    
    /**@brief Function for encoding the beginning of a response.
     *
     * @param[inout] p_buffer  The buffer to encode into.
     * @param[in]    op_code   The opcode of the response.
     * @param[in]    result    The result of the operation.
     *
     * @return The length added to the buffer.
     */
    static uint32_t response_prepare(uint8_t * p_buffer, uint8_t op_code, uint8_t result)
    {
        ASSERT(p_buffer);
        p_buffer[0] = NRF_DFU_OP_RESPONSE;
        p_buffer[1] = op_code;
        p_buffer[2] = result;
        return RESPONSE_HEADER_LEN;
    }
    
    
    /**@brief Function for encoding a select object response into a buffer.
     *
     * The select object response consists of a maximum object size, a firmware offset, and a CRC value.
     *
     * @param[inout] p_buffer   The buffer to encode the response into.
     * @param[in]    max_size   The maximum object size value to encode.
     * @param[in]    fw_offset  The firmware offset value to encode.
     * @param[in]    crc        The CRC value to encode.
     *
     * @return The length added to the buffer.
     */
    static uint32_t response_select_obj_add(uint8_t  * p_buffer,
                                            uint32_t   max_size,
                                            uint32_t   fw_offset,
                                            uint32_t   crc)
    {
        uint16_t offset = uint32_encode(max_size,  &p_buffer[RESPONSE_HEADER_LEN]);
        offset         += uint32_encode(fw_offset, &p_buffer[RESPONSE_HEADER_LEN + offset]);
        offset         += uint32_encode(crc,       &p_buffer[RESPONSE_HEADER_LEN + offset]);
        return offset;
    }
    
    
    /**@brief Function for encoding a CRC response into a buffer.
     *
     * The CRC response consists of a firmware offset and a CRC value.
     *
     * @param[inout] p_buffer   The buffer to encode the response into.
     * @param[in]    fw_offset  The firmware offset value to encode.
     * @param[in]    crc        The CRC value to encode.
     *
     * @return The length added to the buffer.
     */
    static uint32_t response_crc_add(uint8_t * p_buffer, uint32_t fw_offset, uint32_t crc)
    {
        uint16_t offset = uint32_encode(fw_offset, &p_buffer[RESPONSE_HEADER_LEN]);
        offset         += uint32_encode(crc,       &p_buffer[RESPONSE_HEADER_LEN + offset]);
        return offset;
    }
    
    
    /**@brief Function for appending an extended error code to the response buffer.
     *
     * @param[inout] p_buffer    The buffer to append the extended error code to.
     * @param[in]    result      The error code to append.
     * @param[in]    buf_offset  The current length of the buffer.
     *
     * @return The length added to the buffer.
     */
    static uint32_t response_ext_err_payload_add(uint8_t * p_buffer, uint8_t result, uint32_t buf_offset)
    {
        p_buffer[buf_offset] = ext_error_get();
        (void) ext_error_set(NRF_DFU_EXT_ERROR_NO_ERROR);
        return 1;
    }
    
    
    static void ble_dfu_req_handler_callback(nrf_dfu_response_t * p_res, void * p_context)
    {
        ASSERT(p_res);
        ASSERT(p_context);
    
        uint8_t len = 0;
        uint8_t buffer[MAX_RESPONSE_LEN] = {0};
    
        if (p_res->request == NRF_DFU_OP_OBJECT_WRITE)
        {
            --m_pkt_notif_target_cnt;
            if ((m_pkt_notif_target == 0) || (m_pkt_notif_target_cnt && m_pkt_notif_target > 0))
            {
                return;
            }
    
            /* Reply with a CRC message and reset the packet counter. */
            m_pkt_notif_target_cnt = m_pkt_notif_target;
    
            p_res->request = NRF_DFU_OP_CRC_GET;
        }
    
        len += response_prepare(buffer, p_res->request, p_res->result);
    
        if (p_res->result != NRF_DFU_RES_CODE_SUCCESS)
        {
            NRF_LOG_WARNING("DFU request %d failed with error: 0x%x", p_res->request, p_res->result);
    
            if (p_res->result == NRF_DFU_RES_CODE_EXT_ERROR)
            {
                len += response_ext_err_payload_add(buffer, p_res->result, len);
            }
    
            (void) response_send(buffer, len);
            return;
        }
    
        switch (p_res->request)
        {
            case NRF_DFU_OP_OBJECT_CREATE:
            case NRF_DFU_OP_OBJECT_EXECUTE:
                break;
    
            case NRF_DFU_OP_OBJECT_SELECT:
            {
                len += response_select_obj_add(buffer,
                                               p_res->select.max_size,
                                               p_res->select.offset,
                                               p_res->select.crc);
            } break;
    
            case NRF_DFU_OP_OBJECT_WRITE:
            {
                len += response_crc_add(buffer, p_res->write.offset, p_res->write.crc);
            } break;
    
            case NRF_DFU_OP_CRC_GET:
            {
                len += response_crc_add(buffer, p_res->crc.offset, p_res->crc.crc);
            } break;
    
            default:
            {
                // No action.
            } break;
        }
    
        (void) response_send(buffer, len);
    }
    
    
    /**@brief     Function for handling a Write event on the Control Point characteristic.
     *
     * @param[in] p_dfu             DFU Service Structure.
     * @param[in] p_ble_write_evt   Pointer to the write event received from BLE stack.
     *
     * @return    NRF_SUCCESS on successful processing of control point write. Otherwise an error code.
     */
    static uint32_t on_ctrl_pt_write(ble_dfu_t * p_dfu, ble_gatts_evt_write_t const * p_ble_write_evt)
    {
        //lint -save -e415 -e416 : Out-of-bounds access on p_ble_write_evt->data
        nrf_dfu_request_t request =
        {
            .request           = (nrf_dfu_op_t)(p_ble_write_evt->data[0]),
            .p_context         = p_dfu,
            .callback.response = ble_dfu_req_handler_callback,
        };
    
        switch (request.request)
        {
            case NRF_DFU_OP_OBJECT_SELECT:
            {
                /* Set object type to read info about */
                request.select.object_type = p_ble_write_evt->data[1];
            } break;
    
            case NRF_DFU_OP_OBJECT_CREATE:
            {
                /* Reset the packet receipt notification on create object */
                m_pkt_notif_target_cnt = m_pkt_notif_target;
    
                request.create.object_type = p_ble_write_evt->data[1];
                request.create.object_size = uint32_decode(&(p_ble_write_evt->data[2]));
    
                if (request.create.object_type == NRF_DFU_OBJ_TYPE_COMMAND)
                {
                    /* Activity on the current transport. Close all except the current one. */
                    (void) nrf_dfu_transports_close(&ble_dfu_transport);
                }
            } break;
    
            case NRF_DFU_OP_RECEIPT_NOTIF_SET:
            {
                NRF_LOG_DEBUG("Set receipt notif");
    
                m_pkt_notif_target     = uint16_decode(&(p_ble_write_evt->data[1]));
                m_pkt_notif_target_cnt = m_pkt_notif_target;
            } break;
    
            default:
                break;
        }
        //lint -restore : Out-of-bounds access
    
        return nrf_dfu_req_handler_on_req(&request);
    }
    
    
    /**@brief     Function for handling the @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event from the
     *            SoftDevice.
     *
     * @param[in] p_dfu     DFU Service Structure.
     * @param[in] p_ble_evt Pointer to the event received from BLE stack.
     */
    static bool on_rw_authorize_req(ble_dfu_t * p_dfu, ble_evt_t const * p_ble_evt)
    {
        uint32_t err_code;
    
        ble_gatts_evt_rw_authorize_request_t const * p_authorize_request;
        ble_gatts_evt_write_t                const * p_ble_write_evt;
    
        p_authorize_request = &(p_ble_evt->evt.gatts_evt.params.authorize_request);
        p_ble_write_evt     = &(p_ble_evt->evt.gatts_evt.params.authorize_request.request.write);
    
        if (    (p_authorize_request->type                 != BLE_GATTS_AUTHORIZE_TYPE_WRITE)
            ||  (p_authorize_request->request.write.handle != p_dfu->dfu_ctrl_pt_handles.value_handle)
            ||  (p_authorize_request->request.write.op     != BLE_GATTS_OP_WRITE_REQ))
        {
            return false;
        }
    
        ble_gatts_rw_authorize_reply_params_t auth_reply =
        {
            .type                = BLE_GATTS_AUTHORIZE_TYPE_WRITE,
            .params.write.update = 1,
            .params.write.offset = p_ble_write_evt->offset,
            .params.write.len    = p_ble_write_evt->len,
            .params.write.p_data = p_ble_write_evt->data,
        };
    
        if (!is_cccd_configured(p_dfu))
        {
            /* Send an error response to the peer indicating that the CCCD is improperly configured. */
            auth_reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR;
    
            /* Ignore response of auth reply */
            (void) sd_ble_gatts_rw_authorize_reply(m_conn_handle, &auth_reply);
            return false;
        }
        else
        {
            auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
    
            err_code = sd_ble_gatts_rw_authorize_reply(m_conn_handle, &auth_reply);
            return err_code  == NRF_SUCCESS ? true : false;
        }
    }
    
    
    static void on_flash_write(void * p_buf)
    {
        NRF_LOG_DEBUG("Freeing buffer %p", p_buf);
        nrf_balloc_free(&m_buffer_pool, p_buf);
    }
    
    
    /**@brief   Function for handling the @ref BLE_GATTS_EVT_WRITE event from the SoftDevice.
     *
     * @param[in] p_dfu     DFU Service Structure.
     * @param[in] p_ble_evt Pointer to the event received from BLE stack.
     */
    static void on_write(ble_dfu_t * p_dfu, ble_evt_t const * p_ble_evt)
    {
        ble_gatts_evt_write_t const * const p_write_evt = &p_ble_evt->evt.gatts_evt.params.write;
    
        if (p_write_evt->handle != p_dfu->dfu_pkt_handles.value_handle)
        {
            return;
        }
    
        /* Allocate a buffer to receive data. */
        uint8_t * p_balloc_buf = nrf_balloc_alloc(&m_buffer_pool);
        if (p_balloc_buf == NULL)
        {
            /* Operations are retried by the host; do not give up here. */
            NRF_LOG_WARNING("cannot allocate memory buffer!");
            return;
        }
    
        NRF_LOG_DEBUG("Buffer %p acquired, len %d (%d)",
                      p_balloc_buf, p_write_evt->len, MAX_DFU_PKT_LEN);
    
        /* Copy payload into buffer. */
        memcpy(p_balloc_buf, p_write_evt->data, p_write_evt->len);
    
        /* Set up the request. */
        nrf_dfu_request_t request =
        {
            .request      = NRF_DFU_OP_OBJECT_WRITE,
            .p_context    = p_dfu,
            .callback     =
            {
                .response = ble_dfu_req_handler_callback,
                .write    = on_flash_write,
            }
        };
    
        /* Set up the request buffer. */
        request.write.p_data   = p_balloc_buf;
        request.write.len      = p_write_evt->len;
    
        /* Schedule handling of the request. */
        ret_code_t rc = nrf_dfu_req_handler_on_req(&request);
        if (rc != NRF_SUCCESS)
        {
            /* The error is logged in nrf_dfu_req_handler_on_req().
             * Free the buffer.
             */
            (void) nrf_balloc_free(&m_buffer_pool, p_balloc_buf);
        }
    }
    
    
    /**@brief Function for the Application's SoftDevice event handler.
     *
     * @param[in] p_ble_evt SoftDevice event.
     */
    static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
    {
        uint32_t                    err_code;
        ble_gap_evt_t const * const p_gap = &p_ble_evt->evt.gap_evt;
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
            {
                NRF_LOG_DEBUG("Connected");
    
                m_conn_handle = p_gap->conn_handle;
    
                if (m_observer)
                {
                    m_observer(NRF_DFU_EVT_TRANSPORT_ACTIVATED);
                }
    
                err_code = sd_ble_gap_conn_param_update(m_conn_handle, &m_gap_conn_params);
                if (err_code != NRF_SUCCESS)
                {
                    NRF_LOG_ERROR("Failure to update connection parameters: 0x%x", err_code);
                }
            } break;
    
            case BLE_GAP_EVT_DISCONNECTED:
            {
                m_conn_handle = BLE_CONN_HANDLE_INVALID;
    
                /* Restart advertising so that the DFU Controller can reconnect if possible. */
                if (!(m_flags & DFU_BLE_RESETTING_SOON))
                {
                    err_code = advertising_start();
                    APP_ERROR_CHECK(err_code);
                }
    
                if (m_observer)
                {
                    m_observer(NRF_DFU_EVT_TRANSPORT_DEACTIVATED);
                }
            } break;
    
            case BLE_GATTS_EVT_WRITE:
            {
                on_write(&m_dfu, p_ble_evt);
            } break;
    
            case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:
            {
                uint16_t const mtu_requested =
                    p_ble_evt->evt.gatts_evt.params.exchange_mtu_request.client_rx_mtu;
    
                /* If the requested MTU is smaller than the maximum, we can accept with the given
                 * stack configuration, and the payload is not word-aligned, reply with a smaller MTU
                 * that has a word-aligned payload. This ensures that the length of data we write to
                 * flash is a multiple of the word size.
                 */
                uint16_t mtu_reply;
    
                if (mtu_requested < NRF_SDH_BLE_GATT_MAX_MTU_SIZE)
                {
                    /* Round the payload size down to a multiple of 4 so it is word-aligned. */
                    if (GATT_PAYLOAD(mtu_requested) % 4)
                    {
                        mtu_reply = GATT_PAYLOAD(mtu_requested) - 4;
                        mtu_reply = ALIGN_NUM(4, mtu_reply);
                        /* Add the header len to the MTU. */
                        mtu_reply += GATT_HEADER_LEN;
                    }
                    else
                    {
                        mtu_reply = mtu_requested;
                    }
                }
                else
                {
                    mtu_reply = NRF_SDH_BLE_GATT_MAX_MTU_SIZE;
                }
    
                NRF_LOG_DEBUG("Received BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST (request: %d, reply: %d).",
                              mtu_requested, mtu_reply);
    
                err_code = sd_ble_gatts_exchange_mtu_reply(m_conn_handle, mtu_reply);
                APP_ERROR_CHECK(err_code);
            } break;
    #ifndef S112
            case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST:
            {
                NRF_LOG_DEBUG("Received BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST.");
    
                ble_gap_data_length_params_t const dlp =
                {
                    .max_rx_octets = BLE_GAP_DATA_LENGTH_AUTO,
                    .max_tx_octets = BLE_GAP_DATA_LENGTH_AUTO,
                };
    
                err_code = sd_ble_gap_data_length_update(p_ble_evt->evt.gatts_evt.conn_handle,
                                                         &dlp, NULL);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GAP_EVT_DATA_LENGTH_UPDATE:
            {
                NRF_LOG_DEBUG("Received BLE_GAP_EVT_DATA_LENGTH_UPDATE (%u, max_rx_time %u).",
                              p_gap->params.data_length_update.effective_params.max_rx_octets,
                              p_gap->params.data_length_update.effective_params.max_rx_time_us);
            } break;
    #endif
    
            case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
            {
                NRF_LOG_DEBUG("Received BLE_GAP_EVT_SEC_PARAMS_REQUEST");
    
                uint16_t cccd;
                ble_gatts_value_t gatts_value =
                {
                    .len     = BLE_CCCD_VALUE_LEN,
                    .p_value = (uint8_t*)&cccd
                };
    
                err_code = sd_ble_gatts_value_get(m_conn_handle,
                                                  BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED,
                                                  &gatts_value);
                APP_ERROR_CHECK(err_code);
    
                NRF_LOG_DEBUG("CCCD for service changed is 0x%04x", cccd);
    
                err_code = sd_ble_gap_sec_params_reply(m_conn_handle,
                                                       BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP,
                                                       NULL,
                                                       NULL);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GAP_EVT_CONN_PARAM_UPDATE:
            {
                NRF_LOG_DEBUG("Received BLE_GAP_EVT_CONN_PARAM_UPDATE");
    
                ble_gap_conn_params_t const * p_conn =
                    &p_gap->params.conn_param_update.conn_params;
    
                NRF_LOG_DEBUG("max_conn_interval: %d", p_conn->max_conn_interval);
                NRF_LOG_DEBUG("min_conn_interval: %d", p_conn->min_conn_interval);
                NRF_LOG_DEBUG("slave_latency: %d",     p_conn->slave_latency);
                NRF_LOG_DEBUG("conn_sup_timeout: %d",  p_conn->conn_sup_timeout);
            } break;
    
    #ifndef S112
            case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
            {
                NRF_LOG_DEBUG("Received BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST");
    
                err_code = sd_ble_gap_conn_param_update(m_conn_handle,
                    &p_gap->params.conn_param_update_request.conn_params);
    
                if (err_code != NRF_SUCCESS)
                {
                    NRF_LOG_ERROR("Failure to update connection parameter request: 0x%x", err_code);
                }
    
                APP_ERROR_CHECK(err_code);
            } break;
    #endif
    
            case BLE_GAP_EVT_PHY_UPDATE:
            {
                NRF_LOG_DEBUG("Received BLE_GAP_EVT_PHY_UPDATE (RX:%d, TX:%d, status:%d)",
                              p_gap->params.phy_update.rx_phy,
                              p_gap->params.phy_update.tx_phy,
                              p_gap->params.phy_update.status);
                break;
            }
    
            case BLE_GAP_EVT_PHY_UPDATE_REQUEST:
            {
                NRF_LOG_DEBUG("Received BLE_GAP_EVT_PHY_UPDATE_REQUEST.");
    
                ble_gap_phys_t const phys =
                {
                    .rx_phys = BLE_GAP_PHY_AUTO,
                    .tx_phys = BLE_GAP_PHY_AUTO,
                };
    
                err_code = sd_ble_gap_phy_update(p_gap->conn_handle, &phys);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GATTS_EVT_TIMEOUT:
            {
                if (p_ble_evt->evt.gatts_evt.params.timeout.src == BLE_GATT_TIMEOUT_SRC_PROTOCOL)
                {
                    err_code = sd_ble_gap_disconnect(m_conn_handle,
                                                     BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                    APP_ERROR_CHECK(err_code);
                }
            } break;
    
            case BLE_EVT_USER_MEM_REQUEST:
            {
                err_code = sd_ble_user_mem_reply(m_conn_handle, NULL);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
            {
                if (p_ble_evt->evt.gatts_evt.params.authorize_request.type
                    != BLE_GATTS_AUTHORIZE_TYPE_INVALID)
                {
                    if (on_rw_authorize_req(&m_dfu, p_ble_evt))
                    {
                        err_code = on_ctrl_pt_write(&m_dfu,
                               &(p_ble_evt->evt.gatts_evt.params.authorize_request.request.write));
    
                        if (err_code != NRF_SUCCESS)
                        {
                            NRF_LOG_ERROR("Could not handle on_ctrl_pt_write. err_code: 0x%04x", err_code);
                        }
                    }
                }
            } break;
    
            case BLE_GAP_EVT_SEC_INFO_REQUEST:
            {
                NRF_LOG_DEBUG("Received BLE_GAP_EVT_SEC_INFO_REQUEST");
    
                ble_gap_enc_info_t * p_enc_info = NULL;
                ble_gap_irk_t      * p_id_info  = NULL;
    
                #if (NRF_DFU_BLE_REQUIRES_BONDS)
                    /* If there is a match in diversifier, then set the correct keys. */
                    if (p_gap->params.sec_info_request.master_id.ediv ==
                        m_peer_data.enc_key.master_id.ediv)
                    {
                        p_enc_info = &m_peer_data.enc_key.enc_info;
                    }
                    p_id_info = &m_peer_data.ble_id.id_info;
                #endif
    
                err_code = sd_ble_gap_sec_info_reply(p_gap->conn_handle, p_enc_info, p_id_info, NULL);
                APP_ERROR_CHECK(err_code);
            } break;
    
            case BLE_GAP_EVT_CONN_SEC_UPDATE:
            case BLE_GATTS_EVT_SYS_ATTR_MISSING:
            {
                #if (NRF_DFU_BLE_REQUIRES_BONDS)
                    err_code = service_changed_send();
                #else
                    err_code = sd_ble_gatts_sys_attr_set(p_gap->conn_handle, NULL, 0, 0);
                #endif
                APP_ERROR_CHECK(err_code);
                NRF_LOG_DEBUG("Finished handling conn sec update");
            } break;
    
            default:
                /* No implementation needed. */
                break;
        }
    }
    
    
    #if (!NRF_DFU_BLE_REQUIRES_BONDS)
    static uint32_t gap_address_change(void)
    {
        uint32_t       err_code;
        ble_gap_addr_t addr;
    
        err_code = sd_ble_gap_addr_get(&addr);
        VERIFY_SUCCESS(err_code);
    
        /* Increase the BLE address by one when advertising openly. */
        addr.addr[0] += 1;
    
        err_code = sd_ble_gap_addr_set(&addr);
        VERIFY_SUCCESS(err_code);
    
        return NRF_SUCCESS;
    }
    #endif
    
    
    /**@brief     Function for initializing GAP.
     *
     * @details   This function sets up all necessary GAP (Generic Access Profile) parameters of
     *            the device. It also sets the permissions and appearance.
     */
    static uint32_t gap_params_init(void)
    {
        uint32_t                err_code;
        ble_gap_conn_sec_mode_t sec_mode;
        uint8_t const *         device_name;
        uint32_t                name_len;
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
    
    #if (!NRF_DFU_BLE_REQUIRES_BONDS)
    
        err_code = gap_address_change();
        VERIFY_SUCCESS(err_code);
    
        if ((m_flags & DFU_BLE_FLAG_USE_ADV_NAME) != 0)
        {
            NRF_LOG_DEBUG("Setting adv name: %s, length: %d", m_adv_name.name, m_adv_name.len);
            device_name = m_adv_name.name;
            name_len    = m_adv_name.len;
        }
        else
    #endif
        {
            NRF_LOG_DEBUG("Using default advertising name");
            device_name = (uint8_t const *)(NRF_DFU_BLE_ADV_NAME);
            name_len    = strlen(NRF_DFU_BLE_ADV_NAME);
        }
    
        err_code = sd_ble_gap_device_name_set(&sec_mode, device_name, name_len);
        VERIFY_SUCCESS(err_code);
    
        err_code = sd_ble_gap_ppcp_set(&m_gap_conn_params);
        return err_code;
    }
    
    
    static uint32_t ble_stack_init()
    {
        ret_code_t err_code;
        uint32_t   ram_start = 0;
    
        /* Register as a BLE event observer to receive BLE events. */
        NRF_SDH_BLE_OBSERVER(m_ble_evt_observer, BLE_OBSERVER_PRIO, ble_evt_handler, NULL);
    
    #if (!defined(NRF_DFU_BLE_SKIP_SD_INIT)) || (NRF_DFU_BLE_SKIP_SD_INIT == 0)
        err_code = nrf_dfu_mbr_init_sd();
        VERIFY_SUCCESS(err_code);
    
        NRF_LOG_DEBUG("Setting up vector table: 0x%08x", BOOTLOADER_START_ADDR);
        err_code = sd_softdevice_vector_table_base_set(BOOTLOADER_START_ADDR);
        VERIFY_SUCCESS(err_code);
    #endif
    
        NRF_LOG_DEBUG("Enabling SoftDevice.");
        err_code = nrf_sdh_enable_request();
        VERIFY_SUCCESS(err_code);
    
        /* Fetch the start address of the application RAM. */
        err_code = nrf_sdh_ble_app_ram_start_get(&ram_start);
        VERIFY_SUCCESS(err_code);
    
        NRF_LOG_DEBUG("Configuring BLE stack.");
        err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start);
        VERIFY_SUCCESS(err_code);
    
        /* Enable the BLE stack. */
        NRF_LOG_DEBUG("Enabling the BLE stack.");
        return nrf_sdh_ble_enable(&ram_start);
    }
    
    
    /**@brief       Function for adding DFU Packet characteristic to the BLE Stack.
     *
     * @param[in]   p_dfu DFU Service structure.
     *
     * @return      NRF_SUCCESS on success. Otherwise an error code.
     */
    static uint32_t dfu_pkt_char_add(ble_dfu_t * const p_dfu)
    {
        ble_gatts_char_md_t char_md =
        {
            .char_props.write_wo_resp = 1,
        };
    
        ble_uuid_t char_uuid =
        {
            .type = p_dfu->uuid_type,
            .uuid = BLE_DFU_PKT_CHAR_UUID,
        };
    
        ble_gatts_attr_md_t attr_md =
        {
            .vloc = BLE_GATTS_VLOC_STACK,
            .vlen = 1,
            .write_perm =
            {
                .sm = 1,
            #if NRF_DFU_BLE_REQUIRES_BONDS
                .lv = 2,
            #else
                .lv = 1,
            #endif
            }
        };
    
        ble_gatts_attr_t attr_char_value =
        {
            .p_uuid    = &char_uuid,
            .p_attr_md = &attr_md,
            .max_len   = MAX_DFU_PKT_LEN,
        };
    
        return sd_ble_gatts_characteristic_add(p_dfu->service_handle,
                                               &char_md,
                                               &attr_char_value,
                                               &p_dfu->dfu_pkt_handles);
    }
    
    
    /**@brief       Function for adding DFU Control Point characteristic to the BLE Stack.
     *
     * @param[in]   p_dfu DFU Service structure.
     *
     * @return      NRF_SUCCESS on success. Otherwise an error code.
     */
    static uint32_t dfu_ctrl_pt_add(ble_dfu_t * const p_dfu)
    {
        ble_gatts_char_md_t char_md =
        {
            .char_props.write  = 1,
            .char_props.notify = 1,
        };
    
        ble_uuid_t char_uuid =
        {
            .type = p_dfu->uuid_type,
            .uuid = BLE_DFU_CTRL_PT_UUID,
        };
    
        ble_gatts_attr_md_t attr_md =
        {
            .vloc    = BLE_GATTS_VLOC_STACK,
            .wr_auth = 1,
            .vlen    = 1,
            .write_perm =
            {
                .sm = 1,
            #if NRF_DFU_BLE_REQUIRES_BONDS
                .lv = 2,
            #else
                .lv = 1,
            #endif
            },
        };
    
        ble_gatts_attr_t attr_char_value =
        {
            .p_uuid    = &char_uuid,
            .p_attr_md = &attr_md,
            .max_len   = BLE_GATT_ATT_MTU_DEFAULT,
        };
    
        return sd_ble_gatts_characteristic_add(p_dfu->service_handle,
                                               &char_md,
                                               &attr_char_value,
                                               &p_dfu->dfu_ctrl_pt_handles);
    }
    
    
    /**@brief     Function for checking if the CCCD of DFU Control point is configured for Notification.
     *
     * @details   This function checks if the CCCD of DFU Control Point characteristic is configured
     *            for Notification by the DFU Controller.
     *
     * @param[in] p_dfu DFU Service structure.
     *
     * @return    True if the CCCD of DFU Control Point characteristic is configured for Notification.
     *            False otherwise.
     */
    uint32_t ble_dfu_init(ble_dfu_t * p_dfu)
    {
        ASSERT(p_dfu != NULL);
    
        ble_uuid_t service_uuid;
        uint32_t   err_code;
    
        m_conn_handle = BLE_CONN_HANDLE_INVALID;
    
        BLE_UUID_BLE_ASSIGN(service_uuid, BLE_DFU_SERVICE_UUID);
    
        err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
                                            &service_uuid,
                                            &(p_dfu->service_handle));
        VERIFY_SUCCESS(err_code);
    
        ble_uuid128_t const base_uuid128 =
        {
            {
                0x50, 0xEA, 0xDA, 0x30, 0x88, 0x83, 0xB8, 0x9F,
                0x60, 0x4F, 0x15, 0xF3,  0x00, 0x00, 0xC9, 0x8E
            }
        };
    
        err_code = sd_ble_uuid_vs_add(&base_uuid128, &p_dfu->uuid_type);
        VERIFY_SUCCESS(err_code);
    
        err_code = dfu_pkt_char_add(p_dfu);
        VERIFY_SUCCESS(err_code);
    
        err_code = dfu_ctrl_pt_add(p_dfu);
        VERIFY_SUCCESS(err_code);
    
        return NRF_SUCCESS;
    }
    
    
    uint32_t ble_dfu_transport_init(nrf_dfu_observer_t observer)
    {
        uint32_t err_code = NRF_SUCCESS;
    
        if (m_flags & DFU_BLE_FLAG_INITIALIZED)
        {
            return err_code;
        }
    
        NRF_LOG_DEBUG("Initializing BLE DFU transport");
    
        m_observer = observer;
    
        err_code = nrf_balloc_init(&m_buffer_pool);
        UNUSED_RETURN_VALUE(err_code);
    
        err_code = ble_stack_init();
        VERIFY_SUCCESS(err_code);
    
    #if (NRF_DFU_BLE_REQUIRES_BONDS)
        /* Copy out the peer data if bonds are required */
        if (nrf_dfu_settings_peer_data_is_valid())
        {
            NRF_LOG_DEBUG("Copying peer data");
    
            err_code = nrf_dfu_settings_peer_data_copy(&m_peer_data);
            UNUSED_RETURN_VALUE(err_code);
        }
        else
        {
            APP_ERROR_HANDLER(NRF_ERROR_INTERNAL);
        }
    #else
        /* Copy out the new advertisement name when bonds are not required and the name is set. */
        if (nrf_dfu_settings_adv_name_is_valid())
        {
            err_code = nrf_dfu_settings_adv_name_copy(&m_adv_name);
            UNUSED_RETURN_VALUE(err_code);
    
            /* Set flags for advertisement name that is to be used */
            m_flags |= DFU_BLE_FLAG_USE_ADV_NAME;
        }
        else
        {
            NRF_LOG_DEBUG("No advertising name found");
        }
    #endif
    
        err_code = gap_params_init();
        VERIFY_SUCCESS(err_code);
    
        /* Initialize the Device Firmware Update Service. */
        err_code = ble_dfu_init(&m_dfu);
        VERIFY_SUCCESS(err_code);
    
        err_code = advertising_start();
        VERIFY_SUCCESS(err_code);
    
        m_flags |= DFU_BLE_FLAG_INITIALIZED;
    
        NRF_LOG_DEBUG("BLE DFU transport initialized.");
    
        return NRF_SUCCESS;
    }
    
    
    uint32_t ble_dfu_transport_close(nrf_dfu_transport_t const * p_exception)
    {
        uint32_t err_code = NRF_SUCCESS;
    
        if ((m_flags & DFU_BLE_FLAG_INITIALIZED) && (p_exception != &ble_dfu_transport))
        {
            NRF_LOG_DEBUG("Shutting down BLE transport.");
    
            if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
            {
                NRF_LOG_DEBUG("Disconnecting.");
    
                /* Set flag to prevent advertisement from starting */
                m_flags |= DFU_BLE_RESETTING_SOON;
    
                /* Disconnect from the peer. */
                err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                VERIFY_SUCCESS(err_code);
    
                /* Wait a bit for the disconnect event to be sent on air. */
                nrf_delay_ms(200);
            }
            else
            {
                err_code = sd_ble_gap_adv_stop(m_adv_handle);
                UNUSED_RETURN_VALUE(err_code);
            }
    
            err_code = nrf_sdh_disable_request();
            if (err_code == NRF_SUCCESS)
            {
                NRF_LOG_DEBUG("BLE transport shut down.");
            }
        }
    
        return err_code;
    }
    
    uint32_t ble_dfu_transport_disconnect(void)
    {
        uint32_t err_code = NRF_SUCCESS;
    
        if (m_flags & DFU_BLE_FLAG_INITIALIZED)
        {
            NRF_LOG_DEBUG("Disconnect from BLE peer.");
    
            if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
            {
                NRF_LOG_DEBUG("Disconnecting.");
    
                /* Disconnect from the peer. */
                err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
                VERIFY_SUCCESS(err_code);
            }
        }
    
        return err_code;
    }
    


    After you test with 9600kbps, you can try to test with higher baudrate (make sure you update UART_DEFAULT_CONFIG_BAUDRATE in sdkconfig.h with the correct baudrate)

  • Well... It looks like everything is normal. On Monday, I will specifically test how much baud rate can stabilize DFU when HWFC is turned off.

Related