aboutsummaryrefslogtreecommitdiff
path: root/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2018-08-23 17:08:59 +0200
committerTrygve Laugstøl <trygvis@inamo.no>2018-08-23 17:12:21 +0200
commit3061ecca3d0fdfb87dabbf5f63c9e06c2a30f53a (patch)
treeab49cc16ed0b853452c5c2ed2d3042416d628986 /thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu
downloadiot-sensors-master.tar.gz
iot-sensors-master.tar.bz2
iot-sensors-master.tar.xz
iot-sensors-master.zip
o Initial import.HEADmaster
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu')
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.c456
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.h197
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.c141
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.h117
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.c835
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.h216
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/background_dfu_transport.h91
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.c928
-rw-r--r--thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.h80
9 files changed, 3061 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.c
new file mode 100644
index 0000000..8b08068
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.c
@@ -0,0 +1,456 @@
+/**
+ * Copyright (c) 2017 - 2018, 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.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup background_dfu_block background_dfu_block.c
+ * @{
+ * @ingroup background_dfu
+ * @brief Background DFU block handling implementation.
+ *
+ */
+
+#include "background_dfu_block.h"
+
+#include <assert.h>
+
+#include "sdk_config.h"
+#include "app_scheduler.h"
+#include "background_dfu_operation.h"
+#include "compiler_abstraction.h"
+#include "nrf_dfu_handling_error.h"
+
+#define NRF_LOG_MODULE_NAME background_dfu
+
+#define NRF_LOG_LEVEL BACKGROUND_DFU_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR BACKGROUND_DFU_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR BACKGROUND_DFU_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+
+#define BITMAP_BYTE_FROM_INDEX(index) ((index) / 8)
+#define BITMAP_BIT_FROM_INDEX(index) (7 - ((index) % 8))
+
+static void block_buffer_store(background_dfu_block_manager_t * p_bm);
+
+/**@brief Convert block number to bitmap index.
+ *
+ * @param[in] block_num Block number.
+ *
+ * @return Corresponding index.
+ */
+static __INLINE uint16_t block_num_to_index(uint32_t block_num)
+{
+ return block_num % BLOCKS_PER_BUFFER;
+}
+
+/**@brief Set a bit in a bitmap.
+ *
+ * @param[inout] p_bitmap A pointer to the bitmap.
+ * @param[in] index Bit index to set.
+ */
+static __INLINE void set_bitmap_bit(uint8_t * p_bitmap, uint16_t index)
+{
+ p_bitmap[BITMAP_BYTE_FROM_INDEX(index)] |= (0x01 << BITMAP_BIT_FROM_INDEX(index));
+}
+
+/**@brief Clear a bit in a bitmap.
+ *
+ * @param[inout] p_bitmap A pointer to the bitmap.
+ * @param[in] index Bit index to clear.
+ */
+static __INLINE void clear_bitmap_bit(uint8_t * p_bitmap, uint16_t index)
+{
+ p_bitmap[BITMAP_BYTE_FROM_INDEX(index)] &= ~((uint8_t)(0x01 << BITMAP_BIT_FROM_INDEX(index)));
+}
+
+/**@brief Check if a bit in a bitmap is set.
+ *
+ * @param[inout] p_bitmap A pointer to the bitmap.
+ * @param[in] index Bit index to check.
+ *
+ * @return True if bit is set, false otherwise.
+ */
+static __INLINE bool is_block_present(const uint8_t * p_bitmap, uint16_t index)
+{
+ return (p_bitmap[BITMAP_BYTE_FROM_INDEX(index)] >> BITMAP_BIT_FROM_INDEX(index)) & 0x01;
+}
+
+/**
+ * @brief A callback function for DFU operation.
+ */
+static void dfu_operation_callback(nrf_dfu_response_t * p_res, void * p_context)
+{
+ background_dfu_block_manager_t * p_bm = (background_dfu_block_manager_t *)p_context;
+ ret_code_t res_code;
+
+ if (p_res->result != NRF_DFU_RES_CODE_SUCCESS)
+ {
+ p_bm->result_handler(BACKGROUND_DFU_BLOCK_STORE_ERROR, p_bm->p_context);
+ }
+ else
+ {
+ switch (p_res->request)
+ {
+ case NRF_DFU_OP_OBJECT_CREATE:
+ {
+ // Object created, write respective block.
+ uint32_t current_size = p_bm->currently_stored_block * DEFAULT_BLOCK_SIZE;
+ uint16_t data_offset = block_num_to_index(p_bm->currently_stored_block) * DEFAULT_BLOCK_SIZE;
+ uint16_t store_size = MIN(DEFAULT_BLOCK_SIZE, (p_bm->image_size - current_size));
+ res_code = background_dfu_op_write(p_bm->data + data_offset,
+ store_size,
+ dfu_operation_callback,
+ p_bm);
+
+ if (res_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Failed to store block (b:%d c:%d).",
+ p_bm->currently_stored_block,
+ p_bm->current_block);
+ p_bm->result_handler(BACKGROUND_DFU_BLOCK_STORE_ERROR, p_bm->p_context);
+ }
+
+ break;
+ }
+
+ case NRF_DFU_OP_OBJECT_WRITE:
+ if (!((p_bm->currently_stored_block + 1) % BLOCKS_PER_DFU_OBJECT) ||
+ ((p_bm->currently_stored_block + 1) == BLOCKS_PER_SIZE(p_bm->image_size)))
+ {
+ res_code = background_dfu_op_crc(dfu_operation_callback, p_bm);
+
+ if (res_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Failed to store block (b:%d c:%d).",
+ p_bm->currently_stored_block,
+ p_bm->current_block);
+ p_bm->result_handler(BACKGROUND_DFU_BLOCK_STORE_ERROR, p_bm->p_context);
+ }
+ }
+ else
+ {
+ p_bm->last_block_stored = p_bm->currently_stored_block;
+ clear_bitmap_bit(p_bm->bitmap, block_num_to_index(p_bm->currently_stored_block));
+ p_bm->currently_stored_block = INVALID_BLOCK_NUMBER;
+
+ p_bm->result_handler(BACKGROUND_DFU_BLOCK_SUCCESS, p_bm->p_context);
+
+ block_buffer_store(p_bm);
+ }
+
+ break;
+
+ case NRF_DFU_OP_CRC_GET:
+ res_code = background_dfu_op_execute(dfu_operation_callback, p_bm);
+
+ if (res_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Failed to store block (b:%d c:%d).",
+ p_bm->currently_stored_block,
+ p_bm->current_block);
+ p_bm->result_handler(BACKGROUND_DFU_BLOCK_STORE_ERROR, p_bm->p_context);
+ }
+
+ break;
+
+ case NRF_DFU_OP_OBJECT_EXECUTE:
+ p_bm->last_block_stored = p_bm->currently_stored_block;
+ clear_bitmap_bit(p_bm->bitmap, block_num_to_index(p_bm->currently_stored_block));
+ p_bm->currently_stored_block = INVALID_BLOCK_NUMBER;
+
+ p_bm->result_handler(BACKGROUND_DFU_BLOCK_SUCCESS, p_bm->p_context);
+
+ block_buffer_store(p_bm);
+
+ break;
+
+ default:
+ ASSERT(false);
+ }
+ }
+}
+
+/**@brief Store a block from the buffer in a flash.
+ *
+ * @param[inout] p_bm A pointer to the block manager.
+ * @param[in] p_block A block number to store.
+ *
+ * @return NRF_SUCCESS on success, an error code is returned otherwise.
+ */
+static ret_code_t block_store(background_dfu_block_manager_t * p_bm, uint32_t block_num)
+{
+ p_bm->currently_stored_block = block_num;
+
+ ret_code_t res_code = NRF_SUCCESS;
+ uint32_t current_size = block_num * DEFAULT_BLOCK_SIZE;
+
+ do
+ {
+ // Initialize DFU object if needed.
+ if (!(block_num % BLOCKS_PER_DFU_OBJECT))
+ {
+ uint32_t object_size = MIN(DEFAULT_DFU_OBJECT_SIZE, (p_bm->image_size - current_size));
+
+ res_code = background_dfu_op_create(p_bm->image_type,
+ object_size,
+ dfu_operation_callback,
+ p_bm);
+ break;
+ }
+
+ // Store block.
+ uint16_t data_offset = block_num_to_index(block_num) * DEFAULT_BLOCK_SIZE;
+ uint16_t store_size = MIN(DEFAULT_BLOCK_SIZE, (p_bm->image_size - current_size));
+ res_code = background_dfu_op_write(p_bm->data + data_offset,
+ store_size,
+ dfu_operation_callback,
+ p_bm);
+
+ } while (0);
+ return res_code;
+}
+
+/**@brief Check if block manager is busy storing a block.
+ *
+ * @param[inout] p_bm A pointer to the block manager.
+ *
+ */
+static bool is_block_manager_busy(background_dfu_block_manager_t * p_bm)
+{
+ return p_bm->currently_stored_block >= 0;
+}
+
+/**@brief Store any valid blocks from the buffer in a flash.
+ *
+ * @param[inout] p_bm A pointer to the block manager.
+ *
+ */
+static void block_buffer_store(background_dfu_block_manager_t * p_bm)
+{
+ ret_code_t res_code = NRF_SUCCESS;
+
+ if (!is_block_manager_busy(p_bm))
+ {
+ if (p_bm->last_block_stored < p_bm->current_block)
+ {
+ int32_t block = p_bm->last_block_stored + 1;
+
+ if (is_block_present(p_bm->bitmap, block_num_to_index(block)))
+ {
+ NRF_LOG_INFO("Storing block (b:%d c:%d).", block, p_bm->current_block);
+
+ // There is a block to store.
+ res_code = block_store(p_bm, block);
+ if (res_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Failed to store block (b:%d c:%d).", block, p_bm->current_block);
+ p_bm->result_handler(BACKGROUND_DFU_BLOCK_STORE_ERROR, p_bm->p_context);
+ }
+ }
+ else
+ {
+ NRF_LOG_WARNING("Gap encountered - quit (b:%d c:%d).", block, p_bm->current_block);
+ }
+ }
+ }
+}
+
+/**
+ * @brief A callback function for scheduling DFU block operations.
+ */
+static void block_store_scheduled(void * p_evt, uint16_t event_length)
+{
+ UNUSED_PARAMETER(event_length);
+
+ background_dfu_block_manager_t * p_bm = *((background_dfu_block_manager_t **)p_evt);
+ block_buffer_store(p_bm);
+}
+
+/**@brief Copy block data to the buffer.
+ *
+ * @param[inout] p_bm A pointer to the block manager.
+ * @param[in] p_block A pointer to the block.
+ */
+static void block_buffer_add(background_dfu_block_manager_t * p_bm,
+ const background_dfu_block_t * p_block)
+{
+ uint16_t index = block_num_to_index(p_block->number);
+
+ memcpy(p_bm->data + index * DEFAULT_BLOCK_SIZE, p_block->p_payload, DEFAULT_BLOCK_SIZE);
+ set_bitmap_bit(p_bm->bitmap, index);
+
+ if (p_bm->current_block < (int32_t)p_block->number)
+ {
+ p_bm->current_block = (int32_t)p_block->number;
+ }
+
+ // Schedule block store.
+ UNUSED_RETURN_VALUE(app_sched_event_put(&p_bm, sizeof(p_bm), block_store_scheduled));
+}
+
+/***************************************************************************************************
+ * @section Public
+ **************************************************************************************************/
+
+void block_manager_init(background_dfu_block_manager_t * p_bm,
+ uint32_t object_type,
+ uint32_t object_size,
+ int32_t initial_block,
+ block_manager_result_notify_t result_handler,
+ void * p_context)
+{
+ p_bm->image_type = object_type;
+ p_bm->image_size = object_size;
+ p_bm->last_block_stored = p_bm->current_block = initial_block - 1;
+ p_bm->result_handler = result_handler;
+ p_bm->p_context = p_context;
+ p_bm->currently_stored_block = INVALID_BLOCK_NUMBER;
+
+ memset(p_bm->bitmap, 0, sizeof(p_bm->bitmap));
+}
+
+background_dfu_block_result_t block_manager_block_process(background_dfu_block_manager_t * p_bm,
+ const background_dfu_block_t * p_block)
+{
+ /*
+ * Possible scenarios:
+ * 1) We receive a block older than our last stored block - simply ignore it.
+ * 2) We receive a block that fits within current buffer range - process it.
+ * 3) We receive a block that exceeds current buffer range - abort DFU as we won't be able to catch-up.
+ */
+
+ if (p_block->size != DEFAULT_BLOCK_SIZE)
+ {
+ NRF_LOG_WARNING("Block with incorrect size received (s:%d n:%d).",
+ p_block->size, p_block->number);
+ return BACKGROUND_DFU_BLOCK_IGNORE;
+ }
+
+ if ((int32_t)p_block->number <= p_bm->last_block_stored)
+ {
+ NRF_LOG_WARNING("Ignoring block that already was stored(o:%d n:%d).",
+ p_bm->last_block_stored, p_block->number);
+ return BACKGROUND_DFU_BLOCK_IGNORE;
+ }
+
+ if ((int32_t)p_block->number > p_bm->last_block_stored + BLOCKS_PER_BUFFER)
+ {
+ NRF_LOG_WARNING("Too many blocks missed - abort DFU (o:%d n:%d).",
+ p_bm->last_block_stored, p_block->number);
+ return BACKGROUND_DFU_BLOCK_INVALID;
+ }
+
+ // Block fits within current buffer - copy it into the buffer and update the current block if most
+ // recent block was received.
+ block_buffer_add(p_bm, p_block);
+
+ return BACKGROUND_DFU_BLOCK_SUCCESS;
+}
+
+bool block_manager_is_image_complete(const background_dfu_block_manager_t * p_bm)
+{
+ uint32_t image_blocks = BLOCKS_PER_SIZE(p_bm->image_size);
+
+ NRF_LOG_DEBUG("Is image complete (o:%d n:%d).", p_bm->last_block_stored, image_blocks);
+
+ if (p_bm->last_block_stored + 1 == image_blocks)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool block_manager_request_bitmap_get(const background_dfu_block_manager_t * p_bm,
+ background_dfu_request_bitmap_t * p_req_bmp)
+{
+ if (p_bm->current_block > p_bm->last_block_stored)
+ {
+ memset(p_req_bmp, 0, sizeof(*p_req_bmp));
+ p_req_bmp->offset = p_bm->last_block_stored + 1;
+ p_req_bmp->size = (p_bm->current_block - p_bm->last_block_stored + 7) / 8;
+
+ for (uint16_t block = p_req_bmp->offset; block <= p_bm->current_block; block++)
+ {
+ if (!is_block_present(p_bm->bitmap, block_num_to_index(block)))
+ {
+ set_bitmap_bit(p_req_bmp->bitmap, block - p_req_bmp->offset);
+ }
+ }
+
+ // Clip empty bytes at the end.
+ while ((p_req_bmp->size > 0) && (p_req_bmp->bitmap[p_req_bmp->size - 1] == 0))
+ {
+ p_req_bmp->size--;
+ }
+
+ if (p_req_bmp->size == 0)
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+bool block_manager_increment_current_block(background_dfu_block_manager_t * p_bm)
+{
+ uint32_t image_blocks = BLOCKS_PER_SIZE(p_bm->image_size);
+
+ if (p_bm->current_block + 1 == image_blocks)
+ {
+ // Already on last block.
+ return false;
+ }
+ else
+ {
+ p_bm->current_block++;
+ }
+
+ return true;
+}
+
+int32_t block_manager_get_current_block(const background_dfu_block_manager_t * p_bm)
+{
+ return p_bm->current_block;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.h
new file mode 100644
index 0000000..e1e468b
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_block.h
@@ -0,0 +1,197 @@
+/**
+ * Copyright (c) 2017 - 2018, 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.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup background_dfu_block background_dfu_block.H
+ * @{
+ * @ingroup background_dfu
+ * @brief Background DFU block handling.
+ *
+ */
+
+#ifndef BACKGROUND_DFU_BLOCK_H_
+#define BACKGROUND_DFU_BLOCK_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "app_util_platform.h"
+#include "sdk_config.h"
+
+/** @brief Macro for calculating the number of blocks that fits in particular size. */
+#define BLOCKS_PER_SIZE(SIZE) ((SIZE + DEFAULT_BLOCK_SIZE - 1) / DEFAULT_BLOCK_SIZE)
+
+/** @brief Default block size for background DFU blocks. */
+#define DEFAULT_BLOCK_SIZE BACKGROUND_DFU_DEFAULT_BLOCK_SIZE
+
+/** @brief Number of blocks in superblock. */
+#define BLOCKS_PER_BUFFER BACKGROUND_DFU_BLOCKS_PER_BUFFER
+
+/** @brief Size of the block buffer. Shall be a multiply of @ref DEFAULT_BLOCK_SIZE. */
+#define BLOCK_BUFFER_SIZE (BLOCKS_PER_BUFFER * DEFAULT_BLOCK_SIZE)
+
+/** @brief Size of the bitmap reflecting the state of the blocks in a superblock. */
+#define BITMAP_SIZE ((BLOCKS_PER_BUFFER + 7) / 8)
+
+/** @brief Default size of DFU object. Shall be a multiply of @ref DEFAULT_BLOCK_SIZE. */
+#define DEFAULT_DFU_OBJECT_SIZE 4096
+
+/** @brief Number of blocks in DFU object. */
+#define BLOCKS_PER_DFU_OBJECT (BLOCKS_PER_SIZE(DEFAULT_DFU_OBJECT_SIZE))
+
+/** @brief Value of invalid block number (for example to indicate that no block is being stored). */
+#define INVALID_BLOCK_NUMBER (-1)
+
+/** @brief Result of a DFU block operation. */
+typedef enum
+{
+ BACKGROUND_DFU_BLOCK_SUCCESS, /**< Block operation completed successfully. */
+ BACKGROUND_DFU_BLOCK_IGNORE, /**< Block was ignored in current DFU context (i.e. duplicated block). */
+ BACKGROUND_DFU_BLOCK_INVALID, /**< Block is invalid in current context, indicates that DFU shall be aborted. */
+ BACKGROUND_DFU_BLOCK_STORE_ERROR /**< Block was not stored due to internal store error. */
+} background_dfu_block_result_t;
+
+/**@brief A function that module can register to receive block manager error notifications. */
+typedef void (* block_manager_result_notify_t)(background_dfu_block_result_t result,
+ void * p_context);
+
+/**@brief Block information structure. */
+typedef struct
+{
+ uint16_t size; /**< Size of the block in bytes. */
+ uint32_t number; /**< Block number. */
+ uint8_t * p_payload; /**< Block payload. */
+} background_dfu_block_t;
+
+/**@brief Block manager structure.
+ *
+ * Block manager keeps track of received blocks, ensuring that they are written into flash in
+ * a correct order, and updates the missing blocks bitmap, so that they could be requested from
+ * the server.
+ */
+typedef struct
+{
+ uint32_t image_size; /**< Size of currently stored image. */
+ uint32_t image_type; /**< Image type (init command or firmware). */
+ int32_t last_block_stored; /**< Number of the last block written in the flash. */
+ int32_t current_block; /**< Last received (or expected) block. */
+ uint8_t data[BLOCK_BUFFER_SIZE]; /**< Block buffer. */
+ uint8_t bitmap[BITMAP_SIZE]; /**< A bitmap indicating which blocks have been received. */
+ block_manager_result_notify_t result_handler; /**< A callback function for error notification. */
+ void * p_context; /**< A context for result notification.*/
+ int32_t currently_stored_block; /**< Number of block that is currently being stored. */
+} background_dfu_block_manager_t;
+
+/**@brief Bitmap structure used in bitmap requests. */
+typedef struct
+{
+ uint16_t size; /**< Size of the bitmap, in bytes.*/
+ uint16_t offset; /**< Bitmap offset, indicating which block is referenced by first bit in bitmap. */
+ uint8_t bitmap[BITMAP_SIZE]; /**< Bitmap itself. One in specific bit indicates which block is missing. */
+} background_dfu_request_bitmap_t;
+
+/**@brief Initialize block manager.
+ *
+ * @param[inout] p_bm A pointer to the block manager.
+ * @param[in] object_type Type of the image to store.
+ * @param[in] object_size Size of the image to store.
+ * @param[in] initial_block Number of the first block to receive. Typically it would be 0, but
+ * in case DFU restarted in the middle, it may differ.
+ * @param[in] error_handler A callback for error notification.
+ * @param[in] p_context A context for error notification.
+ */
+void block_manager_init(background_dfu_block_manager_t * p_bm,
+ uint32_t object_type,
+ uint32_t object_size,
+ int32_t initial_block,
+ block_manager_result_notify_t result_handler,
+ void * p_context);
+
+/**@brief Process a single block.
+ *
+ * @param[inout] p_bm A pointer to the block manager.
+ * @param[in] p_block A pointer to the block structure containing information about the block.
+ *
+ * @retval BACKGROUND_DFU_BLOCK_SUCCESS Block stored successfully.
+ * @retval BACKGROUND_DFU_BLOCK_IGNORE Invalid block size or block already stored in flash.
+ * @retval BACKGROUND_DFU_BLOCK_INVALID Block number indicates that too many blocks were missed.
+ * @retval BACKGROUND_DFU_BLOCK_STORE_ERROR Block store in flash failed.
+ */
+background_dfu_block_result_t block_manager_block_process(background_dfu_block_manager_t * p_bm,
+ const background_dfu_block_t * p_block);
+
+/**@brief Check if an image managed by a block manager is complete.
+ *
+ * @param[in] p_bm A pointer to the block manager.
+ *
+ * @return True if image is complete, false otherwise.
+ */
+bool block_manager_is_image_complete(const background_dfu_block_manager_t * p_bm);
+
+/**@brief Get current block bitmap.
+ *
+ * @param[in] p_bm A pointer to the block manager.
+ * @param[out] p_req_bmp A pointer to the block bitmap structure.
+ *
+ * @return True if non-empty bitmap was generated, false otherwise.
+ */
+bool block_manager_request_bitmap_get(const background_dfu_block_manager_t * p_bm,
+ background_dfu_request_bitmap_t * p_req_bmp);
+
+/**@brief Increment current block, in case no blocks were received and block timeout shot.
+ *
+ * @param[in] p_bm A pointer to the block manager.
+ *
+ * @return True if block was incremented, false if block manager is already on a last block of the image.
+ */
+bool block_manager_increment_current_block(background_dfu_block_manager_t * p_bm);
+
+/**@brief Get current block number that block manager received/expects.
+ *
+ * @param[in] p_bm A pointer to the block manager.
+ *
+ * @return Current block number.
+ */
+int32_t block_manager_get_current_block(const background_dfu_block_manager_t * p_bm);
+
+#endif /* BACKGROUND_DFU_BLOCK_H_ */
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.c
new file mode 100644
index 0000000..7aa6679
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.c
@@ -0,0 +1,141 @@
+/**
+ * Copyright (c) 2017 - 2018, 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.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup background_dfu_operation background_dfu_operation.c
+ * @{
+ * @ingroup background_dfu
+ * @brief Background DFU operations implementation.
+ *
+ */
+
+#include "background_dfu_operation.h"
+
+#include "sdk_config.h"
+#include "nrf_dfu_req_handler.h"
+
+#define NRF_LOG_MODULE_NAME background_dfu
+
+#define NRF_LOG_LEVEL BACKGROUND_DFU_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR BACKGROUND_DFU_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR BACKGROUND_DFU_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+
+ret_code_t background_dfu_op_select(uint32_t object_type,
+ nrf_dfu_response_callback_t callback,
+ void * p_context)
+{
+ nrf_dfu_request_t dfu_req;
+
+ memset(&dfu_req, 0, sizeof(dfu_req));
+
+ dfu_req.request = NRF_DFU_OP_OBJECT_SELECT;
+ dfu_req.select.object_type = object_type;
+ dfu_req.p_context = p_context;
+ dfu_req.callback.response = callback;
+
+ return nrf_dfu_req_handler_on_req(&dfu_req);
+}
+
+ret_code_t background_dfu_op_create(uint32_t object_type,
+ uint32_t object_size,
+ nrf_dfu_response_callback_t callback,
+ void * p_context)
+{
+ nrf_dfu_request_t dfu_req;
+
+ memset(&dfu_req, 0, sizeof(dfu_req));
+
+ dfu_req.request = NRF_DFU_OP_OBJECT_CREATE;
+ dfu_req.create.object_size = object_size;
+ dfu_req.create.object_type = object_type;
+ dfu_req.p_context = p_context;
+ dfu_req.callback.response = callback;
+
+ return nrf_dfu_req_handler_on_req(&dfu_req);
+}
+
+ret_code_t background_dfu_op_write(const uint8_t * p_payload,
+ uint16_t payload_length,
+ nrf_dfu_response_callback_t callback,
+ void * p_context)
+{
+ nrf_dfu_request_t dfu_req;
+
+ memset(&dfu_req, 0, sizeof(dfu_req));
+
+ dfu_req.request = NRF_DFU_OP_OBJECT_WRITE;
+ dfu_req.write.p_data = (uint8_t *)p_payload;
+ dfu_req.write.len = payload_length;
+ dfu_req.p_context = p_context;
+ dfu_req.callback.response = callback;
+
+ return nrf_dfu_req_handler_on_req(&dfu_req);
+}
+
+ret_code_t background_dfu_op_crc(nrf_dfu_response_callback_t callback,
+ void * p_context)
+{
+ nrf_dfu_request_t dfu_req;
+
+ memset(&dfu_req, 0, sizeof(dfu_req));
+
+ dfu_req.request = NRF_DFU_OP_CRC_GET;
+ dfu_req.p_context = p_context;
+ dfu_req.callback.response = callback;
+
+ return nrf_dfu_req_handler_on_req(&dfu_req);
+}
+
+ret_code_t background_dfu_op_execute(nrf_dfu_response_callback_t callback,
+ void * p_context)
+{
+ nrf_dfu_request_t dfu_req;
+
+ memset(&dfu_req, 0, sizeof(dfu_req));
+
+ dfu_req.request = NRF_DFU_OP_OBJECT_EXECUTE;
+ dfu_req.p_context = p_context;
+ dfu_req.callback.response = callback;
+
+ return nrf_dfu_req_handler_on_req(&dfu_req);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.h
new file mode 100644
index 0000000..b01d9b2
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_operation.h
@@ -0,0 +1,117 @@
+/**
+ * Copyright (c) 2017 - 2018, 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.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup background_dfu_operation background_dfu_operation.h
+ * @{
+ * @ingroup background_dfu
+ * @brief Background DFU operations.
+ *
+ */
+
+#ifndef BACKGROUND_DFU_OPERATION_H_
+#define BACKGROUND_DFU_OPERATION_H_
+
+#include <stdint.h>
+
+#include "nrf_dfu_handling_error.h"
+
+/** @brief Select DFU object.
+ *
+ * @param[in] object_type Object type which should be selected.
+ * @param[in] callback A callback function to be executed after operation is completed.
+ * @param[in] p_context A pointer to the operation context.
+ *
+ * @return Operation result code.
+ */
+ret_code_t background_dfu_op_select(uint32_t object_type,
+ nrf_dfu_response_callback_t callback,
+ void * p_context);
+
+/** @brief Create DFU object.
+ *
+ * @param[in] object_type Object type which should be selected.
+ * @param[in] object_size Size of an object to create.
+ * @param[in] callback A callback function to be executed after operation is completed.
+ * @param[in] p_context A pointer to the operation context.
+ *
+ * @return Operation result code.
+ */
+ret_code_t background_dfu_op_create(uint32_t object_type,
+ uint32_t object_size,
+ nrf_dfu_response_callback_t callback,
+ void * p_context);
+
+/** @brief Write DFU object.
+ *
+ * @param[in] p_payload A pointer to data which should be written to the object.
+ * @param[in] payload_length Length, in bytes, of data which should be written to the object.
+ * @param[in] callback A callback function to be executed after operation is completed.
+ * @param[in] p_context A pointer to the operation context.
+ *
+ * @return Operation result code.
+ */
+ret_code_t background_dfu_op_write(const uint8_t * p_payload,
+ uint16_t payload_length,
+ nrf_dfu_response_callback_t callback,
+ void * p_context);
+
+/** @brief Calculate DFU object CRC.
+ *
+ * @param[in] callback A callback function to be executed after operation is completed.
+ * @param[in] p_context A pointer to the operation context.
+ *
+ * @return Operation result code.
+ */
+ret_code_t background_dfu_op_crc(nrf_dfu_response_callback_t callback,
+ void * p_context);
+
+/** @brief Execute selected DFU.
+ *
+ * @param[in] callback A callback function to be executed after operation is completed.
+ * @param[in] p_context A pointer to the operation context.
+ *
+ * @return Operation result code.
+ */
+ret_code_t background_dfu_op_execute(nrf_dfu_response_callback_t callback,
+ void * p_context);
+
+#endif /* BACKGROUND_DFU_OPERATION_H_ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.c
new file mode 100644
index 0000000..5004558
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.c
@@ -0,0 +1,835 @@
+/**
+ * Copyright (c) 2017 - 2018, 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.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup background_dfu_state background_dfu_state.c
+ * @{
+ * @ingroup background_dfu
+ * @brief Background DFU state management.
+ *
+ */
+
+#include "background_dfu_state.h"
+
+#include <string.h>
+
+#include "sdk_config.h"
+#include "app_timer.h"
+#include "compiler_abstraction.h"
+#include "nrf_dfu_types.h"
+#include "nrf_dfu_settings.h"
+#include "sha256.h"
+#include "background_dfu_transport.h"
+#include "background_dfu_operation.h"
+
+#define NRF_LOG_MODULE_NAME background_dfu
+
+#define NRF_LOG_LEVEL BACKGROUND_DFU_CONFIG_LOG_LEVEL
+#define NRF_LOG_INFO_COLOR BACKGROUND_DFU_CONFIG_INFO_COLOR
+#define NRF_LOG_DEBUG_COLOR BACKGROUND_DFU_CONFIG_DEBUG_COLOR
+
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define BLOCK_REQUEST_JITTER_MIN 200 /**< Minimum jitter value when sending bitmap with requested blocks in multicast DFU. */
+#define BLOCK_REQUEST_JITTER_MAX 2000 /**< Maximum jitter value when sending bitmap with requested blocks in multicast DFU. */
+#define BLOCK_RECEIVE_TIMEOUT 2000 /**< Timeout value after which block is considered missing in multicast DFU. */
+
+#define DFU_DATE_TIME (__DATE__ " " __TIME__)
+
+/**@brief DFU trigger packet version. */
+#define TRIGGER_VERSION 1
+
+/**
+ * @defgroup background_dfu_trigger_flags Trigger flags and offsets.
+ * @{
+ */
+#define TRIGGER_FLAGS_VERSION_OFFSET 4
+#define TRIGGER_FLAGS_VERSION_MASK 0xF0
+#define TRIGGER_FLAGS_MODE_OFFSET 3
+#define TRIGGER_FLAGS_MODE_MASK 0x08
+#define TRIGGER_FLAGS_RESET_OFFSET 2
+#define TRIGGER_FLAGS_RESET_MASK 0x04
+/** @} */
+
+APP_TIMER_DEF(m_missing_block_timer);
+APP_TIMER_DEF(m_block_timeout_timer);
+
+/**@brief Defines how many retries are performed in case no response is received. */
+#define DEFAULT_RETRIES 3
+
+/**@brief DFU error handler.
+ *
+ * @param[inout] p_dfu_ctx DFU context.
+ */
+static __INLINE void dfu_handle_error(background_dfu_context_t * p_dfu_ctx)
+{
+ p_dfu_ctx->dfu_state = BACKGROUND_DFU_ERROR;
+
+ background_dfu_handle_error();
+}
+
+/**@brief Get randomized jitter value.
+ *
+ * @return Randomized jitter value between BLOCK_REQUEST_JITTER_MIN and BLOCK_REQUEST_JITTER_MAX.
+ */
+static __INLINE uint32_t block_request_jitter_get(void)
+{
+ return BLOCK_REQUEST_JITTER_MIN + (background_dfu_random() %
+ (BLOCK_REQUEST_JITTER_MAX - BLOCK_REQUEST_JITTER_MIN));
+}
+
+/**@brief Starts block timeout timer.
+ *
+ * @param[inout] p_dfu_ctx DFU context.
+ */
+static __INLINE void start_block_timeout_timer(background_dfu_context_t * p_dfu_ctx)
+{
+ uint32_t err_code = app_timer_start(m_block_timeout_timer,
+ APP_TIMER_TICKS(BLOCK_RECEIVE_TIMEOUT),
+ p_dfu_ctx);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in app_timer_start (%d)", err_code);
+ }
+}
+
+/**@brief Stops block timeout timer.
+ *
+ * @param[inout] p_dfu_ctx DFU context.
+ */
+static __INLINE void stop_block_timeout_timer(background_dfu_context_t * p_dfu_ctx)
+{
+ UNUSED_PARAMETER(p_dfu_ctx);
+ uint32_t err_code = app_timer_stop(m_block_timeout_timer);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in app_timer_stop (%d)", err_code);
+ }
+}
+
+/**@brief Restarts block timeout timer.
+ *
+ * @param[inout] p_dfu_ctx DFU context.
+ */
+static __INLINE void restart_block_timeout_timer(background_dfu_context_t * p_dfu_ctx)
+{
+ stop_block_timeout_timer(p_dfu_ctx);
+ start_block_timeout_timer(p_dfu_ctx);
+}
+
+/***************************************************************************************************
+ * @section Handle DFU Trigger
+ **************************************************************************************************/
+
+/**@brief Parses trigger data and updates DFU client context accordingly.
+ *
+ * @param[inout] p_dfu_ctx A pointer to DFU Client context.
+ * @param[in] p_trigger A pointer to trigger data.
+ *
+ * @return True if parsing was successful, false otherwise.
+ */
+static bool parse_trigger(background_dfu_context_t * p_dfu_ctx,
+ const background_dfu_trigger_t * p_trigger)
+{
+ uint8_t trigger_version = (p_trigger->flags & TRIGGER_FLAGS_VERSION_MASK)
+ >> TRIGGER_FLAGS_VERSION_OFFSET;
+
+ if (trigger_version <= TRIGGER_VERSION)
+ {
+ // Base fields available from version 0.
+ p_dfu_ctx->init_cmd_size = uint32_big_decode((const uint8_t *)&p_trigger->init_length);
+ p_dfu_ctx->init_cmd_crc = uint32_big_decode((const uint8_t *)&p_trigger->init_crc);
+ p_dfu_ctx->firmware_size = uint32_big_decode((const uint8_t *)&p_trigger->image_length);
+ p_dfu_ctx->firmware_crc = uint32_big_decode((const uint8_t *)&p_trigger->image_crc);
+
+ // Mode flag was added in DFU Trigger version 1.
+ if (trigger_version >= 1)
+ {
+ p_dfu_ctx->dfu_mode = (background_dfu_mode_t)((p_trigger->flags
+ & TRIGGER_FLAGS_MODE_MASK) >> TRIGGER_FLAGS_MODE_OFFSET);
+ p_dfu_ctx->reset_suppress = (p_trigger->flags & TRIGGER_FLAGS_RESET_MASK) >>
+ TRIGGER_FLAGS_RESET_OFFSET;
+
+ }
+ else
+ {
+ p_dfu_ctx->dfu_mode = BACKGROUND_DFU_MODE_UNICAST;
+ }
+
+ NRF_LOG_INFO("DFU trigger: init (sz=%d, crc=%0X) image (sz=%d, crc=%0X)",
+ p_dfu_ctx->init_cmd_size,
+ p_dfu_ctx->init_cmd_crc,
+ p_dfu_ctx->firmware_size,
+ p_dfu_ctx->firmware_crc);
+
+ return true;
+ }
+
+ return false;
+}
+
+bool background_dfu_validate_trigger(background_dfu_context_t * p_dfu_ctx,
+ const uint8_t * p_payload,
+ uint32_t payload_len)
+{
+ if (payload_len != sizeof(background_dfu_trigger_t))
+ {
+ NRF_LOG_ERROR("Validate trigger: size mismatch");
+ return false;
+ }
+
+ if ((p_dfu_ctx->dfu_state != BACKGROUND_DFU_IDLE) &&
+ (p_dfu_ctx->dfu_state != BACKGROUND_DFU_DOWNLOAD_TRIG))
+ {
+ NRF_LOG_ERROR("Validate trigger: DFU already in progress (s:%s).",
+ (uint32_t)background_dfu_state_to_string(p_dfu_ctx->dfu_state));
+ return false;
+ }
+
+ uint8_t trigger_version = (((background_dfu_trigger_t *)p_payload)->flags
+ & TRIGGER_FLAGS_VERSION_MASK) >> TRIGGER_FLAGS_VERSION_OFFSET;
+ if (trigger_version > TRIGGER_VERSION)
+ {
+ NRF_LOG_ERROR("Validate trigger: invalid trigger version.");
+ return false;
+ }
+
+ return true;
+}
+
+bool background_dfu_process_trigger(background_dfu_context_t * p_dfu_ctx,
+ const uint8_t * p_payload,
+ uint32_t payload_len)
+{
+ bool result = false;
+
+ do
+ {
+ if (!parse_trigger(p_dfu_ctx, (background_dfu_trigger_t *)p_payload))
+ {
+ NRF_LOG_ERROR("Process trigger: failed to parse payload");
+ break;
+ }
+
+ p_dfu_ctx->dfu_state = BACKGROUND_DFU_DOWNLOAD_TRIG;
+
+ uint32_t err_code = background_dfu_handle_event(p_dfu_ctx,
+ BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in background_dfu_handle_event (%d)", err_code);
+ }
+
+ result = true;
+ } while(0);
+
+ return result;
+}
+
+/***************************************************************************************************
+ * @section DFU checks
+ **************************************************************************************************/
+
+background_dfu_block_result_t background_dfu_process_block(background_dfu_context_t * p_dfu_ctx,
+ const background_dfu_block_t * p_block)
+{
+ background_dfu_block_result_t result = block_manager_block_process(&p_dfu_ctx->block_manager,
+ p_block);
+ uint32_t err_code = NRF_SUCCESS;
+
+ switch (result)
+ {
+ case BACKGROUND_DFU_BLOCK_IGNORE:
+ // Ignore.
+ if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
+ {
+ restart_block_timeout_timer(p_dfu_ctx);
+ }
+
+ break;
+
+ case BACKGROUND_DFU_BLOCK_SUCCESS:
+ // Intentionally empty.
+ break;
+
+ default:
+ err_code = background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_PROCESSING_ERROR);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in background_dfu_handle_event (%d)", err_code);
+ }
+
+ break;
+ }
+
+ return result;
+}
+
+/**@brief Check if installed image is different from the incoming one.
+ *
+ * @param[in] p_dfu_ctx A pointer to DFU client context.
+ *
+ * @return True if image different, false otherwise.
+ *
+ */
+static bool is_image_different(const background_dfu_context_t * p_dfu_ctx)
+{
+ if (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_INVALID)
+ {
+ NRF_LOG_WARNING("No image in bank 0");
+ return true;
+ }
+
+ if (s_dfu_settings.bank_0.image_crc != p_dfu_ctx->firmware_crc)
+ {
+ NRF_LOG_WARNING("Installed image CRC is different");
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * @brief A callback function for block manager.
+ */
+static void dfu_block_manager_result_handler(background_dfu_block_result_t result, void * p_context)
+{
+ background_dfu_context_t * p_dfu_ctx = p_context;
+ uint32_t err_code;
+
+ if (result == BACKGROUND_DFU_BLOCK_SUCCESS)
+ {
+ if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
+ {
+ restart_block_timeout_timer(p_dfu_ctx);
+ }
+
+ if (block_manager_is_image_complete(&p_dfu_ctx->block_manager))
+ {
+ err_code = background_dfu_handle_event(p_dfu_ctx,
+ BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in background_dfu_handle_event (%d)", err_code);
+ }
+ }
+ else
+ {
+ // FIXME I don't like it here.
+ p_dfu_ctx->block_num++;
+
+ err_code = background_dfu_handle_event(p_dfu_ctx,
+ BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in background_dfu_handle_event (%d)", err_code);
+ }
+ }
+ }
+ else
+ {
+ err_code = background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_PROCESSING_ERROR);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in background_dfu_handle_event (%d)", err_code);
+ }
+ }
+}
+
+/**
+ * @brief Prepare state machine to download init command.
+ */
+static void setup_download_init_command(background_dfu_context_t * p_dfu_ctx)
+{
+ p_dfu_ctx->p_resource_size = &p_dfu_ctx->init_cmd_size;
+ p_dfu_ctx->retry_count = DEFAULT_RETRIES;
+ p_dfu_ctx->block_num = 0;
+
+ background_dfu_transport_state_update(p_dfu_ctx);
+
+ block_manager_init(&p_dfu_ctx->block_manager,
+ p_dfu_ctx->dfu_state,
+ *p_dfu_ctx->p_resource_size,
+ p_dfu_ctx->block_num,
+ dfu_block_manager_result_handler,
+ p_dfu_ctx);
+
+ if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
+ {
+ NRF_LOG_INFO("Init complete. Multicast Mode.");
+ uint32_t jitter = block_request_jitter_get();
+ uint32_t err_code = app_timer_start(m_missing_block_timer,
+ APP_TIMER_TICKS(jitter),
+ p_dfu_ctx);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in app_timer_start (%d)", err_code);
+ }
+ }
+ else
+ {
+ NRF_LOG_INFO("Init complete. Unicast Mode.");
+ }
+}
+
+/**
+ * @brief A callback function for DFU command operations.
+ */
+static void dfu_init_check_callback(nrf_dfu_response_t * p_res, void * p_context)
+{
+ background_dfu_context_t * p_dfu_ctx = (background_dfu_context_t *)p_context;
+
+ switch (p_res->request)
+ {
+ case NRF_DFU_OP_OBJECT_SELECT:
+ if (p_res->result != NRF_DFU_RES_CODE_SUCCESS)
+ {
+ NRF_LOG_ERROR("No valid init command - select failed");
+ setup_download_init_command((background_dfu_context_t *)p_context);
+
+ UNUSED_RETURN_VALUE(background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE));
+ }
+
+ p_dfu_ctx->max_obj_size = p_res->select.max_size;
+ p_dfu_ctx->block_num = p_res->select.offset / DEFAULT_BLOCK_SIZE;
+
+ if (background_dfu_op_execute(dfu_init_check_callback, p_context) != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("No valid init command - execute error");
+ setup_download_init_command((background_dfu_context_t *)p_context);
+
+ UNUSED_RETURN_VALUE(background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE));
+ }
+
+ break;
+
+ case NRF_DFU_OP_OBJECT_EXECUTE:
+ if ((p_res->result != NRF_DFU_RES_CODE_SUCCESS) ||
+ (s_dfu_settings.progress.command_crc != p_dfu_ctx->init_cmd_crc))
+ {
+ NRF_LOG_ERROR("Init commad has changed");
+ p_dfu_ctx->remaining_size = 0;
+ setup_download_init_command((background_dfu_context_t *)p_context);
+
+ UNUSED_RETURN_VALUE(background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE));
+ }
+ else
+ {
+ // Valid init command stored, download firmware.
+ p_dfu_ctx->dfu_diag.state = BACKGROUND_DFU_DOWNLOAD_INIT_CMD;
+
+ UNUSED_RETURN_VALUE(background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE));
+ }
+
+ break;
+
+ default:
+ ASSERT(false);
+ }
+}
+
+/**
+ * @brief A callback function for DFU data operation.
+ */
+static void dfu_data_select_callback(nrf_dfu_response_t * p_res, void * p_context)
+{
+ ASSERT(p_res->request == NRF_DFU_OP_OBJECT_SELECT);
+
+ background_dfu_context_t * p_dfu_ctx = (background_dfu_context_t *)p_context;
+ if (p_res->result != NRF_DFU_RES_CODE_SUCCESS)
+ {
+ NRF_LOG_ERROR("Select failed");
+ dfu_handle_error(p_dfu_ctx);
+ return;
+ }
+
+ p_dfu_ctx->dfu_state = BACKGROUND_DFU_DOWNLOAD_FIRMWARE;
+ p_dfu_ctx->p_resource_size = &p_dfu_ctx->firmware_size;
+ p_dfu_ctx->retry_count = DEFAULT_RETRIES;
+ p_dfu_ctx->block_num = (p_res->select.offset / DEFAULT_BLOCK_SIZE);
+ p_dfu_ctx->max_obj_size = p_res->select.max_size;
+
+ background_dfu_transport_state_update(p_dfu_ctx);
+
+ block_manager_init(&p_dfu_ctx->block_manager,
+ p_dfu_ctx->dfu_state,
+ *p_dfu_ctx->p_resource_size,
+ p_dfu_ctx->block_num,
+ dfu_block_manager_result_handler,
+ p_dfu_ctx);
+
+ UNUSED_RETURN_VALUE(background_dfu_handle_event(p_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE));
+}
+
+/***************************************************************************************************
+ * @section Timer handlers
+ **************************************************************************************************/
+
+/**@brief Handler function for block request timer.
+ *
+ * @param[inout] p_context DFU context.
+ */
+static void block_request_handler(void * p_context)
+{
+ background_dfu_context_t * p_dfu_ctx = (background_dfu_context_t *)p_context;
+
+ if ((p_dfu_ctx->dfu_state != BACKGROUND_DFU_DOWNLOAD_FIRMWARE) &&
+ (p_dfu_ctx->dfu_state != BACKGROUND_DFU_DOWNLOAD_INIT_CMD))
+ {
+ return;
+ }
+
+ background_dfu_request_bitmap_t req_bmp;
+ if (block_manager_request_bitmap_get(&p_dfu_ctx->block_manager, &req_bmp) &&
+ (req_bmp.size > 0))
+ {
+ background_dfu_transport_block_request_send(p_dfu_ctx, &req_bmp);
+ }
+
+ // Reschedule the timer.
+ uint32_t jitter = block_request_jitter_get();
+ uint32_t err_code = app_timer_start(m_missing_block_timer, APP_TIMER_TICKS(jitter), p_dfu_ctx);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in app_timer_start (%d)", err_code);
+ }
+}
+
+/**@brief Handler function for block timeout timer.
+ *
+ * @param[inout] p_context DFU context.
+ */
+static void block_timeout_handler(void * p_context)
+{
+ background_dfu_context_t * p_dfu_ctx = (background_dfu_context_t *)p_context;
+
+ NRF_LOG_INFO("Block timeout! (b: %d)",
+ block_manager_get_current_block(&p_dfu_ctx->block_manager));
+
+ if ((p_dfu_ctx->dfu_state != BACKGROUND_DFU_DOWNLOAD_FIRMWARE) &&
+ (p_dfu_ctx->dfu_state != BACKGROUND_DFU_DOWNLOAD_INIT_CMD))
+ {
+ return;
+ }
+
+ if (block_manager_increment_current_block(&p_dfu_ctx->block_manager))
+ {
+ start_block_timeout_timer(p_dfu_ctx);
+ }
+}
+
+/***************************************************************************************************
+ * @section API functions
+ **************************************************************************************************/
+
+/** @brief Helper function converting DFU state to string.
+ *
+ * @param[in] state DFU client state.
+ *
+ * @return A pointer to null terminated string with state name.
+ */
+const char * background_dfu_state_to_string(const background_dfu_state_t state)
+{
+ static const char * const names[] =
+ {
+ "DFU_DOWNLOAD_INIT_CMD",
+ "DFU_DOWNLOAD_FIRMWARE",
+ "DFU_DOWNLOAD_TRIG",
+ "DFU_WAIT_FOR_RESET",
+ "DFU_IDLE",
+ "DFU_ERROR",
+ };
+
+ return names[(uint32_t)state - BACKGROUND_DFU_DOWNLOAD_INIT_CMD];
+}
+
+/** @brief Helper function convering DFU event name to string.
+ *
+ * @param[in] state DFU client event.
+ *
+ * @return A pointer to null terminated string with event name.
+ */
+const char * background_dfu_event_to_string(const background_dfu_event_t event)
+{
+ static const char * const names[] = {
+ "DFU_EVENT_TRANSFER_COMPLETE",
+ "DFU_EVENT_TRANSFER_CONTINUE",
+ "DFU_EVENT_TRANSFER_ERROR",
+ "DFU_EVENT_PROCESSING_ERROR",
+ };
+
+ return names[event];
+}
+
+uint32_t background_dfu_handle_event(background_dfu_context_t * p_dfu_ctx,
+ background_dfu_event_t event)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ NRF_LOG_INFO("state=%s event=%s",
+ (uint32_t)background_dfu_state_to_string(p_dfu_ctx->dfu_state),
+ (uint32_t)background_dfu_event_to_string(event));
+
+ switch (p_dfu_ctx->dfu_state)
+ {
+ case BACKGROUND_DFU_IDLE:
+ {
+ if (event == BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE)
+ {
+ p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_IDLE;
+
+ p_dfu_ctx->dfu_state = BACKGROUND_DFU_DOWNLOAD_TRIG;
+ p_dfu_ctx->block_num = 0;
+ p_dfu_ctx->retry_count = DEFAULT_RETRIES;
+
+ background_dfu_transport_state_update(p_dfu_ctx);
+ }
+
+ break;
+ }
+
+ case BACKGROUND_DFU_DOWNLOAD_TRIG:
+ {
+ if (event == BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE)
+ {
+ if (!is_image_different(p_dfu_ctx))
+ {
+ NRF_LOG_INFO("Image is already installed");
+ background_dfu_reset_state(p_dfu_ctx);
+ break;
+ }
+
+ p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_DOWNLOAD_TRIG;
+
+ p_dfu_ctx->dfu_state = BACKGROUND_DFU_DOWNLOAD_INIT_CMD;
+
+ // Initiate init command check procedure.
+ if (background_dfu_op_select(NRF_DFU_OBJ_TYPE_COMMAND,
+ dfu_init_check_callback,
+ p_dfu_ctx) != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("No valid init command - select error");
+ setup_download_init_command(p_dfu_ctx);
+ }
+ else
+ {
+ // We wait for dfu request to finish - do not send anything.
+ return NRF_SUCCESS;
+ }
+ }
+
+ break;
+ }
+
+ case BACKGROUND_DFU_DOWNLOAD_INIT_CMD:
+ {
+ if (event == BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE)
+ {
+ p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_DOWNLOAD_INIT_CMD;
+
+ if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
+ {
+ stop_block_timeout_timer(p_dfu_ctx);
+ }
+
+ if (background_dfu_op_select(NRF_DFU_OBJ_TYPE_DATA,
+ dfu_data_select_callback,
+ p_dfu_ctx) != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Select failed");
+ dfu_handle_error(p_dfu_ctx);
+ err_code = NRF_ERROR_INTERNAL;
+ }
+ else
+ {
+ return NRF_SUCCESS;
+ }
+ }
+ else if (event == BACKGROUND_DFU_EVENT_PROCESSING_ERROR)
+ {
+ p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_DOWNLOAD_INIT_CMD;
+
+ if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
+ {
+ stop_block_timeout_timer(p_dfu_ctx);
+ }
+
+ NRF_LOG_ERROR("Processing error while downloading init command.");
+ dfu_handle_error(p_dfu_ctx);
+ }
+ break;
+ }
+
+ case BACKGROUND_DFU_DOWNLOAD_FIRMWARE:
+ {
+ if (event == BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE)
+ {
+ p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_DOWNLOAD_FIRMWARE;
+
+ p_dfu_ctx->dfu_state = BACKGROUND_DFU_WAIT_FOR_RESET;
+
+ if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
+ {
+ stop_block_timeout_timer(p_dfu_ctx);
+ }
+
+ background_dfu_transport_state_update(p_dfu_ctx);
+ }
+ else if (event == BACKGROUND_DFU_EVENT_PROCESSING_ERROR)
+ {
+ p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_DOWNLOAD_FIRMWARE;
+
+ if (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST)
+ {
+ stop_block_timeout_timer(p_dfu_ctx);
+ }
+
+ NRF_LOG_ERROR("Processing error while downloading firmware.");
+ dfu_handle_error(p_dfu_ctx);
+ }
+ break;
+ }
+
+ case BACKGROUND_DFU_WAIT_FOR_RESET:
+ NRF_LOG_WARNING("An event received in wait for reset state. This should not happen.");
+ break;
+
+ default:
+ NRF_LOG_ERROR("Unhandled state");
+ break;
+ }
+
+ if ((p_dfu_ctx->dfu_state != BACKGROUND_DFU_IDLE) &&
+ (p_dfu_ctx->dfu_state != BACKGROUND_DFU_ERROR) &&
+ (p_dfu_ctx->dfu_state != BACKGROUND_DFU_WAIT_FOR_RESET))
+ {
+ if (((p_dfu_ctx->dfu_state == BACKGROUND_DFU_DOWNLOAD_FIRMWARE) ||
+ (p_dfu_ctx->dfu_state == BACKGROUND_DFU_DOWNLOAD_INIT_CMD)) &&
+ (p_dfu_ctx->dfu_mode == BACKGROUND_DFU_MODE_MULTICAST))
+ {
+ // In multicast DFU firmware download, client doesn't initiate block requests.
+ }
+ else
+ {
+ if ((event == BACKGROUND_DFU_EVENT_TRANSFER_ERROR) && (p_dfu_ctx->retry_count > 0))
+ {
+ p_dfu_ctx->retry_count -= 1;
+ }
+
+ if (p_dfu_ctx->retry_count > 0)
+ {
+ background_dfu_transport_send_request(p_dfu_ctx);
+ }
+ else
+ {
+ NRF_LOG_ERROR("No more retries");
+ dfu_handle_error(p_dfu_ctx);
+ }
+ }
+ }
+
+ return err_code;
+}
+
+void background_dfu_reset_state(background_dfu_context_t * p_dfu_ctx)
+{
+ sha256_context_t sha256_ctx;
+
+ uint8_t hash[32];
+ uint32_t err_code = NRF_SUCCESS;
+
+ p_dfu_ctx->dfu_state = BACKGROUND_DFU_IDLE;
+ p_dfu_ctx->dfu_mode = BACKGROUND_DFU_MODE_UNICAST;
+ p_dfu_ctx->init_cmd_size = 0;
+ p_dfu_ctx->firmware_size = 0;
+ p_dfu_ctx->remaining_size = 0;
+
+ memset(&p_dfu_ctx->dfu_diag, 0, sizeof(p_dfu_ctx->dfu_diag));
+
+ err_code = sha256_init(&sha256_ctx);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in sha256_init (%d)", err_code);
+ }
+
+ err_code = sha256_update(&sha256_ctx, (const uint8_t *)DFU_DATE_TIME, strlen(DFU_DATE_TIME));
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in sha256_update (%d)", err_code);
+ }
+
+ err_code = sha256_final(&sha256_ctx, (uint8_t *)hash, false);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in sha256_final (%d)", err_code);
+ }
+
+ p_dfu_ctx->dfu_diag.build_id = uint32_big_decode(hash);
+ p_dfu_ctx->dfu_diag.state = BACKGROUND_DFU_IDLE;
+ p_dfu_ctx->dfu_diag.prev_state = BACKGROUND_DFU_IDLE;
+
+ NRF_LOG_INFO("Current DFU Diag version: %s, 0x%08x",
+ (uint32_t)DFU_DATE_TIME, p_dfu_ctx->dfu_diag.build_id);
+}
+
+void background_dfu_state_init(background_dfu_context_t * p_dfu_ctx)
+{
+ uint32_t err_code;
+
+ err_code = app_timer_create(&m_missing_block_timer,
+ APP_TIMER_MODE_SINGLE_SHOT,
+ block_request_handler);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in app_timer_create (%d)", err_code);
+ }
+
+ err_code = app_timer_create(&m_block_timeout_timer,
+ APP_TIMER_MODE_SINGLE_SHOT,
+ block_timeout_handler);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in app_timer_create (%d)", err_code);
+ }
+
+ background_dfu_reset_state(p_dfu_ctx);
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.h
new file mode 100644
index 0000000..8dd4395
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/background_dfu_state.h
@@ -0,0 +1,216 @@
+/**
+ * Copyright (c) 2017 - 2018, 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.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup background_dfu_state background_dfu_state.h
+ * @{
+ * @ingroup background_dfu
+ * @brief Background DFU state management.
+ *
+ */
+
+#ifndef BACKGROUND_DFU_STATE_H_
+#define BACKGROUND_DFU_STATE_H_
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include "background_dfu_block.h"
+#include "nrf_dfu_req_handler.h"
+
+/** @brief DFU client state ID.
+ *
+ * We reuse DFU object type IDs as DFU process states IDs,
+ * so that current state can be used as the object type in
+ * function which expect one.
+ */
+typedef enum
+{
+ BACKGROUND_DFU_DOWNLOAD_INIT_CMD = NRF_DFU_OBJ_TYPE_COMMAND,
+ BACKGROUND_DFU_DOWNLOAD_FIRMWARE = NRF_DFU_OBJ_TYPE_DATA,
+ BACKGROUND_DFU_DOWNLOAD_TRIG,
+ BACKGROUND_DFU_WAIT_FOR_RESET,
+ BACKGROUND_DFU_IDLE,
+ BACKGROUND_DFU_ERROR,
+} background_dfu_state_t;
+
+/** @brief DFU event definitions. */
+typedef enum
+{
+ BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE,
+ BACKGROUND_DFU_EVENT_TRANSFER_CONTINUE,
+ BACKGROUND_DFU_EVENT_TRANSFER_ERROR,
+ BACKGROUND_DFU_EVENT_PROCESSING_ERROR,
+} background_dfu_event_t;
+
+/** @brief DFU mode definitions. */
+typedef enum
+{
+ BACKGROUND_DFU_MODE_UNICAST,
+ BACKGROUND_DFU_MODE_MULTICAST
+} background_dfu_mode_t;
+
+/** @brief Trigger packet structure. */
+typedef PACKED_STRUCT
+{
+ uint8_t flags; /**< Trigger message flags. Bits 7:4 (oldest) - trigger version, bit 3 - DFU mode, bits 2:0 - reserved. */
+ uint32_t init_length;
+ uint32_t init_crc;
+ uint32_t image_length;
+ uint32_t image_crc;
+} background_dfu_trigger_t;
+
+/**@brief Structure with DFU diagnostic information. */
+typedef PACKED_STRUCT background_dfu_diagnostic
+{
+ uint32_t build_id; /**< Build identifier, based on compilation time. */
+ uint8_t state; /**< Current DFU state. */
+ uint8_t prev_state; /**< Previous DFU state. */
+ uint16_t init_blocks_requested; /**< Number of requested missing init blocks. */
+ uint16_t image_blocks_requested; /**< Number of requested missing image blocks. */
+ uint16_t triggers_received; /**< Number of triggers received. */
+ uint16_t total_init_blocks_received; /**< Total number of init blocks received, including retransmitted ones. */
+ uint16_t total_image_blocks_received; /**< Total number of image blocks received, including retransmitted ones. */
+} background_dfu_diagnostic_t;
+
+/** @brief DFU client state. */
+typedef struct dfu_context
+{
+ background_dfu_state_t dfu_state; /**< Current DFU client state. */
+ background_dfu_mode_t dfu_mode; /**< Current DFU mode. */
+ bool reset_suppress; /**< If set then device won't automatically reset after
+ downloading firmware. */
+ background_dfu_diagnostic_t dfu_diag; /**< DFU diagnostic information. */
+
+ uint32_t init_cmd_size; /**< Current init command size. */
+ uint32_t init_cmd_crc; /**< Current init command checksum. */
+ uint32_t firmware_size; /**< Current firmware command size. */
+ uint32_t firmware_crc; /**< Current firmware command checksum. */
+ uint32_t max_obj_size; /**< Maximum size of the DFU object. */
+ uint32_t remaining_size; /**< Remaining size, in bytes, of the resource which
+ is being downloaded. */
+ /* TODO Move the block num to the block manager. */
+ uint32_t block_num; /**< Currently requested block number. */
+ uint32_t * p_resource_size; /**< Downloaded resource size. */
+ background_dfu_block_manager_t block_manager; /**< An entity managing block reception and storage. */
+ uint8_t retry_count; /**< Number of remaining retires. */
+} background_dfu_context_t;
+
+/**@brief Check if payload contains valid trigger.
+ *
+ * @param[inout] p_dfu_ctx DFU context.
+ * @param[in] p_payload A pointer to the message payload.
+ * @param[in[ payload_len Payload length.
+ *
+ * @return True if trigger was valid, false otherwise.
+ */
+bool background_dfu_validate_trigger(background_dfu_context_t * p_dfu_ctx,
+ const uint8_t * p_payload,
+ uint32_t payload_len);
+
+/**@brief Process a payload with a DFU trigger.
+ *
+ * @param[inout] p_dfu_ctx DFU context.
+ * @param[in] p_payload A pointer to the message payload.
+ * @param[in[ payload_len Payload length.
+ *
+ * @return True if trigger was successfully processed, false otherwise.
+ */
+bool background_dfu_process_trigger(background_dfu_context_t * p_dfu_ctx,
+ const uint8_t * p_payload,
+ uint32_t payload_len);
+
+/**@brief Process the block and return CoAP result code corresponding to the result of operation.
+ *
+ * @param[inout] p_dfu_ctx DFU context.
+ * @param[in] p_block A pointer to the block structure.
+ *
+ * @return True if init command is valid, false otherwise.
+ *
+ * @retval BACKGROUND_DFU_BLOCK_SUCCESS The block was processed correctly.
+ * @retval BACKGROUND_DFU_BLOCK_IGNORE The block was incorrect for this node, but did not
+ * indicate that the DFU shall be stopped.
+ * @retval BACKGROUND_DFU_BLOCK_INVALID The block indicated that the node would not catch-up with the DFU
+ * transfer or other error occured. Node aborted DFU.
+ * @retval BACKGROUND_DFU_BLOCK_STORE_ERROR DFU store error.
+ */
+background_dfu_block_result_t background_dfu_process_block(background_dfu_context_t * p_dfu_ctx,
+ const background_dfu_block_t * p_block);
+
+/**@brief DFU state machine handler.
+ *
+ * @param[in] p_dfu_ctx DFU context.
+ * @param[in] event DFU event.
+ *
+ * @return NRF_SUCCESS or error code
+ */
+uint32_t background_dfu_handle_event(background_dfu_context_t * p_dfu_ctx,
+ background_dfu_event_t event);
+
+/**@brief Reset state machine state.
+ *
+ * @param[in] p_dfu_ctx A pointer to DFU client context.
+ */
+void background_dfu_reset_state(background_dfu_context_t * p_dfu_ctx);
+
+/**@brief Initialize state machine state.
+ *
+ * @param[in] p_dfu_ctx A pointer to DFU client context.
+ */
+void background_dfu_state_init(background_dfu_context_t * p_dfu_ctx);
+
+/**@brief Convert a DFU event enum value to a string description.
+ *
+ * @param[in] event A DFU event.
+ *
+ * @return String representing the event.
+ */
+const char * background_dfu_event_to_string(const background_dfu_event_t event);
+
+/**@brief Convert a DFU state enum value to a string description.
+ *
+ * @param[in] event A DFU state.
+ *
+ * @return String representing the state.
+ */
+const char * background_dfu_state_to_string(const background_dfu_state_t state);
+
+#endif /* BACKGROUND_DFU_STATE_H_ */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/background_dfu_transport.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/background_dfu_transport.h
new file mode 100644
index 0000000..061a921
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/background_dfu_transport.h
@@ -0,0 +1,91 @@
+/**
+ * Copyright (c) 2017 - 2018, 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.
+ *
+ */
+
+/** @file
+ *
+ * @defgroup background_dfu_transport background_dfu_state.h
+ * @{
+ * @ingroup background_dfu
+ * @brief Background DFU transport API.
+ *
+ */
+
+#ifndef BACKGROUND_DFU_TRANSPORT_H_
+#define BACKGROUND_DFU_TRANSPORT_H_
+
+#include "background_dfu_state.h"
+
+/**@brief Create and send DFU block request with missing blocks.
+ *
+ * This function is used in multicast DFU.
+ *
+ * @param[in] p_dfu_ctx A pointer to the background DFU context.
+ * @param[in] p_req_bmp A pointer to the bitmap structure that shall be sent.
+ */
+void background_dfu_transport_block_request_send(background_dfu_context_t * p_dfu_ctx,
+ background_dfu_request_bitmap_t * p_req_bmp);
+
+/**@brief Send background DFU request, based on DFU state.
+ *
+ * @param[in] p_dfu_ctx A pointer to the background DFU context.
+ */
+void background_dfu_transport_send_request(background_dfu_context_t * p_dfu_ctx);
+
+/**@brief Update background DFU transport state.
+ *
+ * @param[in] p_dfu_ctx A pointer to the background DFU context.
+ */
+void background_dfu_transport_state_update(background_dfu_context_t * p_dfu_ctx);
+
+/**@brief Get random value.
+ *
+ * @returns A random value of uint32_t type.
+ */
+uint32_t background_dfu_random(void);
+
+/** @brief Handle DFU error.
+ *
+ * Notify transport about DFU error.
+ */
+void background_dfu_handle_error(void);
+
+#endif /* BACKGROUND_DFU_COAP_H_ */
+
+/** @} */
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.c
new file mode 100644
index 0000000..923d220
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.c
@@ -0,0 +1,928 @@
+/**
+ * Copyright (c) 2017 - 2018, 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.
+ *
+ */
+
+/** @file
+ *
+ * @brief TFTP DFU Example - Background DFU transport implementation.
+ *
+ */
+#include "tftp_dfu.h"
+
+#include "background_dfu_transport.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include "app_timer.h"
+#include "background_dfu_block.h"
+#include "background_dfu_transport.h"
+#include "cJSON.h"
+#include "cJSON_iot_hooks.h"
+#include "crc16.h"
+#include "iot_file_static.h"
+#include "iot_tftp.h"
+#include "nrf.h"
+#include "nrf_assert.h"
+#include "nrf_delay.h"
+#include "nrf_dfu_req_handler.h"
+#include "nrf_dfu_settings.h"
+#include "nrf_dfu_utils.h"
+#include "nrf_log_ctrl.h"
+
+#define NRF_LOG_LEVEL 4
+#define NRF_LOG_MODULE_NAME TFTP_DFU
+#include "nrf_log.h"
+NRF_LOG_MODULE_REGISTER();
+
+#define MAX_LENGTH_FILENAME 32 /**< Maximum length of the filename. */
+#define MAX_CONFIG_SIZE 1024 /**< Maximum DFU of the config size. */
+
+#define CONFIG_APP_KEY "app"
+#define CONFIG_SD_KEY "sd"
+#define CONFIG_APPSD_KEY "appsd"
+#define CONFIG_BL_KEY "bl"
+#define CONFIG_PATH_KEY "p"
+#define CONFIG_INIT_PATH_KEY "i"
+#define CONFIG_SIZE_KEY "s"
+#define CONFIG_ID_KEY "id"
+#define CONFIG_INIT_SIZE_KEY "is"
+#define CONFIG_INIT_ID_KEY "iid"
+
+#define APP_TFTP_BLOCK_SIZE 512 /**< Maximum or negotiated size of data block. */
+#define APP_TFTP_RETRANSMISSION_TIME 3 /**< Number of milliseconds between retransmissions. */
+
+#define BOOTLOADER_REGION_START 0x0007D000 /**< This field should correspond to start address of the bootloader, found in UICR.RESERVED, 0x10001014, register.
+ This value is used for sanity check, so the bootloader will fail immediately if this value differs from runtime value.
+ The value is used to determine max application size for updating. */
+
+#define TFTP_SOFTDEVICE_UPGRADE_SUPPORT false /**< Upgrade of softdevice or bootloader is not supported with current version of Background DFU module. */
+
+/** The device info offset can be modified to place the device info settings at a different location.
+ * If the customer reserved UICR location is used for other application specific data, the offset
+ * must be updated to avoid collision with that data.:
+ */
+/** [DFU UICR DEV offset] */
+#define UICR_CUSTOMER_DEVICE_INFO_OFFSET 0x0 /**< Device info offset inside the customer UICR reserved area. Customers may change this value to place the device information in a user-preferred location. */
+/** [DFU UICR DEV offset] */
+#define UICR_CUSTOMER_RESERVED_OFFSET 0x80 /**< Customer reserved area in the UICR. The area from UICR + 0x80 is reserved for customer usage. */
+#define DFU_DEVICE_INFO_BASE (NRF_UICR_BASE + \
+ UICR_CUSTOMER_RESERVED_OFFSET + \
+ UICR_CUSTOMER_DEVICE_INFO_OFFSET) /**< The device information base address inside of UICR. */
+#define DFU_DEVICE_INFO ((dfu_device_info_t *)DFU_DEVICE_INFO_BASE) /**< The memory mapped structure for device information data. */
+
+
+/**@brief Structure holding basic device information settings.
+ */
+typedef struct
+{
+ uint16_t device_type; /**< Device type (2 bytes), for example Heart Rate. This number must be defined by the customer before production. It can be located in UICR or FICR. */
+ uint16_t device_rev; /**< Device revision (2 bytes), for example major revision 1, minor revision 0. This number must be defined by the customer before production. It can be located in UICR or FICR. */
+} dfu_device_info_t;
+
+/**@brief Description of single block of firmware. */
+typedef struct
+{
+ uint32_t size; /**< Size of firmware block. */
+ uint32_t crc; /**< CRC of firmware block. Set to 0 if no checksum checking is needed. */
+ uint32_t init_size; /**< Size of init file. */
+ uint32_t init_crc; /**< CRC of init file. */
+} iot_dfu_firmware_block_t;
+
+
+/**@brief Description of the new firmware that has been written into flash memory. */
+typedef struct
+{
+ iot_dfu_firmware_block_t application; /**< Description of Application block in firmware image. */
+ iot_dfu_firmware_block_t softdevice; /**< Description of SoftDevice block in firmware image. */
+ iot_dfu_firmware_block_t bootloader; /**< Description of Bootloader block in firmware image. */
+} iot_dfu_firmware_desc_t;
+
+/**@brief Type of image being updated by the DFU module. */
+typedef enum
+{
+ TFTP_DFU_IMAGE_TYPE_APPLICATION, /**< DFU updates application. */
+ TFTP_DFU_IMAGE_TYPE_SOFTDEVICE, /**< DFU updates softdevice and application. */
+ TFTP_DFU_IMAGE_TYPE_BOOTLOADER, /**< DFU updates bootloader. */
+} tftp_dfu_image_type_t;
+
+/**@brief Static data used by TFTP DFU module. */
+typedef struct
+{
+ iot_tftp_t tftp; /**< TFTP instance. */
+ char resource_path[MAX_LENGTH_FILENAME]; /**< Path of remote resource to get. */
+ uint32_t block_number; /**< Number of block that will be passed to background DFU module. */
+ uint8_t block[DEFAULT_BLOCK_SIZE]; /**< Buffer for parts of blocks to pass to background DFU module. */
+ uint16_t block_size; /**< Size of data in block buffer. */
+ tftp_dfu_image_type_t image_type; /**< Type of image that is currently updated. */
+ iot_file_t config_file; /**< Pointer to the file used for config of DFU. */
+ uint8_t config_mem[MAX_CONFIG_SIZE]; /**< Static memory for configuration file. */
+ cJSON * p_config_json; /**< Pointer of cJSON instance. */
+ iot_dfu_firmware_desc_t firmware_desc; /**< Details from configuration file. */
+} tftp_dfu_context_t;
+
+static background_dfu_context_t m_dfu_ctx; /**< Background DFU context. */
+static tftp_dfu_context_t m_tftp_dfu_ctx; /**< TFTP DFU context. */
+
+/***************************************************************************************************
+ * @section Common operations
+ **************************************************************************************************/
+
+/**@brief Set resource path to trigger (config) file. */
+static void trigger_path_set(void)
+{
+ int retval = snprintf(m_tftp_dfu_ctx.resource_path,
+ sizeof(m_tftp_dfu_ctx.resource_path),
+ "/dfu/c/%d/%d",
+ DFU_DEVICE_INFO->device_type,
+ DFU_DEVICE_INFO->device_rev);
+ if (retval < 0) {
+ NRF_LOG_ERROR("Failed to set path using snprintf, retval: %d", retval);
+ }
+}
+
+/**@brief Function for reading binary path from JSON configuration.
+ *
+ * @param[out] p_dst_str Pointer to memory, where path should be stored.
+ * @param[in] p_key Key inside JSON configuration file, describing firmware.
+ *
+ * @return NRF_SUCCESS if path found and stored in p_dst_str, otherwise error code.
+ */
+static uint32_t get_path(char * p_dst_str, const char * p_key)
+{
+ cJSON * p_cursor;
+
+ if ((m_tftp_dfu_ctx.p_config_json == NULL) || (p_dst_str == NULL))
+ {
+ NRF_LOG_ERROR("Invalid parameters");
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ p_cursor = cJSON_GetObjectItem(m_tftp_dfu_ctx.p_config_json, CONFIG_PATH_KEY);
+ if (p_cursor != NULL)
+ {
+ p_cursor = cJSON_GetObjectItem(p_cursor, (const char *)p_key);
+ if ((p_cursor != NULL) && (p_cursor->type == cJSON_String))
+ {
+ memcpy(p_dst_str, p_cursor->valuestring, strlen(p_cursor->valuestring));
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ return NRF_SUCCESS;
+}
+
+/**@brief Function for reading init binary path from JSON configuration.
+ *
+ * @param[out] p_dst_str Pointer to memory, where path should be stored.
+ * @param[in] p_key Key inside JSON configuration file, describing firmware.
+ *
+ * @return NRF_SUCCESS if path found and stored in p_dst_str, otherwise error code.
+ */
+static uint32_t get_init_path(char * p_dst_str, const char * p_key)
+{
+ cJSON * p_cursor;
+
+ if ((m_tftp_dfu_ctx.p_config_json == NULL) || (p_dst_str == NULL))
+ {
+ NRF_LOG_ERROR("Invalid parameters");
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ p_cursor = cJSON_GetObjectItem(m_tftp_dfu_ctx.p_config_json, CONFIG_INIT_PATH_KEY);
+ if (p_cursor != NULL)
+ {
+ p_cursor = cJSON_GetObjectItem(p_cursor, (const char *)p_key);
+ if ((p_cursor != NULL) && (p_cursor->type == cJSON_String))
+ {
+ memcpy(p_dst_str, p_cursor->valuestring, strlen(p_cursor->valuestring));
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+ }
+ else
+ {
+ return NRF_ERROR_INVALID_PARAM;
+ }
+
+ return NRF_SUCCESS;
+}
+
+/**@brief Function for parsing JSON file to get details of an application.
+ *
+ * @param[in] p_key Key inside JSON configuration file, describing firmware.
+ * @param[out] p_block Pointer to structure containing description of single block of firmware.
+ *
+ * @returns NRF_SUCCESS if correctly parsed data. Otherwise an error code indicating failure reason.
+ */
+static uint32_t details_parse(const char * p_key, iot_dfu_firmware_block_t * p_block)
+{
+ cJSON * p_cursor;
+ cJSON * p_cursor_back;
+
+ // Clear output parameters.
+ memset(p_block, 0, sizeof(*p_block));
+
+ if (m_tftp_dfu_ctx.p_config_json == NULL)
+ {
+ NRF_LOG_ERROR("Invalid JSON file");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_cursor = cJSON_GetObjectItem(m_tftp_dfu_ctx.p_config_json, (const char *)p_key);
+ if (p_cursor != NULL)
+ {
+ p_cursor_back = p_cursor;
+ p_cursor = cJSON_GetObjectItem(p_cursor, CONFIG_ID_KEY);
+ if (p_cursor != NULL)
+ {
+ if (p_cursor->type != cJSON_Number)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_block->crc = p_cursor->valueint;
+ }
+ else
+ {
+ NRF_LOG_ERROR("No binary ID inside JSON.");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_cursor = p_cursor_back;
+ p_cursor = cJSON_GetObjectItem(p_cursor, CONFIG_INIT_SIZE_KEY);
+ if (p_cursor != NULL)
+ {
+ if (p_cursor->type != cJSON_Number)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_block->init_size = p_cursor->valueint;
+ }
+ else
+ {
+ NRF_LOG_ERROR("No init SIZE inside JSON.");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_cursor = p_cursor_back;
+ p_cursor = cJSON_GetObjectItem(p_cursor, CONFIG_INIT_ID_KEY);
+ if (p_cursor != NULL)
+ {
+ if (p_cursor->type != cJSON_Number)
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_block->init_crc = p_cursor->valueint;
+ }
+ else
+ {
+ NRF_LOG_ERROR("No init ID inside JSON.");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_cursor = p_cursor_back;
+ p_cursor = cJSON_GetObjectItem(p_cursor, CONFIG_SIZE_KEY);
+ if (p_cursor != NULL)
+ {
+ if ((p_cursor->type != cJSON_Number) || (p_cursor->valueint == 0))
+ {
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ p_block->size = p_cursor->valueint;
+ }
+ else
+ {
+ NRF_LOG_ERROR("No binary SIZE inside JSON.");
+ return NRF_ERROR_INVALID_DATA;
+ }
+ }
+ else
+ {
+ NRF_LOG_ERROR("No binary KEY inside JSON.");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for parsing and processing config file.
+ *
+ * @param[out] p_dfu_firmware_desc Details of available firmware images (size and CRC)
+ * @param[out] p_filename Remote path to init file that should be downloaded in DFU process
+ *
+ * @return NRF_SUCCESS If config file is valid. Otherwise an error code indicating failure reason.
+ */
+static uint32_t app_dfu_config_process(iot_dfu_firmware_desc_t * p_dfu_firmware_desc,
+ char * p_filename)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ iot_dfu_firmware_block_t app;
+#if TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+ iot_dfu_firmware_block_t sd;
+ iot_dfu_firmware_block_t bl;
+#endif // TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+ bool app_present = false;
+#if TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+ bool sd_present = false;
+ bool bl_present = false;
+#endif // TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+
+ // Clear global parameters before parsing a new one.
+ memset(p_filename, 0, MAX_LENGTH_FILENAME);
+
+ m_tftp_dfu_ctx.p_config_json = cJSON_Parse((const char *)m_tftp_dfu_ctx.config_mem);
+ if (m_tftp_dfu_ctx.p_config_json == NULL)
+ {
+ NRF_LOG_ERROR("JSON parse failed.");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+#if TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+ if (details_parse(CONFIG_SD_KEY, &sd) == NRF_SUCCESS)
+ {
+ sd_present = true;
+ }
+
+ if (details_parse(CONFIG_BL_KEY, &bl) == NRF_SUCCESS)
+ {
+ bl_present = true;
+ }
+#endif // TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+
+ if (details_parse(CONFIG_APP_KEY, &app) == NRF_SUCCESS)
+ {
+ app_present = true;
+ }
+
+#if TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+ // Background DFU does not support SoftDevice or bootloader update yet.
+ if ((sd_present) && (app_present))
+ {
+ NRF_LOG_INFO("Update Softdevice with Application.");
+ m_tftp_dfu_ctx.image_type = TFTP_DFU_IMAGE_TYPE_SOFTDEVICE;
+ }
+ else if (bl_present)
+ {
+ NRF_LOG_INFO("Update Bootloader.");
+ m_tftp_dfu_ctx.image_type = TFTP_DFU_IMAGE_TYPE_BOOTLOADER;
+ }
+ else
+#endif // TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+ {
+ if (app_present)
+ {
+ NRF_LOG_INFO("Update Application only.");
+ m_tftp_dfu_ctx.image_type = TFTP_DFU_IMAGE_TYPE_APPLICATION;
+ }
+ else
+ {
+ // This example application does not implement SoftDevice with Bootloader update
+ NRF_LOG_INFO("Device firmware up to date.");
+ err_code = NRF_ERROR_NOT_FOUND;
+ }
+ }
+
+ if (err_code == NRF_SUCCESS)
+ {
+ switch (m_tftp_dfu_ctx.image_type)
+ {
+ case TFTP_DFU_IMAGE_TYPE_APPLICATION:
+ err_code = get_init_path(p_filename, CONFIG_APP_KEY);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_dfu_firmware_desc->application = app;
+ }
+
+ break;
+
+#if TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+ case TFTP_DFU_IMAGE_TYPE_BOOTLOADER:
+ err_code = get_init_path(p_filename, CONFIG_BL_KEY);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_dfu_firmware_desc->bootloader = bl;
+ }
+
+ break;
+
+ case TFTP_DFU_IMAGE_TYPE_SOFTDEVICE:
+ err_code = get_init_path(p_filename, CONFIG_APPSD_KEY);
+ if (err_code == NRF_SUCCESS)
+ {
+ p_dfu_firmware_desc->softdevice = sd;
+ p_dfu_firmware_desc->application = app;
+ }
+
+ break;
+#endif // TFTP_SOFTDEVICE_UPGRADE_SUPPORT
+
+ default:
+ ASSERT(false);
+ }
+ }
+
+ if (p_filename[0] == '\0')
+ {
+ NRF_LOG_ERROR("File name has not be found.");
+ err_code = NRF_ERROR_INVALID_PARAM;
+ }
+
+ cJSON_Delete(m_tftp_dfu_ctx.p_config_json);
+
+ return err_code;
+}
+
+/** @brief Set resource path to point to firmware binary file.
+ *
+ * @param [out] p_filename Pointer to resource path.
+ *
+ * @return NRF_SUCCESS if setting firmware path succeeded or error code indicating failure reason.
+ */
+static uint32_t set_firmware_path(char * p_filename)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ m_tftp_dfu_ctx.p_config_json = cJSON_Parse((const char *)m_tftp_dfu_ctx.config_mem);
+ if (m_tftp_dfu_ctx.p_config_json == NULL)
+ {
+ NRF_LOG_ERROR("JSON parse failed.");
+ return NRF_ERROR_INVALID_DATA;
+ }
+
+ switch (m_tftp_dfu_ctx.image_type)
+ {
+ case TFTP_DFU_IMAGE_TYPE_APPLICATION:
+ err_code = get_path(p_filename, CONFIG_APP_KEY);
+ break;
+
+ case TFTP_DFU_IMAGE_TYPE_BOOTLOADER:
+ err_code = get_path(p_filename, CONFIG_BL_KEY);
+ break;
+
+ case TFTP_DFU_IMAGE_TYPE_SOFTDEVICE:
+ err_code = get_path(p_filename, CONFIG_APPSD_KEY);
+ break;
+
+ default:
+ ASSERT(false);
+ }
+
+ if (p_filename[0] == '\0')
+ {
+ NRF_LOG_ERROR("File name has not be found.");
+ err_code = NRF_ERROR_INVALID_PARAM;
+ }
+
+ cJSON_Delete(m_tftp_dfu_ctx.p_config_json);
+
+ return err_code;
+}
+
+/** @brief Send download request to the TFTP server.
+ *
+ * @param[in] p_file Pointer to file instance used to store file. May be NULL if file is not
+ * stored by TFTP module.
+ */
+static void send_request(iot_file_t * p_file)
+{
+ uint32_t err_code;
+ iot_tftp_trans_params_t trans_params;
+
+ trans_params.block_size = APP_TFTP_BLOCK_SIZE;
+ trans_params.next_retr = APP_TFTP_RETRANSMISSION_TIME;
+
+ err_code = iot_tftp_set_params(&m_tftp_dfu_ctx.tftp, &trans_params);
+ ASSERT(err_code == NRF_SUCCESS);
+
+ err_code = iot_tftp_get(&m_tftp_dfu_ctx.tftp, p_file, m_tftp_dfu_ctx.resource_path);
+ ASSERT(err_code == NRF_SUCCESS);
+
+ UNUSED_VARIABLE(err_code);
+}
+
+/***************************************************************************************************
+ * @section TFTP handler
+ **************************************************************************************************/
+
+/**
+ * @brief Process retrieved config file
+ *
+ * @param[in] p_file Pointer to retrieved config file.
+ */
+static void config_file_retrieved(iot_file_t * p_file)
+{
+ uint32_t err_code;
+ background_dfu_trigger_t trigger;
+ iot_dfu_firmware_block_t * p_firmware_block = NULL;
+
+ NRF_LOG_INFO("Config file successfully downloaded.");
+
+ m_tftp_dfu_ctx.config_mem[p_file->file_size] = 0;
+ memset(&m_tftp_dfu_ctx.firmware_desc, 0, sizeof(m_tftp_dfu_ctx.firmware_desc));
+
+ err_code = app_dfu_config_process(&m_tftp_dfu_ctx.firmware_desc, m_tftp_dfu_ctx.resource_path);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ NRF_LOG_INFO("New sofware available. Starting downloading procedure.");
+
+ switch(m_tftp_dfu_ctx.image_type)
+ {
+ case TFTP_DFU_IMAGE_TYPE_APPLICATION:
+ p_firmware_block = &m_tftp_dfu_ctx.firmware_desc.application;
+ break;
+
+ case TFTP_DFU_IMAGE_TYPE_BOOTLOADER:
+ p_firmware_block = &m_tftp_dfu_ctx.firmware_desc.bootloader;
+ break;
+
+ case TFTP_DFU_IMAGE_TYPE_SOFTDEVICE:
+ p_firmware_block = &m_tftp_dfu_ctx.firmware_desc.softdevice;
+ break;
+ }
+
+ memset(&trigger, 0, sizeof(trigger));
+ trigger.init_length = uint32_big_decode((const uint8_t *)&p_firmware_block->init_size);
+ trigger.init_crc = uint32_big_decode((const uint8_t *)&p_firmware_block->init_crc);
+ trigger.image_length = uint32_big_decode((const uint8_t *)&p_firmware_block->size);
+ trigger.image_crc = uint32_big_decode((const uint8_t *)&p_firmware_block->crc);
+
+ if (background_dfu_validate_trigger(&m_dfu_ctx, (uint8_t *)&trigger, sizeof(trigger)))
+ {
+ if (!background_dfu_process_trigger(&m_dfu_ctx, (uint8_t *)&trigger, sizeof(trigger)))
+ {
+ NRF_LOG_ERROR("Error in TFTP background_dfu_process_trigger");
+ }
+
+ if (m_dfu_ctx.dfu_state == BACKGROUND_DFU_IDLE)
+ {
+ // State in DFU_IDLE, nothing to download.
+ err_code = iot_tftp_uninit(&m_tftp_dfu_ctx.tftp);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in TFTP uninit (%d)", err_code);
+ }
+ }
+ }
+ }
+ else
+ {
+ NRF_LOG_INFO("No new sofware available or incorrect JSON file.");
+ }
+}
+
+/**
+ * @brief Pass block of retrieved data to background DFU module.
+ *
+ * @param[in] p_block Pointer to block of retrieved data.
+ */
+static void process_block(uint8_t * p_block)
+{
+ background_dfu_block_t block;
+ background_dfu_block_result_t result;
+
+ block.number = m_tftp_dfu_ctx.block_number;
+ block.size = DEFAULT_BLOCK_SIZE;
+ block.p_payload = p_block;
+
+ m_tftp_dfu_ctx.block_number++;
+
+ result = background_dfu_process_block(&m_dfu_ctx, &block);
+ if (result != BACKGROUND_DFU_BLOCK_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in TFTP background_dfu_process_block (%d)", result);
+ }
+}
+
+/**
+ * @brief Process retrieved data chunk.
+ *
+ * Split retrieved data to blocks of DEFAULT_BLOCK_SIZE bytes and pass to DFU module.
+ *
+ * @param[in] p_data_received Pointer to structure describing received data chunk.
+ */
+static void data_chunk_retrieved(iot_tftp_evt_data_received_t * p_data_received)
+{
+ uint16_t processed_bytes = 0;
+
+ // Process part of block from previous chunk
+ if (m_tftp_dfu_ctx.block_size)
+ {
+ uint16_t first_block_missing_size = DEFAULT_BLOCK_SIZE - m_tftp_dfu_ctx.block_size;
+
+ if (p_data_received->size < first_block_missing_size)
+ {
+ first_block_missing_size = p_data_received->size;
+ }
+
+ memcpy(&m_tftp_dfu_ctx.block[m_tftp_dfu_ctx.block_size],
+ p_data_received->p_data,
+ first_block_missing_size);
+
+ process_block(m_tftp_dfu_ctx.block);
+
+ processed_bytes = first_block_missing_size;
+ }
+
+ // Process received chunks
+ while (p_data_received->size - processed_bytes >= DEFAULT_BLOCK_SIZE)
+ {
+ process_block(&p_data_received->p_data[processed_bytes]);
+ processed_bytes += DEFAULT_BLOCK_SIZE;
+ }
+
+ m_tftp_dfu_ctx.block_size = p_data_received->size - processed_bytes;
+
+ // Leave not processed data
+ if (p_data_received->size > processed_bytes)
+ {
+ memcpy(m_tftp_dfu_ctx.block,
+ &p_data_received->p_data[processed_bytes],
+ m_tftp_dfu_ctx.block_size);
+ }
+}
+
+/**
+ * @brief Process data left from previous chunk.
+ */
+static void preserved_block_process(void)
+{
+ process_block(m_tftp_dfu_ctx.block);
+ m_tftp_dfu_ctx.block_size = 0;
+}
+
+/**
+ * @brief Handler of TFTP events.
+ */
+static void tftp_dfu_tftp_handler(iot_tftp_t * p_tftp, iot_tftp_evt_t * p_evt)
+{
+ switch (p_evt->id)
+ {
+ case IOT_TFTP_EVT_TRANSFER_DATA_RECEIVED:
+ switch (m_dfu_ctx.dfu_state)
+ {
+ case BACKGROUND_DFU_DOWNLOAD_TRIG:
+ break;
+
+ case BACKGROUND_DFU_DOWNLOAD_INIT_CMD:
+ case BACKGROUND_DFU_DOWNLOAD_FIRMWARE:
+ data_chunk_retrieved(&p_evt->param.data_received);
+ break;
+
+ default:
+ ASSERT(false);
+ break;
+ }
+ break;
+
+ case IOT_TFTP_EVT_TRANSFER_GET_COMPLETE:
+ switch (m_dfu_ctx.dfu_state)
+ {
+ case BACKGROUND_DFU_DOWNLOAD_TRIG:
+ config_file_retrieved(p_evt->p_file);
+ break;
+
+ case BACKGROUND_DFU_DOWNLOAD_INIT_CMD:
+ case BACKGROUND_DFU_DOWNLOAD_FIRMWARE:
+ preserved_block_process();
+ break;
+
+ default:
+ ASSERT(false);
+ break;
+ }
+ break;
+
+ case IOT_TFTP_EVT_ERROR:
+ background_dfu_handle_error();
+ break;
+
+ default:
+ ASSERT(false);
+ break;
+ }
+}
+
+static void dfu_observer(nrf_dfu_evt_type_t evt_type)
+{
+ switch (evt_type)
+ {
+ case NRF_DFU_EVT_DFU_COMPLETED:
+ NRF_LOG_FINAL_FLUSH();
+
+#if NRF_MODULE_ENABLED(NRF_LOG_BACKEND_RTT)
+ // To allow the buffer to be flushed by the host.
+ nrf_delay_ms(100);
+#endif
+
+ NVIC_SystemReset();
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/***************************************************************************************************
+ * @section Private API
+ **************************************************************************************************/
+
+void background_dfu_transport_block_request_send(background_dfu_context_t * p_dfu_ctx,
+ background_dfu_request_bitmap_t * p_req_bmp)
+{
+ // Intentionally empty: multicast DFU not implemented.
+}
+
+void background_dfu_transport_send_request(background_dfu_context_t * p_dfu_ctx)
+{
+ switch (m_dfu_ctx.dfu_state)
+ {
+ case BACKGROUND_DFU_DOWNLOAD_TRIG:
+ send_request(&m_tftp_dfu_ctx.config_file);
+ break;
+
+ default:
+ // In other states download operation is triggered by state_update() notification.
+ break;
+ }
+}
+
+void background_dfu_transport_state_update(background_dfu_context_t * p_dfu_ctx)
+{
+ switch (p_dfu_ctx->dfu_state)
+ {
+ case BACKGROUND_DFU_DOWNLOAD_TRIG:
+ trigger_path_set();
+ break;
+
+ case BACKGROUND_DFU_DOWNLOAD_INIT_CMD:
+ m_tftp_dfu_ctx.block_number = 0;
+ m_tftp_dfu_ctx.block_size = 0;
+ send_request(NULL);
+ break;
+
+ case BACKGROUND_DFU_DOWNLOAD_FIRMWARE:
+ m_tftp_dfu_ctx.block_number = 0;
+ m_tftp_dfu_ctx.block_size = 0;
+ UNUSED_RETURN_VALUE(set_firmware_path(m_tftp_dfu_ctx.resource_path));
+ send_request(NULL);
+ break;
+
+ case BACKGROUND_DFU_WAIT_FOR_RESET:
+ // Do nothing.
+ break;
+
+ default:
+ NRF_LOG_WARNING("Unhandled state in background_dfu_transport_state_update (s: %s).",
+ (uint32_t)background_dfu_state_to_string(p_dfu_ctx->dfu_state));
+ }
+}
+
+uint32_t background_dfu_random(void)
+{
+ // Intentionally empty: multicast DFU not implemented.
+ return 0;
+}
+
+/***************************************************************************************************
+ * @section Public API
+ **************************************************************************************************/
+
+uint32_t tftp_dfu_init(void)
+{
+ uint32_t err_code = NRF_SUCCESS;
+
+ memset(&m_tftp_dfu_ctx, 0, sizeof(m_tftp_dfu_ctx));
+
+ err_code = nrf_dfu_settings_init(true);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ err_code = nrf_dfu_req_handler_init(dfu_observer);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ background_dfu_state_init(&m_dfu_ctx);
+
+ cJSON_Init();
+
+ // Initialize file static instance.
+ IOT_FILE_STATIC_INIT(&m_tftp_dfu_ctx.config_file,
+ m_tftp_dfu_ctx.resource_path,
+ m_tftp_dfu_ctx.config_mem,
+ MAX_CONFIG_SIZE);
+
+ return err_code;
+}
+
+uint32_t tftp_dfu_trigger(const ipv6_addr_t * p_host_ipv6, uint16_t src_port, uint16_t dst_port)
+{
+ uint32_t err_code;
+ iot_tftp_init_t tftp_init_params;
+
+ NRF_LOG_INFO("Triggering DFU");
+
+ if (p_host_ipv6 == NULL)
+ {
+ NRF_LOG_WARNING("NULL IPv6 address");
+ return NRF_ERROR_NULL;
+ }
+
+ if (m_dfu_ctx.dfu_state != BACKGROUND_DFU_IDLE)
+ {
+ NRF_LOG_WARNING("Invalid state");
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ // Set TFTP configuration
+ memset(&tftp_init_params, 0, sizeof(iot_tftp_init_t));
+ tftp_init_params.p_ipv6_addr = (ipv6_addr_t *)p_host_ipv6;
+ tftp_init_params.src_port = src_port;
+ tftp_init_params.dst_port = dst_port;
+ tftp_init_params.callback = tftp_dfu_tftp_handler;
+
+ // Initialize instance, bind socket, check parameters.
+ err_code = iot_tftp_init(&m_tftp_dfu_ctx.tftp, &tftp_init_params);
+ if (err_code != NRF_SUCCESS)
+ {
+ NRF_LOG_ERROR("Error in TFTP init (%d)", err_code);
+ return err_code;
+ }
+
+ trigger_path_set();
+
+ // Transition from DFU_IDLE to DFU_DOWNLOAD_TRIG.
+ return background_dfu_handle_event(&m_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE);
+}
+
+void background_dfu_handle_error(void)
+{
+ UNUSED_RETURN_VALUE(iot_tftp_uninit(&m_tftp_dfu_ctx.tftp));
+ tftp_dfu_handle_error();
+}
+
+__WEAK void tftp_dfu_handle_error(void)
+{
+
+}
+
+bool nrf_dfu_button_enter_check(void)
+{
+ // Dummy function for Keil compilation. This should not be called.
+ return false;
+}
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.h
new file mode 100644
index 0000000..6c8370b
--- /dev/null
+++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/iot/background_dfu/transport/tftp/tftp_dfu.h
@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2017 - 2018, 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.
+ *
+ */
+
+/** @file tftp_dfu.h
+ *
+ * @defgroup tftp_dfu TFTP transport for Background DFU
+ * @ingroup iot_tftp_dfu
+ * @{
+ * @brief TFTP transport for Background DFU.
+ *
+ */
+
+#ifndef TFTP_DFU_H_
+#define TFTP_DFU_H_
+
+#include <stdint.h>
+#include "iot_defines.h"
+
+/** @brief Initialize DFU client.
+ *
+ * @returns NRF_SUCCESS if DFU procedure started. Otherwise an error code indicating problem.
+ */
+uint32_t tftp_dfu_init(void);
+
+/** @brief Trigger DFU.
+ *
+ * @param[in] p_host_ipv6 IPv6 address of TFTP host.
+ * @param[in] src_port Source UDP port used by TFTP service.
+ * @param[in] dst_port Destination UDP port used by TFTP service.
+ *
+ * @returns NRF_SUCCESS if DFU procedure started. Otherwise an error code indicating problem.
+ */
+uint32_t tftp_dfu_trigger(const ipv6_addr_t * p_host_ipv6, uint16_t src_port, uint16_t dst_port);
+
+/** @brief Handle DFU error.
+ *
+ * This function can be implemented in the application to undertake application-specific action on DFU error.
+ */
+extern void tftp_dfu_handle_error(void);
+
+#endif /* TFTP_DFU_H_ */
+
+/** @} */