summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorroot <root@no.no.james.local>2015-09-01 13:12:02 +0100
committerroot <root@no.no.james.local>2015-09-01 13:12:02 +0100
commitb31e97e4b49b3c8582c85d1fdccfabe41de02dc5 (patch)
tree1e29ede47a988cda9c85ddc69dffcd69395ded47
parent261436d22bc93338e08e67956a47142e3b0d5086 (diff)
downloadbootloader-b31e97e4b49b3c8582c85d1fdccfabe41de02dc5.tar.gz
bootloader-b31e97e4b49b3c8582c85d1fdccfabe41de02dc5.tar.bz2
bootloader-b31e97e4b49b3c8582c85d1fdccfabe41de02dc5.zip
fish
-rw-r--r--Makefile5
-rw-r--r--sdk-config/sdk/libraries/bootloader_dfu/dfu_single_bank.c819
-rw-r--r--sdk-config/sdk/libraries/bootloader_dfu/dfu_transport_ble.c1109
3 files changed, 1931 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index 721f452..93edd60 100644
--- a/Makefile
+++ b/Makefile
@@ -27,9 +27,7 @@ SDKCSRCS= \
libraries/bootloader_dfu/bootloader_settings.c \
libraries/bootloader_dfu/bootloader_util.c \
libraries/crc16/crc16.c \
- libraries/bootloader_dfu/dfu_dual_bank.c \
libraries/bootloader_dfu/dfu_init_template.c \
- libraries/bootloader_dfu/dfu_transport_ble.c \
libraries/hci/hci_mem_pool.c \
libraries/util/nrf_assert.c \
drivers_nrf/hal/nrf_delay.c \
@@ -46,10 +44,13 @@ SDKSSRCS = toolchain/gcc/gcc_startup_nrf51.s
CSRCS = \
+ sdk-config/sdk/libraries/bootloader_dfu/dfu_single_bank.c \
+ sdk-config/sdk/libraries/bootloader_dfu/dfu_transport_ble.c \
dfu_ble_svc.c \
main.c
+
SOFTDEVICE=${SDK}/sdk/softdevice/s130/hex/s130_softdevice.hex
LINKER_SCRIPT=dfu_gcc_nrf51.ld #sdk/toolchain/gcc/s130.ld
diff --git a/sdk-config/sdk/libraries/bootloader_dfu/dfu_single_bank.c b/sdk-config/sdk/libraries/bootloader_dfu/dfu_single_bank.c
new file mode 100644
index 0000000..7c8368c
--- /dev/null
+++ b/sdk-config/sdk/libraries/bootloader_dfu/dfu_single_bank.c
@@ -0,0 +1,819 @@
+/* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+#include <sdk/libraries/bootloader_dfu/dfu.h>
+#include <sdk/libraries/bootloader_dfu/dfu_types.h>
+#include <sdk/libraries/bootloader_dfu/dfu_bank_internal.h>
+#include <sdk/device/nrf.h>
+#include <sdk/device/nrf51.h>
+#include <sdk/device/nrf51_bitfields.h>
+#include <sdk/libraries/util/app_util.h>
+#include <sdk/softdevice/s130/headers/nrf_sdm.h>
+#include <sdk/libraries/util/app_error.h>
+#include <sdk/softdevice/s130/headers/nrf_error.h>
+#include <sdk/libraries/timer/app_timer.h>
+#include <sdk/libraries/util/app_error.h>
+#include <sdk/libraries/util/nordic_common.h>
+#include <sdk/libraries/bootloader_dfu/bootloader.h>
+#include <sdk/libraries/bootloader_dfu/bootloader_types.h>
+#include <sdk/drivers_nrf/pstorage/pstorage.h>
+#include <sdk/softdevice/s130/headers/nrf_mbr.h>
+#include <sdk/libraries/bootloader_dfu/dfu_init.h>
+
+static dfu_state_t m_dfu_state; /**< Current DFU state. */
+static uint32_t m_image_size; /**< Size of the image that will be transmitted. */
+
+static dfu_start_packet_t m_start_packet; /**< Start packet received for this update procedure. Contains update mode and image sizes information to be used for image transfer. */
+static uint8_t m_init_packet[64]; /**< Init packet, can hold CRC, Hash, Signed Hash and similar, for image validation, integrety check and authorization checking. */
+static uint8_t m_init_packet_length; /**< Length of init packet received. */
+static uint16_t m_image_crc; /**< Calculated CRC of the image received. */
+
+static app_timer_id_t m_dfu_timer_id; /**< Application timer id. */
+static bool m_dfu_timed_out = false; /**< Boolean flag value for tracking DFU timer timeout state. */
+
+static pstorage_handle_t m_storage_handle_app; /**< Pstorage handle for the application area (bank 0). Bank used when updating a SoftDevice w/wo bootloader. Handle also used when swapping received application from bank 1 to bank 0. */
+static pstorage_handle_t * mp_storage_handle_active; /**< Pointer to the pstorage handle for the active bank for receiving of data packets. */
+
+static dfu_callback_t m_data_pkt_cb; /**< Callback from DFU Bank module for notification of asynchronous operation such as flash prepare. */
+static dfu_bank_func_t m_functions; /**< Structure holding operations for the selected update process. */
+
+
+/**@brief Function for handling callbacks from pstorage module.
+ *
+ * @details Handles pstorage results for clear and storage operation. For detailed description of
+ * the parameters provided with the callback, please refer to \ref pstorage_ntf_cb_t.
+ */
+static void pstorage_callback_handler(pstorage_handle_t * p_handle,
+ uint8_t op_code,
+ uint32_t result,
+ uint8_t * p_data,
+ uint32_t data_len)
+{
+ switch (op_code)
+ {
+ case PSTORAGE_STORE_OP_CODE:
+ if ((m_dfu_state == DFU_STATE_RX_DATA_PKT) && (m_data_pkt_cb != NULL))
+ {
+ m_data_pkt_cb(DATA_PACKET, result, p_data);
+ }
+ break;
+
+ case PSTORAGE_CLEAR_OP_CODE:
+ if (m_dfu_state == DFU_STATE_PREPARING)
+ {
+ m_functions.cleared();
+ m_dfu_state = DFU_STATE_RDY;
+ if (m_data_pkt_cb != NULL)
+ {
+ m_data_pkt_cb(START_PACKET, result, p_data);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ APP_ERROR_CHECK(result);
+}
+
+
+/**@brief Function for handling the DFU timeout.
+ *
+ * @param[in] p_context The timeout context.
+ */
+static void dfu_timeout_handler(void * p_context)
+{
+ UNUSED_PARAMETER(p_context);
+ dfu_update_status_t update_status;
+
+ m_dfu_timed_out = true;
+ update_status.status_code = DFU_TIMEOUT;
+
+ bootloader_dfu_update_process(update_status);
+}
+
+
+/**@brief Function for restarting the DFU Timer.
+ *
+ * @details This function will stop and restart the DFU timer. This function will be called by the
+ * functions handling any DFU packet received from the peer that is transferring a firmware
+ * image.
+ */
+static uint32_t dfu_timer_restart(void)
+{
+ if (m_dfu_timed_out)
+ {
+ // The DFU timer had already timed out.
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ uint32_t err_code = app_timer_stop(m_dfu_timer_id);
+ APP_ERROR_CHECK(err_code);
+
+ err_code = app_timer_start(m_dfu_timer_id, DFU_TIMEOUT_INTERVAL, NULL);
+ APP_ERROR_CHECK(err_code);
+
+ return err_code;
+}
+
+
+/**@brief Function for preparing of flash before receiving SoftDevice image.
+ *
+ * @details This function will erase current application area to ensure sufficient amount of
+ * storage for the SoftDevice image. Upon erase complete a callback will be done.
+ * See \ref dfu_bank_prepare_t for further details.
+ */
+static void dfu_prepare_func_app_erase(uint32_t image_size)
+{
+ uint32_t err_code;
+
+ mp_storage_handle_active = &m_storage_handle_app;
+
+ // Doing a SoftDevice update thus current application must be cleared to ensure enough space
+ // for new SoftDevice.
+ m_dfu_state = DFU_STATE_PREPARING;
+ err_code = pstorage_clear(&m_storage_handle_app, m_image_size);
+ APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for handling behaviour when clear operation has completed.
+ */
+static void dfu_cleared_func_app(void)
+{
+ dfu_update_status_t update_status = {DFU_BANK_0_ERASED, };
+ bootloader_dfu_update_process(update_status);
+}
+
+
+/**@brief Function for calculating storage offset for receiving SoftDevice image.
+ *
+ * @details When a new SoftDevice is received it will be temporary stored in flash before moved to
+ * address 0x0. In order to succesfully validate transfer and relocation it is important
+ * that temporary image and final installed image does not ovwerlap hence an offset must
+ * be calculated in case new image is larger than currently installed SoftDevice.
+ */
+uint32_t offset_calculate(uint32_t sd_image_size)
+{
+ uint32_t offset = 0;
+
+ if (m_start_packet.sd_image_size > DFU_BANK_0_REGION_START)
+ {
+ uint32_t page_mask = (CODE_PAGE_SIZE - 1);
+ uint32_t diff = m_start_packet.sd_image_size - DFU_BANK_0_REGION_START;
+
+ offset = diff & ~page_mask;
+
+ // Align offset to next page if image size is not page sized.
+ if ((diff & page_mask) > 0)
+ {
+ offset += CODE_PAGE_SIZE;
+ }
+ }
+
+ return offset;
+}
+
+
+/**@brief Function for activating received SoftDevice image.
+ *
+ * @note This function will not move the SoftDevice image.
+ * The bootloader settings will be marked as SoftDevice update complete and the swapping of
+ * current SoftDevice will occur after system reset.
+ *
+ * @return NRF_SUCCESS on success.
+ */
+static uint32_t dfu_activate_sd(void)
+{
+ dfu_update_status_t update_status;
+
+ update_status.status_code = DFU_UPDATE_SD_COMPLETE;
+ update_status.app_crc = m_image_crc;
+ update_status.sd_image_start = DFU_BANK_0_REGION_START;
+ update_status.sd_size = m_start_packet.sd_image_size;
+ update_status.bl_size = m_start_packet.bl_image_size;
+ update_status.app_size = m_start_packet.app_image_size;
+
+ bootloader_dfu_update_process(update_status);
+
+ return NRF_SUCCESS;
+}
+
+
+/**@brief Function for activating received Application image.
+ *
+ * @details This function will move the received application image fram swap (bank 1) to
+ * application area (bank 0).
+ *
+ * @return NRF_SUCCESS on success. Error code otherwise.
+ */
+static uint32_t dfu_activate_app(void)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ dfu_update_status_t update_status;
+
+ memset(&update_status, 0, sizeof(dfu_update_status_t ));
+ update_status.status_code = DFU_UPDATE_APP_COMPLETE;
+ update_status.app_crc = m_image_crc;
+ update_status.app_size = m_start_packet.app_image_size;
+
+ bootloader_dfu_update_process(update_status);
+
+ return err_code;
+}
+
+
+/**@brief Function for activating received Bootloader image.
+ *
+ * @note This function will not move the bootloader image.
+ * The bootloader settings will be marked as Bootloader update complete and the swapping of
+ * current bootloader will occur after system reset.
+ *
+ * @return NRF_SUCCESS on success.
+ */
+static uint32_t dfu_activate_bl(void)
+{
+ dfu_update_status_t update_status;
+
+ update_status.status_code = DFU_UPDATE_BOOT_COMPLETE;
+ update_status.app_crc = m_image_crc;
+ update_status.sd_size = m_start_packet.sd_image_size;
+ update_status.bl_size = m_start_packet.bl_image_size;
+ update_status.app_size = m_start_packet.app_image_size;
+
+ bootloader_dfu_update_process(update_status);
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t dfu_init(void)
+{
+ uint32_t err_code;
+ pstorage_module_param_t storage_module_param = {.cb = pstorage_callback_handler};
+
+ m_init_packet_length = 0;
+ m_image_crc = 0;
+
+ err_code = pstorage_register(&storage_module_param, &m_storage_handle_app);
+ if (err_code != NRF_SUCCESS)
+ {
+ m_dfu_state = DFU_STATE_INIT_ERROR;
+ return err_code;
+ }
+
+ m_storage_handle_app.block_id = DFU_BANK_0_REGION_START;
+
+ // Create the timer to monitor the activity by the peer doing the firmware update.
+ err_code = app_timer_create(&m_dfu_timer_id,
+ APP_TIMER_MODE_SINGLE_SHOT,
+ dfu_timeout_handler);
+ APP_ERROR_CHECK(err_code);
+
+ // Start the DFU timer.
+ err_code = app_timer_start(m_dfu_timer_id, DFU_TIMEOUT_INTERVAL, NULL);
+ APP_ERROR_CHECK(err_code);
+
+ m_data_received = 0;
+ m_dfu_state = DFU_STATE_IDLE;
+
+ return NRF_SUCCESS;
+}
+
+
+void dfu_register_callback(dfu_callback_t callback_handler)
+{
+ m_data_pkt_cb = callback_handler;
+}
+
+
+uint32_t dfu_start_pkt_handle(dfu_update_packet_t * p_packet)
+{
+ uint32_t err_code;
+
+ m_start_packet = *(p_packet->params.start_packet);
+
+ // Check that the requested update procedure is supported.
+ // Currently the following combinations are allowed:
+ // - Application
+ // - SoftDevice
+ // - Bootloader
+ // - SoftDevice with Bootloader
+ if (IS_UPDATING_APP(m_start_packet) &&
+ (IS_UPDATING_SD(m_start_packet) || IS_UPDATING_BL(m_start_packet)))
+ {
+ // App update is only supported independently.
+ return NRF_ERROR_NOT_SUPPORTED;
+ }
+
+ if (!(IS_WORD_SIZED(m_start_packet.sd_image_size) &&
+ IS_WORD_SIZED(m_start_packet.bl_image_size) &&
+ IS_WORD_SIZED(m_start_packet.app_image_size)))
+ {
+ // Image_sizes are not a multiple of 4 (word size).
+ return NRF_ERROR_NOT_SUPPORTED;
+ }
+
+ m_image_size = m_start_packet.sd_image_size + m_start_packet.bl_image_size +
+ m_start_packet.app_image_size;
+
+ if (m_start_packet.bl_image_size > DFU_BL_IMAGE_MAX_SIZE)
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ if (m_image_size > (DFU_IMAGE_MAX_SIZE_FULL))
+ {
+ return NRF_ERROR_DATA_SIZE;
+ }
+ m_functions.prepare = dfu_prepare_func_app_erase;
+ m_functions.cleared = dfu_cleared_func_app;
+
+ if (IS_UPDATING_SD(m_start_packet))
+ {
+ m_functions.activate = dfu_activate_sd;
+ }
+ else if (IS_UPDATING_BL(m_start_packet))
+ {
+ m_functions.activate = dfu_activate_bl;
+ }
+ else
+ {
+ m_functions.activate = dfu_activate_app;
+ }
+
+ switch (m_dfu_state)
+ {
+ case DFU_STATE_IDLE:
+ // Valid peer activity detected. Hence restart the DFU timer.
+ err_code = dfu_timer_restart();
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ m_functions.prepare(m_image_size);
+
+ break;
+
+ default:
+ err_code = NRF_ERROR_INVALID_STATE;
+ break;
+ }
+
+ return err_code;
+}
+
+
+uint32_t dfu_data_pkt_handle(dfu_update_packet_t * p_packet)
+{
+ uint32_t data_length;
+ uint32_t err_code;
+ uint32_t * p_data;
+
+ if (p_packet == NULL)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ // Check pointer alignment.
+ if (!is_word_aligned(p_packet->params.data_packet.p_data_packet))
+ {
+ // The p_data_packet is not word aligned address.
+ return NRF_ERROR_INVALID_ADDR;
+ }
+
+ switch (m_dfu_state)
+ {
+ case DFU_STATE_RDY:
+ case DFU_STATE_RX_INIT_PKT:
+ return NRF_ERROR_INVALID_STATE;
+
+ case DFU_STATE_RX_DATA_PKT:
+ data_length = p_packet->params.data_packet.packet_length * sizeof(uint32_t);
+
+ if ((m_data_received + data_length) > m_image_size)
+ {
+ // The caller is trying to write more bytes into the flash than the size provided to
+ // the dfu_image_size_set function. This is treated as a serious error condition and
+ // an unrecoverable one. Hence point the variable mp_app_write_address to the top of
+ // the flash area. This will ensure that all future application data packet writes
+ // will be blocked because of the above check.
+ m_data_received = 0xFFFFFFFF;
+
+ return NRF_ERROR_DATA_SIZE;
+ }
+
+ // Valid peer activity detected. Hence restart the DFU timer.
+ err_code = dfu_timer_restart();
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ p_data = (uint32_t *)p_packet->params.data_packet.p_data_packet;
+
+ err_code = pstorage_store(mp_storage_handle_active,
+ (uint8_t *)p_data,
+ data_length,
+ m_data_received);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ m_data_received += data_length;
+
+ if (m_data_received != m_image_size)
+ {
+ // The entire image is not received yet. More data is expected.
+ err_code = NRF_ERROR_INVALID_LENGTH;
+ }
+ else
+ {
+ // The entire image has been received. Return NRF_SUCCESS.
+ err_code = NRF_SUCCESS;
+ }
+ break;
+
+ default:
+ err_code = NRF_ERROR_INVALID_STATE;
+ break;
+ }
+
+ return err_code;
+}
+
+
+uint32_t dfu_init_pkt_complete(void)
+{
+ uint32_t err_code = NRF_ERROR_INVALID_STATE;
+
+ // DFU initialization has been done and a start packet has been received.
+ if (IMAGE_WRITE_IN_PROGRESS())
+ {
+ // Image write is already in progress. Cannot handle an init packet now.
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ if (m_dfu_state == DFU_STATE_RX_INIT_PKT)
+ {
+ err_code = dfu_init_prevalidate(m_init_packet, m_init_packet_length);
+ if (err_code == NRF_SUCCESS)
+ {
+ m_dfu_state = DFU_STATE_RX_DATA_PKT;
+ }
+ else
+ {
+ m_init_packet_length = 0;
+ }
+ }
+ return err_code;
+}
+
+
+uint32_t dfu_init_pkt_handle(dfu_update_packet_t * p_packet)
+{
+ uint32_t err_code = NRF_SUCCESS;
+ uint32_t length;
+
+ switch (m_dfu_state)
+ {
+ case DFU_STATE_RDY:
+ m_dfu_state = DFU_STATE_RX_INIT_PKT;
+ // When receiving init packet in state ready just update and fall through this case.
+
+ case DFU_STATE_RX_INIT_PKT:
+ // DFU initialization has been done and a start packet has been received.
+ if (IMAGE_WRITE_IN_PROGRESS())
+ {
+ // Image write is already in progress. Cannot handle an init packet now.
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ // Valid peer activity detected. Hence restart the DFU timer.
+ err_code = dfu_timer_restart();
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ length = p_packet->params.data_packet.packet_length * sizeof(uint32_t);
+ if ((m_init_packet_length + length) > sizeof(m_init_packet))
+ {
+ return NRF_ERROR_INVALID_LENGTH;
+ }
+
+ memcpy(&m_init_packet[m_init_packet_length],
+ &p_packet->params.data_packet.p_data_packet[0],
+ length);
+ m_init_packet_length += length;
+ break;
+
+ default:
+ // Either the start packet was not received or dfu_init function was not called before.
+ err_code = NRF_ERROR_INVALID_STATE;
+ break;
+ }
+
+ return err_code;
+}
+
+
+uint32_t dfu_image_validate()
+{
+ uint32_t err_code;
+
+ switch (m_dfu_state)
+ {
+ case DFU_STATE_RX_DATA_PKT:
+ // Check if the application image write has finished.
+ if (m_data_received != m_image_size)
+ {
+ // Image not yet fully transfered by the peer or the peer has attempted to write
+ // too much data. Hence the validation should fail.
+ err_code = NRF_ERROR_INVALID_STATE;
+ }
+ else
+ {
+ m_dfu_state = DFU_STATE_VALIDATE;
+
+ // Valid peer activity detected. Hence restart the DFU timer.
+ err_code = dfu_timer_restart();
+ if (err_code == NRF_SUCCESS)
+ {
+ err_code = dfu_init_postvalidate((uint8_t *)mp_storage_handle_active->block_id,
+ m_image_size);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ m_dfu_state = DFU_STATE_WAIT_4_ACTIVATE;
+ }
+ }
+ break;
+
+ default:
+ err_code = NRF_ERROR_INVALID_STATE;
+ break;
+ }
+
+ return err_code;
+}
+
+
+uint32_t dfu_image_activate()
+{
+ uint32_t err_code;
+
+ switch (m_dfu_state)
+ {
+ case DFU_STATE_WAIT_4_ACTIVATE:
+
+ // Stop the DFU Timer because the peer activity need not be monitored any longer.
+ err_code = app_timer_stop(m_dfu_timer_id);
+ APP_ERROR_CHECK(err_code);
+
+ err_code = m_functions.activate();
+ break;
+
+ default:
+ err_code = NRF_ERROR_INVALID_STATE;
+ break;
+ }
+
+ return err_code;
+}
+
+
+void dfu_reset(void)
+{
+ dfu_update_status_t update_status;
+
+ update_status.status_code = DFU_RESET;
+
+ bootloader_dfu_update_process(update_status);
+}
+
+
+static uint32_t dfu_compare_block(uint32_t * ptr1, uint32_t * ptr2, uint32_t len)
+{
+ sd_mbr_command_t sd_mbr_cmd;
+
+ sd_mbr_cmd.command = SD_MBR_COMMAND_COMPARE;
+ sd_mbr_cmd.params.compare.ptr1 = ptr1;
+ sd_mbr_cmd.params.compare.ptr2 = ptr2;
+ sd_mbr_cmd.params.compare.len = len / sizeof(uint32_t);
+
+ return sd_mbr_command(&sd_mbr_cmd);
+}
+
+
+static uint32_t dfu_copy_sd(uint32_t * src, uint32_t * dst, uint32_t len)
+{
+ sd_mbr_command_t sd_mbr_cmd;
+
+ sd_mbr_cmd.command = SD_MBR_COMMAND_COPY_SD;
+ sd_mbr_cmd.params.copy_sd.src = src;
+ sd_mbr_cmd.params.copy_sd.dst = dst;
+ sd_mbr_cmd.params.copy_sd.len = len / sizeof(uint32_t);
+
+ return sd_mbr_command(&sd_mbr_cmd);
+}
+
+
+static uint32_t dfu_sd_img_block_swap(uint32_t * src,
+ uint32_t * dst,
+ uint32_t len,
+ uint32_t block_size)
+{
+ // It is neccesarry to swap the new SoftDevice in 3 rounds to ensure correct copy of data
+ // and verifucation of data in case power reset occurs during write to flash.
+ // To ensure the robustness of swapping the images are compared backwards till start of
+ // image swap. If the back is identical everything is swapped.
+ uint32_t err_code = dfu_compare_block(src, dst, len);
+ if (err_code == NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ if ((uint32_t)dst > SOFTDEVICE_REGION_START)
+ {
+ err_code = dfu_sd_img_block_swap((uint32_t *)((uint32_t)src - block_size),
+ (uint32_t *)((uint32_t)dst - block_size),
+ block_size,
+ block_size);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ err_code = dfu_copy_sd(src, dst, len);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ return dfu_compare_block(src, dst, len);
+}
+
+
+uint32_t dfu_sd_image_swap(void)
+{
+ bootloader_settings_t boot_settings;
+
+ bootloader_settings_get(&boot_settings);
+
+ if (boot_settings.sd_image_size == 0)
+ {
+ return NRF_SUCCESS;
+ }
+
+ if ((SOFTDEVICE_REGION_START + boot_settings.sd_image_size) > boot_settings.sd_image_start)
+ {
+ uint32_t err_code;
+ uint32_t sd_start = SOFTDEVICE_REGION_START;
+ uint32_t block_size = (boot_settings.sd_image_start - sd_start) / 2;
+ uint32_t image_end = boot_settings.sd_image_start + boot_settings.sd_image_size;
+
+ uint32_t img_block_start = boot_settings.sd_image_start + 2 * block_size;
+ uint32_t sd_block_start = sd_start + 2 * block_size;
+
+ if (SD_SIZE_GET(MBR_SIZE) < boot_settings.sd_image_size)
+ {
+ // This will clear a page thus ensuring the old image is invalidated before swapping.
+ err_code = dfu_copy_sd((uint32_t *)(sd_start + block_size),
+ (uint32_t *)(sd_start + block_size),
+ sizeof(uint32_t));
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = dfu_copy_sd((uint32_t *)sd_start, (uint32_t *)sd_start, sizeof(uint32_t));
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+ }
+
+ return dfu_sd_img_block_swap((uint32_t *)img_block_start,
+ (uint32_t *)sd_block_start,
+ image_end - img_block_start,
+ block_size);
+ }
+ else
+ {
+ if (boot_settings.sd_image_size != 0)
+ {
+ return dfu_copy_sd((uint32_t *)boot_settings.sd_image_start,
+ (uint32_t *)SOFTDEVICE_REGION_START,
+ boot_settings.sd_image_size);
+ }
+ }
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t dfu_bl_image_swap(void)
+{
+ bootloader_settings_t bootloader_settings;
+ sd_mbr_command_t sd_mbr_cmd;
+
+ bootloader_settings_get(&bootloader_settings);
+
+ if (bootloader_settings.bl_image_size != 0)
+ {
+ uint32_t bl_image_start = (bootloader_settings.sd_image_size == 0) ?
+ DFU_BANK_0_REGION_START :
+ bootloader_settings.sd_image_start +
+ bootloader_settings.sd_image_size;
+
+ sd_mbr_cmd.command = SD_MBR_COMMAND_COPY_BL;
+ sd_mbr_cmd.params.copy_bl.bl_src = (uint32_t *)(bl_image_start);
+ sd_mbr_cmd.params.copy_bl.bl_len = bootloader_settings.bl_image_size / sizeof(uint32_t);
+
+ return sd_mbr_command(&sd_mbr_cmd);
+ }
+ return NRF_SUCCESS;
+}
+
+
+uint32_t dfu_bl_image_validate(void)
+{
+ bootloader_settings_t bootloader_settings;
+ sd_mbr_command_t sd_mbr_cmd;
+
+ bootloader_settings_get(&bootloader_settings);
+
+ if (bootloader_settings.bl_image_size != 0)
+ {
+ uint32_t bl_image_start = (bootloader_settings.sd_image_size == 0) ?
+ DFU_BANK_0_REGION_START :
+ bootloader_settings.sd_image_start +
+ bootloader_settings.sd_image_size;
+
+ sd_mbr_cmd.command = SD_MBR_COMMAND_COMPARE;
+ sd_mbr_cmd.params.compare.ptr1 = (uint32_t *)BOOTLOADER_REGION_START;
+ sd_mbr_cmd.params.compare.ptr2 = (uint32_t *)(bl_image_start);
+ sd_mbr_cmd.params.compare.len = bootloader_settings.bl_image_size / sizeof(uint32_t);
+
+ return sd_mbr_command(&sd_mbr_cmd);
+ }
+ return NRF_SUCCESS;
+}
+
+
+uint32_t dfu_sd_image_validate(void)
+{
+ bootloader_settings_t bootloader_settings;
+ sd_mbr_command_t sd_mbr_cmd;
+
+ bootloader_settings_get(&bootloader_settings);
+
+ if (bootloader_settings.sd_image_size == 0)
+ {
+ return NRF_SUCCESS;
+ }
+
+ if ((SOFTDEVICE_REGION_START + bootloader_settings.sd_image_size) > bootloader_settings.sd_image_start)
+ {
+ uint32_t sd_start = SOFTDEVICE_REGION_START;
+ uint32_t block_size = (bootloader_settings.sd_image_start - sd_start) / 2;
+ uint32_t image_end = bootloader_settings.sd_image_start +
+ bootloader_settings.sd_image_size;
+
+ uint32_t img_block_start = bootloader_settings.sd_image_start + 2 * block_size;
+ uint32_t sd_block_start = sd_start + 2 * block_size;
+
+ if (SD_SIZE_GET(MBR_SIZE) < bootloader_settings.sd_image_size)
+ {
+ return NRF_ERROR_NULL;
+ }
+
+ return dfu_sd_img_block_swap((uint32_t *)img_block_start,
+ (uint32_t *)sd_block_start,
+ image_end - img_block_start,
+ block_size);
+ }
+
+ sd_mbr_cmd.command = SD_MBR_COMMAND_COMPARE;
+ sd_mbr_cmd.params.compare.ptr1 = (uint32_t *)SOFTDEVICE_REGION_START;
+ sd_mbr_cmd.params.compare.ptr2 = (uint32_t *)bootloader_settings.sd_image_start;
+ sd_mbr_cmd.params.compare.len = bootloader_settings.sd_image_size / sizeof(uint32_t);
+
+ return sd_mbr_command(&sd_mbr_cmd);
+}
diff --git a/sdk-config/sdk/libraries/bootloader_dfu/dfu_transport_ble.c b/sdk-config/sdk/libraries/bootloader_dfu/dfu_transport_ble.c
new file mode 100644
index 0000000..a8d53d2
--- /dev/null
+++ b/sdk-config/sdk/libraries/bootloader_dfu/dfu_transport_ble.c
@@ -0,0 +1,1109 @@
+/* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include <sdk/libraries/bootloader_dfu/dfu_transport.h>
+#include <sdk/libraries/bootloader_dfu/dfu.h>
+#include <sdk/libraries/bootloader_dfu/dfu_types.h>
+#include <stddef.h>
+#include <string.h>
+#include <bsp/boards.h>
+#include <sdk/device/nrf51.h>
+#include <sdk/softdevice/s130/headers/nrf_sdm.h>
+#include <sdk/drivers_nrf/hal/nrf_gpio.h>
+#include <sdk/libraries/util/app_util.h>
+#include <sdk/libraries/util/app_error.h>
+#include <sdk/softdevice/common/softdevice_handler/softdevice_handler.h>
+#include <sdk/softdevice/common/softdevice_handler/ble_stack_handler_types.h>
+#include <sdk/ble/common/ble_advdata.h>
+#include <sdk/softdevice/s130/headers/ble_l2cap.h>
+#include <sdk/softdevice/s130/headers/ble_gap.h>
+#include <sdk/softdevice/s130/headers/ble_gatt.h>
+#include <sdk/softdevice/s130/headers/ble_hci.h>
+#include <sdk/ble/ble_services/ble_dfu/ble_dfu.h>
+#include <sdk/libraries/util/nordic_common.h>
+#include <sdk/libraries/timer/app_timer.h>
+#include <sdk/ble/common/ble_conn_params.h>
+#include <sdk/libraries/hci/hci_mem_pool.h>
+#include <sdk/libraries/bootloader_dfu/bootloader.h>
+#include <sdk/libraries/bootloader_dfu/dfu_ble_svc_internal.h>
+#include <sdk/drivers_nrf/hal/nrf_delay.h>
+
+#define DFU_REV_MAJOR 0x00 /** DFU Major revision number to be exposed. */
+#define DFU_REV_MINOR 0x08 /** DFU Minor revision number to be exposed. */
+#define DFU_REVISION ((DFU_REV_MAJOR << 8) | DFU_REV_MINOR) /** DFU Revision number to be exposed. Combined of major and minor versions. */
+#define ADVERTISING_LED_PIN_NO BSP_LED_0 /**< Is on when device is advertising. */
+#define CONNECTED_LED_PIN_NO BSP_LED_1 /**< Is on when device has connected. */
+#define DFU_SERVICE_HANDLE 0x000C /**< Handle of DFU service when DFU service is first service initialized. */
+#define BLE_HANDLE_MAX 0xFFFF /**< Max handle value is BLE. */
+
+#define DEVICE_NAME "DfuTarg" /**< Name of device. Will be included in the advertising data. */
+#define MANUFACTURER_NAME "NordicSemiconductor" /**< Manufacturer. Will be passed to Device Information Service. */
+
+#define MIN_CONN_INTERVAL (uint16_t)(MSEC_TO_UNITS(15, UNIT_1_25_MS)) /**< Minimum acceptable connection interval (11.25 milliseconds). */
+#define MAX_CONN_INTERVAL (uint16_t)(MSEC_TO_UNITS(30, UNIT_1_25_MS)) /**< Maximum acceptable connection interval (15 milliseconds). */
+#define SLAVE_LATENCY 0 /**< Slave latency. */
+#define CONN_SUP_TIMEOUT (4 * 100) /**< Connection supervisory timeout (4 seconds). */
+
+#define APP_TIMER_PRESCALER 0 /**< Value of the RTC1 PRESCALER register. */
+
+#define FIRST_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(100, APP_TIMER_PRESCALER) /**< Time from the Connected event to first time sd_ble_gap_conn_param_update is called (100 milliseconds). */
+#define NEXT_CONN_PARAMS_UPDATE_DELAY APP_TIMER_TICKS(500, APP_TIMER_PRESCALER) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (500 milliseconds). */
+#define MAX_CONN_PARAMS_UPDATE_COUNT 3 /**< Number of attempts before giving up the connection parameter negotiation. */
+
+#define APP_ADV_INTERVAL MSEC_TO_UNITS(25, UNIT_0_625_MS) /**< The advertising interval (25 ms.). */
+#define APP_ADV_TIMEOUT_IN_SECONDS BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED /**< The advertising timeout in units of seconds. This is set to @ref BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED so that the advertisement is done as long as there there is a call to @ref dfu_transport_close function.*/
+#define APP_DIRECTED_ADV_TIMEOUT 50 /**< number of direct advertisement (each lasting 1.28seconds). */
+#define PEER_ADDRESS_TYPE_INVALID 0xFF /**< Value indicating that no valid peer address exists. This will be the case when a private resolvable address is used in which case there is no address available but instead an IRK is present. */
+#define PEER_ADDRESS_TYPE_INVALID 0xFF /**< Value indicating that no valid peer address exists. This will be the case when a private resolvable address is used in which case there is no address available but instead an IRK is present. */
+
+#define SEC_PARAM_TIMEOUT 30 /**< Timeout for Pairing Request or Security Request (in seconds). */
+#define SEC_PARAM_BOND 0 /**< Perform bonding. */
+#define SEC_PARAM_MITM 0 /**< Man In The Middle protection not required. */
+#define SEC_PARAM_IO_CAPABILITIES BLE_GAP_IO_CAPS_NONE /**< No I/O capabilities. */
+#define SEC_PARAM_OOB 0 /**< Out Of Band data not available. */
+#define SEC_PARAM_MIN_KEY_SIZE 7 /**< Minimum encryption key size. */
+#define SEC_PARAM_MAX_KEY_SIZE 16 /**< Maximum encryption key size. */
+
+#define MAX_SIZE_OF_BLE_STACK_EVT (sizeof(ble_evt_t) + BLE_L2CAP_MTU_DEF) /**< Maximum size (in bytes) of the event received from S110 SoftDevice.*/
+#define NUM_WORDS_RESERVED_FOR_BLE_EVENTS CEIL_DIV(MAX_SIZE_OF_BLE_STACK_EVT, sizeof(uint32_t)) /**< Size of the memory (in words) reserved for receiving S110 SoftDevice events. */
+
+#define IS_CONNECTED() (m_conn_handle != BLE_CONN_HANDLE_INVALID) /**< Macro to determine if the device is in connected state. */
+
+#define APP_FEATURE_NOT_SUPPORTED BLE_GATT_STATUS_ATTERR_APP_BEGIN + 2 /**< Reply when unsupported features are requested. */
+#define SD_IMAGE_SIZE_OFFSET 0 /**< Offset in start packet for the size information for SoftDevice. */
+#define BL_IMAGE_SIZE_OFFSET 4 /**< Offset in start packet for the size information for bootloader. */
+#define APP_IMAGE_SIZE_OFFSET 8 /**< Offset in start packet for the size information for application. */
+
+
+/**@brief Packet type enumeration.
+ */
+typedef enum
+{
+ PKT_TYPE_INVALID, /**< Invalid packet type. Used for initialization purpose.*/
+ PKT_TYPE_START, /**< Start packet.*/
+ PKT_TYPE_INIT, /**< Init packet.*/
+ PKT_TYPE_FIRMWARE_DATA /**< Firmware data packet.*/
+} pkt_type_t;
+
+static ble_gap_sec_params_t m_sec_params; /**< Security requirements for this application. */
+static ble_gap_adv_params_t m_adv_params; /**< Parameters to be passed to the stack when starting advertising. */
+static ble_dfu_t m_dfu; /**< Structure used to identify the Device Firmware Update service. */
+static pkt_type_t m_pkt_type; /**< Type of packet to be expected from the DFU Controller. */
+static uint8_t m_update_mode; /**< Type of update mode specified by the DFU Controller. */
+static uint32_t m_num_of_firmware_bytes_rcvd; /**< Cumulative number of bytes of firmware data received. */
+static uint16_t m_pkt_notif_target; /**< Number of packets of firmware data to be received before transmitting the next Packet Receipt Notification to the DFU Controller. */
+static uint16_t m_pkt_notif_target_cnt; /**< Number of packets of firmware data received after sending last Packet Receipt Notification or since the receipt of a @ref BLE_DFU_PKT_RCPT_NOTIF_ENABLED event from the DFU service, which ever occurs later.*/
+static uint8_t * mp_rx_buffer; /**< Pointer to a RX buffer.*/
+static bool m_tear_down_in_progress = false; /**< Variable to indicate whether a tear down is in progress. A tear down could be because the application has initiated it or the peer has disconnected. */
+static bool m_pkt_rcpt_notif_enabled = false; /**< Variable to denote whether packet receipt notification has been enabled by the DFU controller.*/
+static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; /**< Handle of the current connection. */
+static bool m_is_advertising = false; /**< Variable to indicate if advertising is ongoing.*/
+static dfu_ble_peer_data_t m_ble_peer_data; /**< BLE Peer data exchanged from application on buttonless update mode. */
+static bool m_ble_peer_data_valid = false; /**< True if BLE Peer data has been exchanged from application. */
+static uint32_t m_direct_adv_cnt = APP_DIRECTED_ADV_TIMEOUT; /**< Counter of direct advertisements. */
+static uint8_t * mp_final_packet; /**< Pointer to final data packet received. When callback for succesful packet handling is received from dfu bank handling a transfer complete response can be sent to peer. */
+
+
+/**@brief Function updating Service Changed CCCD and indicate a service change to peer.
+ *
+ * @details This function will verify the CCCD setting provided with \ref m_ble_peer_data and
+ * update the system attributes accordingly. If Service Change CCCD is set to indicate
+ * then a service change indication will be send to the peer.
+ *
+ * @retval NRF_INVALID_STATE if no connection has been established to a central.
+ * @return Any error code returned by SoftDevice function calls.
+ */
+static uint32_t service_change_indicate()
+{
+ uint32_t err_code;
+
+ if (m_conn_handle == BLE_CONN_HANDLE_INVALID)
+ {
+ return NRF_ERROR_INVALID_STATE;
+ }
+
+ if (m_ble_peer_data_valid)
+ {
+ err_code = sd_ble_gatts_sys_attr_set(m_conn_handle,
+ m_ble_peer_data.sys_serv_attr,
+ sizeof(m_ble_peer_data.sys_serv_attr),
+ BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = sd_ble_gatts_sys_attr_set(m_conn_handle,
+ NULL,
+ 0,
+ BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = sd_ble_gatts_service_changed(m_conn_handle, DFU_SERVICE_HANDLE, BLE_HANDLE_MAX);
+ if ((err_code == BLE_ERROR_INVALID_CONN_HANDLE) ||
+ (err_code == NRF_ERROR_INVALID_STATE) ||
+ (err_code == BLE_ERROR_NO_TX_BUFFERS))
+ {
+ // Those errors can be expected when sending trying to send Service Changed Indication
+ // if the CCCD is not set to indicate. Thus set the returning error code to success.
+ err_code = NRF_SUCCESS;
+ }
+ }
+ else
+ {
+ err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
+ }
+
+ return err_code;
+}
+
+
+/**@brief Function to convert an nRF51 error code to a DFU Response Value.
+ *
+ * @details This function will convert a given nRF51 error code to a DFU Response Value. The
+ * result of this function depends on the current DFU procedure in progress, given as
+ * input in current_dfu_proc parameter.
+ *
+ * @param[in] err_code The nRF51 error code to be converted.
+ * @param[in] current_dfu_proc Current DFU procedure in progress.
+ *
+ * @return Converted Response Value.
+ */
+static ble_dfu_resp_val_t nrf_err_code_translate(uint32_t err_code,
+ const ble_dfu_procedure_t current_dfu_proc)
+{
+ switch (err_code)
+ {
+ case NRF_SUCCESS:
+ return BLE_DFU_RESP_VAL_SUCCESS;
+
+ case NRF_ERROR_INVALID_STATE:
+ return BLE_DFU_RESP_VAL_INVALID_STATE;
+
+ case NRF_ERROR_NOT_SUPPORTED:
+ return BLE_DFU_RESP_VAL_NOT_SUPPORTED;
+
+ case NRF_ERROR_DATA_SIZE:
+ return BLE_DFU_RESP_VAL_DATA_SIZE;
+
+ case NRF_ERROR_INVALID_DATA:
+ if (current_dfu_proc == BLE_DFU_VALIDATE_PROCEDURE)
+ {
+ // When this error is received in Validation phase, then it maps to a CRC Error.
+ // Refer dfu_image_validate function for more information.
+ return BLE_DFU_RESP_VAL_CRC_ERROR;
+ }
+ return BLE_DFU_RESP_VAL_OPER_FAILED;
+
+ default:
+ return BLE_DFU_RESP_VAL_OPER_FAILED;
+ }
+}
+
+
+/**@brief Function for handling the callback events from the dfu module.
+ * Callbacks are expected when \ref dfu_data_pkt_handle has been executed.
+ *
+ * @param[in] packet Packet type for which this callback is related.
+ * @param[in] result Operation result code. NRF_SUCCESS when a queued operation was successful.
+ * @param[in] p_data Pointer to the data to which the operation is related.
+ */
+static void dfu_cb_handler(uint32_t packet, uint32_t result, uint8_t * p_data)
+{
+ switch (packet)
+ {
+ ble_dfu_resp_val_t resp_val;
+ uint32_t err_code;
+
+ case DATA_PACKET:
+ if (result != NRF_SUCCESS)
+ {
+ // Disconnect from peer.
+ if (IS_CONNECTED())
+ {
+ err_code = sd_ble_gap_disconnect(m_conn_handle,
+ BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
+ APP_ERROR_CHECK(err_code);
+ }
+ }
+ else
+ {
+ err_code = hci_mem_pool_rx_consume(p_data);
+ APP_ERROR_CHECK(err_code);
+
+ // If the callback matches final data packet received then the peer is notified.
+ if (mp_final_packet == p_data)
+ {
+ // Notify the DFU Controller about the success of the procedure.
+ err_code = ble_dfu_response_send(&m_dfu,
+ BLE_DFU_RECEIVE_APP_PROCEDURE,
+ BLE_DFU_RESP_VAL_SUCCESS);
+ APP_ERROR_CHECK(err_code);
+ }
+ }
+ break;
+
+ case START_PACKET:
+ // Translate the err_code returned by the above function to DFU Response Value.
+ resp_val = nrf_err_code_translate(result, BLE_DFU_START_PROCEDURE);
+
+ err_code = ble_dfu_response_send(&m_dfu,
+ BLE_DFU_START_PROCEDURE,
+ resp_val);
+ APP_ERROR_CHECK(err_code);
+ break;
+
+ default:
+ // ignore.
+ break;
+ }
+}
+
+
+/**@brief Function for notifying a DFU Controller about error conditions in the DFU module.
+ * This function also ensures that an error is translated from nrf_errors to DFU Response
+ * Value.
+ *
+ * @param[in] p_dfu DFU Service Structure.
+ * @param[in] err_code Nrf error code that should be translated and send to the DFU Controller.
+ */
+static void dfu_error_notify(ble_dfu_t * p_dfu, uint32_t err_code)
+{
+ // An error has occurred. Notify the DFU Controller about this error condition.
+ // Translate the err_code returned to DFU Response Value.
+ ble_dfu_resp_val_t resp_val;
+
+ resp_val = nrf_err_code_translate(err_code, BLE_DFU_RECEIVE_APP_PROCEDURE);
+
+ err_code = ble_dfu_response_send(p_dfu, BLE_DFU_RECEIVE_APP_PROCEDURE, resp_val);
+ APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for processing start data written by the peer to the DFU Packet
+ * Characteristic.
+ *
+ * @param[in] p_dfu DFU Service Structure.
+ * @param[in] p_evt Pointer to the event received from the S110 SoftDevice.
+ */
+static void start_data_process(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt)
+{
+ uint32_t err_code;
+
+ dfu_start_packet_t start_packet = {.dfu_update_mode = m_update_mode};
+ dfu_update_packet_t update_packet =
+ {
+ .packet_type = START_PACKET,
+ .params.start_packet = &start_packet
+ };
+
+ uint32_t length = p_evt->evt.ble_dfu_pkt_write.len;
+
+ // Verify that the data is exactly three * four bytes (three words) long.
+ if (length != (3 * sizeof(uint32_t)))
+ {
+ err_code = ble_dfu_response_send(p_dfu,
+ BLE_DFU_START_PROCEDURE,
+ BLE_DFU_RESP_VAL_NOT_SUPPORTED);
+ APP_ERROR_CHECK(err_code);
+ }
+ else
+ {
+ // Extract the size of from the DFU Packet Characteristic.
+ uint8_t * p_length_data = p_evt->evt.ble_dfu_pkt_write.p_data;
+
+ start_packet.sd_image_size = uint32_decode(p_length_data + SD_IMAGE_SIZE_OFFSET);
+ start_packet.bl_image_size = uint32_decode(p_length_data + BL_IMAGE_SIZE_OFFSET);
+ start_packet.app_image_size = uint32_decode(p_length_data + APP_IMAGE_SIZE_OFFSET);
+
+ err_code = dfu_start_pkt_handle(&update_packet);
+ if (err_code != NRF_SUCCESS)
+ {
+ // Translate the err_code returned by the above function to DFU Response Value.
+ ble_dfu_resp_val_t resp_val;
+
+ resp_val = nrf_err_code_translate(err_code, BLE_DFU_START_PROCEDURE);
+ err_code = ble_dfu_response_send(p_dfu, BLE_DFU_START_PROCEDURE, resp_val);
+ }
+
+ APP_ERROR_CHECK(err_code);
+ }
+}
+
+
+/**@brief Function for processing initialization data written by the peer to the DFU Packet
+ * Characteristic.
+ *
+ * @param[in] p_dfu DFU Service Structure.
+ * @param[in] p_evt Pointer to the event received from the S110 SoftDevice.
+ */
+static void init_data_process(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt)
+{
+ uint32_t err_code;
+ dfu_update_packet_t dfu_pkt;
+
+ // The DFU module accepts the dfu_pkt.packet_length to be in 'number of words'. And so if the
+ // received data does not have a size which is a multiple of four, it should be padded with
+ // zeros and the packet_length should be incremented accordingly before calling
+ // dfu_init_pkt_handle.
+ if ((p_evt->evt.ble_dfu_pkt_write.len & (sizeof(uint32_t) - 1)) != 0)
+ {
+ uint32_t padding;
+ uint32_t i;
+ uint8_t pkt_length = p_evt->evt.ble_dfu_pkt_write.len;
+
+ // Find out the number of bytes to be padded.
+ padding = sizeof(uint32_t) - (pkt_length & (sizeof(uint32_t) - 1));
+
+ for (i = 0; i < padding; i++)
+ {
+ p_evt->evt.ble_dfu_pkt_write.p_data[pkt_length++] = 0;
+ }
+
+ p_evt->evt.ble_dfu_pkt_write.len = pkt_length;
+ }
+
+ dfu_pkt.packet_type = INIT_PACKET;
+
+ dfu_pkt.params.data_packet.p_data_packet = (uint32_t *)p_evt->evt.ble_dfu_pkt_write.p_data;
+ dfu_pkt.params.data_packet.packet_length = p_evt->evt.ble_dfu_pkt_write.len / sizeof(uint32_t);
+
+ err_code = dfu_init_pkt_handle(&dfu_pkt);
+
+ // Translate the err_code returned by the above function to DFU Response Value.
+ if (err_code != NRF_SUCCESS)
+ {
+ ble_dfu_resp_val_t resp_val = nrf_err_code_translate(err_code, BLE_DFU_INIT_PROCEDURE);
+
+ err_code = ble_dfu_response_send(p_dfu, BLE_DFU_INIT_PROCEDURE, resp_val);
+ APP_ERROR_CHECK(err_code);
+ }
+}
+
+
+/**@brief Function for processing application data written by the peer to the DFU Packet
+ * Characteristic.
+ *
+ * @param[in] p_dfu DFU Service Structure.
+ * @param[in] p_evt Pointer to the event received from the S110 SoftDevice.
+ */
+static void app_data_process(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt)
+{
+ uint32_t err_code;
+
+ if ((p_evt->evt.ble_dfu_pkt_write.len & (sizeof(uint32_t) - 1)) != 0)
+ {
+ // Data length is not a multiple of 4 (word size).
+ err_code = ble_dfu_response_send(p_dfu,
+ BLE_DFU_RECEIVE_APP_PROCEDURE,
+ BLE_DFU_RESP_VAL_NOT_SUPPORTED);
+ APP_ERROR_CHECK(err_code);
+ return;
+ }
+
+ uint32_t length = p_evt->evt.ble_dfu_pkt_write.len;
+
+ err_code = hci_mem_pool_rx_produce(length, (void **) &mp_rx_buffer);
+ if (err_code != NRF_SUCCESS)
+ {
+ dfu_error_notify(p_dfu, err_code);
+ return;
+ }
+
+ uint8_t * p_data_packet = p_evt->evt.ble_dfu_pkt_write.p_data;
+
+ memcpy(mp_rx_buffer, p_data_packet, length);
+
+ err_code = hci_mem_pool_rx_data_size_set(length);
+ if (err_code != NRF_SUCCESS)
+ {
+ dfu_error_notify(p_dfu, err_code);
+ return;
+ }
+
+ err_code = hci_mem_pool_rx_extract(&mp_rx_buffer, &length);
+ if (err_code != NRF_SUCCESS)
+ {
+ dfu_error_notify(p_dfu, err_code);
+ return;
+ }
+
+ dfu_update_packet_t dfu_pkt;
+
+ dfu_pkt.packet_type = DATA_PACKET;
+ dfu_pkt.params.data_packet.packet_length = length / sizeof(uint32_t);
+ dfu_pkt.params.data_packet.p_data_packet = (uint32_t *)mp_rx_buffer;
+
+ err_code = dfu_data_pkt_handle(&dfu_pkt);
+
+ if (err_code == NRF_SUCCESS)
+ {
+ m_num_of_firmware_bytes_rcvd += p_evt->evt.ble_dfu_pkt_write.len;
+
+ // All the expected firmware data has been received and processed successfully.
+ // Response will be sent when flash operation for final packet is completed.
+ mp_final_packet = mp_rx_buffer;
+ }
+ else if (err_code == NRF_ERROR_INVALID_LENGTH)
+ {
+ // Firmware data packet was handled successfully. And more firmware data is expected.
+ m_num_of_firmware_bytes_rcvd += p_evt->evt.ble_dfu_pkt_write.len;
+
+ // Check if a packet receipt notification is needed to be sent.
+ if (m_pkt_rcpt_notif_enabled)
+ {
+ // Decrement the counter for the number firmware packets needed for sending the
+ // next packet receipt notification.
+ m_pkt_notif_target_cnt--;
+
+ if (m_pkt_notif_target_cnt == 0)
+ {
+ err_code = ble_dfu_pkts_rcpt_notify(p_dfu, m_num_of_firmware_bytes_rcvd);
+ APP_ERROR_CHECK(err_code);
+
+ // Reset the counter for the number of firmware packets.
+ m_pkt_notif_target_cnt = m_pkt_notif_target;
+ }
+ }
+ }
+ else
+ {
+ uint32_t hci_error = hci_mem_pool_rx_consume(mp_rx_buffer);
+ if (hci_error != NRF_SUCCESS)
+ {
+ dfu_error_notify(p_dfu, hci_error);
+ }
+
+ dfu_error_notify(p_dfu, err_code);
+ }
+}
+
+
+/**@brief Function for processing data written by the peer to the DFU Packet Characteristic.
+ *
+ * @param[in] p_dfu DFU Service Structure.
+ * @param[in] p_evt Pointer to the event received from the S110 SoftDevice.
+ */
+static void on_dfu_pkt_write(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt)
+{
+ // The peer has written to the DFU Packet characteristic. Depending on the value of
+ // the current value of the DFU Control Point, the appropriate action is taken.
+ switch (m_pkt_type)
+ {
+ case PKT_TYPE_START:
+ // The peer has written a start packet to the DFU Packet characteristic.
+ start_data_process(p_dfu, p_evt);
+ break;
+
+ case PKT_TYPE_INIT:
+ // The peer has written an init packet to the DFU Packet characteristic.
+ init_data_process(p_dfu, p_evt);
+ break;
+
+ case PKT_TYPE_FIRMWARE_DATA:
+ app_data_process(p_dfu, p_evt);
+ break;
+
+ default:
+ // It is not possible to find out what packet it is. Ignore. There is no
+ // mechanism to notify the DFU Controller about this error condition.
+ break;
+ }
+}
+
+
+/**@brief Function for handling a Connection Parameters error.
+ *
+ * @param[in] nrf_error Error code.
+ */
+static void conn_params_error_handler(uint32_t nrf_error)
+{
+ APP_ERROR_HANDLER(nrf_error);
+}
+
+
+/**@brief Function for initializing the Connection Parameters module.
+ */
+static void conn_params_init(void)
+{
+ uint32_t err_code;
+ ble_conn_params_init_t cp_init;
+
+ memset(&cp_init, 0, sizeof(cp_init));
+
+ cp_init.p_conn_params = NULL;
+ cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
+ cp_init.next_conn_params_update_delay = NEXT_CONN_PARAMS_UPDATE_DELAY;
+ cp_init.max_conn_params_update_count = MAX_CONN_PARAMS_UPDATE_COUNT;
+ cp_init.start_on_notify_cccd_handle = BLE_GATT_HANDLE_INVALID;
+ cp_init.disconnect_on_fail = false;
+ cp_init.evt_handler = NULL;
+ cp_init.error_handler = conn_params_error_handler;
+
+ err_code = ble_conn_params_init(&cp_init);
+ APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for the Device Firmware Update Service event handler.
+ *
+ * @details This function will be called for all Device Firmware Update Service events which
+ * are passed to the application.
+ *
+ * @param[in] p_dfu Device Firmware Update Service structure.
+ * @param[in] p_evt Event received from the Device Firmware Update Service.
+ */
+static void on_dfu_evt(ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt)
+{
+ uint32_t err_code;
+ ble_dfu_resp_val_t resp_val;
+
+ switch (p_evt->ble_dfu_evt_type)
+ {
+ case BLE_DFU_VALIDATE:
+ err_code = dfu_image_validate();
+
+ // Translate the err_code returned by the above function to DFU Response Value.
+ resp_val = nrf_err_code_translate(err_code, BLE_DFU_VALIDATE_PROCEDURE);
+
+ err_code = ble_dfu_response_send(p_dfu, BLE_DFU_VALIDATE_PROCEDURE, resp_val);
+ APP_ERROR_CHECK(err_code);
+ break;
+
+ case BLE_DFU_ACTIVATE_N_RESET:
+ err_code = dfu_transport_close();
+ APP_ERROR_CHECK(err_code);
+
+ // With the S110 Flash API it is safe to initiate the activate before connection is
+ // fully closed.
+ err_code = dfu_image_activate();
+ if (err_code != NRF_SUCCESS)
+ {
+ dfu_reset();
+ }
+ break;
+
+ case BLE_DFU_SYS_RESET:
+ err_code = dfu_transport_close();
+ APP_ERROR_CHECK(err_code);
+
+ dfu_reset();
+ break;
+
+ case BLE_DFU_START:
+ m_pkt_type = PKT_TYPE_START;
+ m_update_mode = (uint8_t)p_evt->evt.ble_dfu_pkt_write.p_data[0];
+ break;
+
+ case BLE_DFU_RECEIVE_INIT_DATA:
+ m_pkt_type = PKT_TYPE_INIT;
+ if ((uint8_t)p_evt->evt.ble_dfu_pkt_write.p_data[0] == DFU_INIT_COMPLETE)
+ {
+ err_code = dfu_init_pkt_complete();
+
+ // Translate the err_code returned by the above function to DFU Response Value.
+ resp_val = nrf_err_code_translate(err_code, BLE_DFU_INIT_PROCEDURE);
+
+ err_code = ble_dfu_response_send(p_dfu, BLE_DFU_INIT_PROCEDURE, resp_val);
+ APP_ERROR_CHECK(err_code);
+ }
+ break;
+
+ case BLE_DFU_RECEIVE_APP_DATA:
+ m_pkt_type = PKT_TYPE_FIRMWARE_DATA;
+ break;
+
+ case BLE_DFU_PACKET_WRITE:
+ on_dfu_pkt_write(p_dfu, p_evt);
+ break;
+
+ case BLE_DFU_PKT_RCPT_NOTIF_ENABLED:
+ m_pkt_rcpt_notif_enabled = true;
+ m_pkt_notif_target = p_evt->evt.pkt_rcpt_notif_req.num_of_pkts;
+ m_pkt_notif_target_cnt = p_evt->evt.pkt_rcpt_notif_req.num_of_pkts;
+ break;
+
+ case BLE_DFU_PKT_RCPT_NOTIF_DISABLED:
+ m_pkt_rcpt_notif_enabled = false;
+ m_pkt_notif_target = 0;
+ break;
+
+ case BLE_DFU_BYTES_RECEIVED_SEND:
+ err_code = ble_dfu_bytes_rcvd_report(p_dfu, m_num_of_firmware_bytes_rcvd);
+ APP_ERROR_CHECK(err_code);
+ break;
+
+ default:
+ // Unsupported event received from DFU Service. Ignore.
+ break;
+ }
+}
+
+
+/**@brief Function for the Advertising functionality initialization.
+ *
+ * @details Encodes the required advertising data and passes it to the stack.
+ * Also builds a structure to be passed to the stack when starting advertising.
+ */
+static void advertising_init(uint8_t adv_flags)
+{
+ uint32_t err_code;
+ ble_advdata_t advdata;
+ ble_uuid_t service_uuid;
+
+ service_uuid.type = m_dfu.uuid_type;
+ service_uuid.uuid = BLE_DFU_SERVICE_UUID;
+
+ // Build and set advertising data.
+ memset(&advdata, 0, sizeof(advdata));
+
+ advdata.name_type = BLE_ADVDATA_FULL_NAME;
+ advdata.include_appearance = false;
+ advdata.flags = adv_flags;
+ advdata.uuids_more_available.uuid_cnt = 1;
+ advdata.uuids_more_available.p_uuids = &service_uuid;
+
+ err_code = ble_advdata_set(&advdata, NULL);
+ APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for starting advertising.
+ */
+static void advertising_start(void)
+{
+ if (!m_is_advertising)
+ {
+ uint32_t err_code;
+
+ // Initialize advertising parameters (used when starting advertising).
+ memset(&m_adv_params, 0, sizeof(m_adv_params));
+
+ if (m_ble_peer_data_valid)
+ {
+ ble_gap_irk_t empty_irk = {{0}};
+
+ if (memcmp(m_ble_peer_data.irk.irk, empty_irk.irk, sizeof(empty_irk.irk)) == 0)
+ {
+ advertising_init(BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE);
+ m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_DIRECT_IND;
+ m_adv_params.p_peer_addr = &m_ble_peer_data.addr;
+ m_adv_params.fp = BLE_GAP_ADV_FP_ANY;
+ m_adv_params.interval = 0;
+ m_adv_params.timeout = 0;
+ }
+ else
+ {
+ ble_gap_irk_t * p_irk[1];
+ ble_gap_addr_t * p_addr[1];
+
+ p_irk[0] = &m_ble_peer_data.irk;
+ p_addr[0] = &m_ble_peer_data.addr;
+
+ ble_gap_whitelist_t whitelist;
+ whitelist.addr_count = 1;
+ whitelist.pp_addrs = p_addr;
+ whitelist.irk_count = 1;
+ whitelist.pp_irks = p_irk;
+
+ advertising_init(BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED);
+ m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND;
+ m_adv_params.fp = BLE_GAP_ADV_FP_FILTER_CONNREQ;
+ m_adv_params.p_whitelist = &whitelist;
+ m_adv_params.interval = APP_ADV_INTERVAL;
+ m_adv_params.timeout = APP_ADV_TIMEOUT_IN_SECONDS;
+ }
+ }
+ else
+ {
+ advertising_init(BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE);
+ m_adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND;
+ m_adv_params.p_peer_addr = NULL;
+ m_adv_params.fp = BLE_GAP_ADV_FP_ANY;
+ m_adv_params.interval = APP_ADV_INTERVAL;
+ m_adv_params.timeout = APP_ADV_TIMEOUT_IN_SECONDS;
+ }
+
+ err_code = sd_ble_gap_adv_start(&m_adv_params);
+ APP_ERROR_CHECK(err_code);
+
+ nrf_gpio_pin_clear(ADVERTISING_LED_PIN_NO);
+
+ m_is_advertising = true;
+ }
+}
+
+
+/**@brief Function for stopping advertising.
+ */
+static void advertising_stop(void)
+{
+ if (m_is_advertising)
+ {
+ uint32_t err_code;
+
+ err_code = sd_ble_gap_adv_stop();
+ APP_ERROR_CHECK(err_code);
+
+ nrf_gpio_pin_set(ADVERTISING_LED_PIN_NO);
+
+ m_is_advertising = false;
+ }
+}
+
+
+/**@brief Function for the Application's S110 SoftDevice event handler.
+ *
+ * @param[in] p_ble_evt S110 SoftDevice event.
+ */
+static void on_ble_evt(ble_evt_t * p_ble_evt)
+{
+ uint32_t err_code;
+ ble_gatts_rw_authorize_reply_params_t auth_reply;
+
+ switch (p_ble_evt->header.evt_id)
+ {
+ case BLE_GAP_EVT_CONNECTED:
+ nrf_gpio_pin_clear(CONNECTED_LED_PIN_NO);
+ nrf_gpio_pin_set(ADVERTISING_LED_PIN_NO);
+
+ m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
+ m_is_advertising = false;
+ break;
+
+ case BLE_GAP_EVT_DISCONNECTED:
+ {
+ uint8_t sys_attr[128];
+ uint16_t sys_attr_len = 128;
+
+ m_direct_adv_cnt = APP_DIRECTED_ADV_TIMEOUT;
+ nrf_gpio_pin_set(CONNECTED_LED_PIN_NO);
+
+ err_code = sd_ble_gatts_sys_attr_get(m_conn_handle,
+ sys_attr,
+ &sys_attr_len,
+ BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS);
+ APP_ERROR_CHECK(err_code);
+
+ }
+ if (!m_tear_down_in_progress)
+ {
+ // The Disconnected event is because of an external event. (Link loss or
+ // disconnect triggered by the DFU Controller before the firmware update was
+ // complete).
+ // Restart advertising so that the DFU Controller can reconnect if possible.
+ advertising_start();
+ }
+
+ m_conn_handle = BLE_CONN_HANDLE_INVALID;
+
+ break;
+
+ case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
+ {
+ ble_gap_sec_keyset_t keys;
+ ble_gap_enc_key_t enc_key;
+ ble_gap_id_key_t id_key;
+
+ id_key.id_addr_info = m_ble_peer_data.addr;
+ id_key.id_info = m_ble_peer_data.irk;
+ enc_key = m_ble_peer_data.enc_key;
+
+ keys.keys_central.p_id_key = &id_key;
+ keys.keys_central.p_enc_key = &enc_key;
+
+ err_code = sd_ble_gap_sec_params_reply(m_conn_handle,
+ BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP,
+ &m_sec_params,
+ &keys);
+ APP_ERROR_CHECK(err_code);
+ }
+ break;
+
+ case BLE_GATTS_EVT_TIMEOUT:
+ if (p_ble_evt->evt.gatts_evt.params.timeout.src == BLE_GATT_TIMEOUT_SRC_PROTOCOL)
+ {
+ err_code = sd_ble_gap_disconnect(m_conn_handle,
+ BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
+ APP_ERROR_CHECK(err_code);
+ }
+ break;
+
+ case BLE_GAP_EVT_TIMEOUT:
+ if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISING)
+ {
+ m_is_advertising = false;
+ m_direct_adv_cnt--;
+ if (m_direct_adv_cnt == 0)
+ {
+ dfu_update_status_t update_status = {.status_code = DFU_TIMEOUT};
+ bootloader_dfu_update_process(update_status);
+ }
+ else
+ {
+ advertising_start();
+ }
+ }
+ break;
+
+ case BLE_EVT_USER_MEM_REQUEST:
+ err_code = sd_ble_user_mem_reply(m_conn_handle, NULL);
+ APP_ERROR_CHECK(err_code);
+ break;
+
+ case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
+ if (p_ble_evt->evt.gatts_evt.params.authorize_request.type
+ != BLE_GATTS_AUTHORIZE_TYPE_INVALID)
+ {
+ if ((p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.op
+ == BLE_GATTS_OP_PREP_WRITE_REQ)
+ || (p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.op
+ == BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
+ || (p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.op
+ == BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL))
+ {
+ if (p_ble_evt->evt.gatts_evt.params.authorize_request.type
+ == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
+ {
+ auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
+ }
+ else
+ {
+ auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_READ;
+ }
+ auth_reply.params.write.gatt_status = APP_FEATURE_NOT_SUPPORTED;
+
+ err_code = sd_ble_gatts_rw_authorize_reply(m_conn_handle,&auth_reply);
+ APP_ERROR_CHECK(err_code);
+ }
+ }
+ break;
+
+ case BLE_GAP_EVT_SEC_INFO_REQUEST:
+ {
+ ble_gap_enc_info_t * p_enc_info = NULL;
+
+ // If there is a match in diversifier then set the correct keys.
+ if (p_ble_evt->evt.gap_evt.params.sec_info_request.master_id.ediv ==
+ m_ble_peer_data.enc_key.master_id.ediv)
+ {
+ p_enc_info = &m_ble_peer_data.enc_key.enc_info;
+ }
+
+ err_code = sd_ble_gap_sec_info_reply(p_ble_evt->evt.gap_evt.conn_handle,
+ p_enc_info,
+ &m_ble_peer_data.irk,
+ NULL);
+ APP_ERROR_CHECK(err_code);
+ }
+ break;
+
+ case BLE_GATTS_EVT_SYS_ATTR_MISSING:
+ case BLE_GAP_EVT_CONN_SEC_UPDATE:
+ err_code = service_change_indicate();
+ APP_ERROR_CHECK(err_code);
+ break;
+
+ case BLE_GAP_EVT_AUTH_STATUS:
+ // No implementation needed.
+ break;
+
+ default:
+ // No implementation needed.
+ break;
+ }
+}
+
+
+/**@brief Function for dispatching a S110 SoftDevice event to all modules with a S110
+ * SoftDevice event handler.
+ *
+ * @details This function is called from the S110 SoftDevice event interrupt handler after a
+ * S110 SoftDevice event has been received.
+ *
+ * @param[in] p_ble_evt S110 SoftDevice event.
+ */
+static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
+{
+ ble_conn_params_on_ble_evt(p_ble_evt);
+ ble_dfu_on_ble_evt(&m_dfu, p_ble_evt);
+ on_ble_evt(p_ble_evt);
+}
+
+
+/**@brief Function for the LEDs initialization.
+ *
+ * @details Initializes all LEDs used by this application.
+ */
+static void leds_init(void)
+{
+ nrf_gpio_cfg_output(ADVERTISING_LED_PIN_NO);
+ nrf_gpio_cfg_output(CONNECTED_LED_PIN_NO);
+ nrf_gpio_pin_set(ADVERTISING_LED_PIN_NO);
+ nrf_gpio_pin_set(CONNECTED_LED_PIN_NO);
+}
+
+
+/**@brief Function for the GAP initialization.
+ *
+ * @details This function will setup all the necessary GAP (Generic Access Profile) parameters of
+ * the device. It also sets the permissions and appearance.
+ */
+static void gap_params_init(void)
+{
+ uint32_t err_code;
+ ble_gap_conn_params_t gap_conn_params;
+ ble_gap_conn_sec_mode_t sec_mode;
+
+ BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
+
+ err_code = sd_ble_gap_device_name_set(&sec_mode,
+ (const uint8_t *)DEVICE_NAME,
+ strlen(DEVICE_NAME));
+ APP_ERROR_CHECK(err_code);
+
+ memset(&gap_conn_params, 0, sizeof(gap_conn_params));
+
+ gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
+ gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
+ gap_conn_params.slave_latency = SLAVE_LATENCY;
+ gap_conn_params.conn_sup_timeout = CONN_SUP_TIMEOUT;
+
+ err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
+ APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for handling Service errors.
+ *
+ * @details A pointer to this function will be passed to the DFU service which may need to inform
+ * the application about an error.
+ *
+ * @param[in] nrf_error Error code containing information about what went wrong.
+ */
+static void service_error_handler(uint32_t nrf_error)
+{
+ APP_ERROR_HANDLER(nrf_error);
+}
+
+
+/**@brief Function for initializing services that will be used by the application.
+ */
+static void services_init(void)
+{
+ uint32_t err_code;
+ ble_dfu_init_t dfu_init_obj;
+
+ // Initialize the Device Firmware Update Service.
+ memset(&dfu_init_obj, 0, sizeof(dfu_init_obj));
+
+ dfu_init_obj.revision = DFU_REVISION;
+ dfu_init_obj.evt_handler = on_dfu_evt;
+ dfu_init_obj.error_handler = service_error_handler;
+
+ err_code = ble_dfu_init(&m_dfu, &dfu_init_obj);
+
+ APP_ERROR_CHECK(err_code);
+}
+
+
+/**@brief Function for initializing security parameters.
+ */
+static void sec_params_init(void)
+{
+ m_sec_params.bond = SEC_PARAM_BOND;
+ m_sec_params.mitm = SEC_PARAM_MITM;
+ m_sec_params.io_caps = SEC_PARAM_IO_CAPABILITIES;
+ m_sec_params.oob = SEC_PARAM_OOB;
+ m_sec_params.min_key_size = SEC_PARAM_MIN_KEY_SIZE;
+ m_sec_params.max_key_size = SEC_PARAM_MAX_KEY_SIZE;
+}
+
+
+uint32_t dfu_transport_update_start(void)
+{
+ uint32_t err_code;
+
+ m_tear_down_in_progress = false;
+ m_pkt_type = PKT_TYPE_INVALID;
+
+ leds_init();
+
+ err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ dfu_register_callback(dfu_cb_handler);
+
+ err_code = hci_mem_pool_open();
+ if (err_code != NRF_SUCCESS)
+ {
+ return err_code;
+ }
+
+ err_code = dfu_ble_peer_data_get(&m_ble_peer_data);
+ if (err_code == NRF_SUCCESS)
+ {
+ m_ble_peer_data_valid = true;
+ }
+ else
+ {
+ ble_gap_addr_t addr;
+
+ err_code = sd_ble_gap_address_get(&addr);
+ APP_ERROR_CHECK(err_code);
+
+ // Increase the BLE address by one when advertising openly.
+ addr.addr[0] += 1;
+
+ err_code = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &addr);
+ APP_ERROR_CHECK(err_code);
+ }
+
+ gap_params_init();
+ services_init();
+ conn_params_init();
+ sec_params_init();
+ advertising_start();
+
+ return NRF_SUCCESS;
+}
+
+
+uint32_t dfu_transport_close()
+{
+ uint32_t err_code;
+
+ m_tear_down_in_progress = true;
+
+ if (IS_CONNECTED())
+ {
+ // Disconnect from peer.
+ err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
+ APP_ERROR_CHECK(err_code);
+ }
+ else
+ {
+ // If not connected, then the device will be advertising. Hence stop the advertising.
+ advertising_stop();
+ }
+
+ err_code = ble_conn_params_stop();
+ APP_ERROR_CHECK(err_code);
+
+ return NRF_SUCCESS;
+}