123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865 |
- /**
- * Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form, except as embedded into a Nordic
- * Semiconductor ASA integrated circuit in a product or a software update for
- * such product, must reproduce the above copyright notice, this list of
- * conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution.
- *
- * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
- * contributors may be used to endorse or promote products derived from this
- * software without specific prior written permission.
- *
- * 4. This software, with or without modification, must only be used with a
- * Nordic Semiconductor ASA integrated circuit.
- *
- * 5. Any software provided in binary form under this license must not be reverse
- * engineered, decompiled, modified and/or disassembled.
- *
- * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
- #include <stdint.h>
- #include <stdbool.h>
- #include "sdk_config.h"
- #include "nrf_dfu.h"
- #include "nrf_dfu_types.h"
- #include "nrf_dfu_req_handler.h"
- #include "nrf_dfu_handling_error.h"
- #include "nrf_dfu_settings.h"
- #include "nrf_dfu_utils.h"
- #include "nrf_dfu_flash.h"
- #include "nrf_fstorage.h"
- #include "nrf_bootloader_info.h"
- #include "app_util.h"
- #include "pb.h"
- #include "pb_common.h"
- #include "pb_decode.h"
- #include "dfu-cc.pb.h"
- #include "crc32.h"
- #include "app_scheduler.h"
- #include "sdk_macros.h"
- #include "nrf_crypto.h"
- #include "nrf_assert.h"
- #include "nrf_dfu_validation.h"
- #define NRF_LOG_MODULE_NAME nrf_dfu_req_handler
- #include "nrf_log.h"
- NRF_LOG_MODULE_REGISTER();
- #define NRF_DFU_PROTOCOL_VERSION (0x01)
- #ifndef NRF_DFU_PROTOCOL_REDUCED
- #define NRF_DFU_PROTOCOL_REDUCED 0
- #endif
- STATIC_ASSERT(DFU_SIGNED_COMMAND_SIZE <= INIT_COMMAND_MAX_SIZE);
- static uint32_t m_firmware_start_addr; /**< Start address of the current firmware image. */
- static uint32_t m_firmware_size_req; /**< The size of the entire firmware image. Defined by the init command. */
- static nrf_dfu_observer_t m_observer;
- static void on_dfu_complete(nrf_fstorage_evt_t * p_evt)
- {
- UNUSED_PARAMETER(p_evt);
- NRF_LOG_DEBUG("All flash operations have completed. DFU completed.");
- m_observer(NRF_DFU_EVT_DFU_COMPLETED);
- }
- static nrf_dfu_result_t ext_err_code_handle(nrf_dfu_result_t ret_val)
- {
- if (ret_val < NRF_DFU_RES_CODE_EXT_ERROR)
- {
- return ret_val;
- }
- else
- {
- nrf_dfu_ext_error_code_t ext_err =
- (nrf_dfu_ext_error_code_t)((uint8_t)ret_val - (uint8_t)NRF_DFU_RES_CODE_EXT_ERROR);
- return ext_error_set(ext_err);
- }
- }
- #if !NRF_DFU_PROTOCOL_REDUCED
- static void on_protocol_version_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
- {
- UNUSED_PARAMETER(p_req);
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_PROTOCOL_VERSION");
- if (NRF_DFU_PROTOCOL_VERSION_MSG)
- {
- p_res->protocol.version = NRF_DFU_PROTOCOL_VERSION;
- }
- else
- {
- NRF_LOG_DEBUG("NRF_DFU_OP_PROTOCOL_VERSION disabled.");
- p_res->result = NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED;
- }
- }
- static void on_hw_version_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
- {
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_HARDWARE_VERSION");
- p_res->hardware.part = NRF_FICR->INFO.PART;
- p_res->hardware.variant = NRF_FICR->INFO.VARIANT;
- /* FICR values are in Kilobytes, we report them in bytes. */
- p_res->hardware.memory.ram_size = NRF_FICR->INFO.RAM * 1024;
- p_res->hardware.memory.rom_size = NRF_FICR->INFO.FLASH * 1024;
- p_res->hardware.memory.rom_page_size = NRF_FICR->CODEPAGESIZE;
- }
- static void on_fw_version_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
- {
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_FIRMWARE_VERSION");
- NRF_LOG_DEBUG("Firmware image requested: %d", p_req->firmware.image_number);
- if (NRF_DFU_PROTOCOL_FW_VERSION_MSG)
- {
- uint8_t fw_count = 1;
- if (SD_PRESENT)
- {
- fw_count++;
- }
- if (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_VALID_APP)
- {
- fw_count++;
- }
- p_res->result = NRF_DFU_RES_CODE_SUCCESS;
- if (p_req->firmware.image_number == 0)
- {
- /* Bootloader is always present and it is always image zero. */
- p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_BOOTLOADER;
- p_res->firmware.version = s_dfu_settings.bootloader_version;
- p_res->firmware.addr = BOOTLOADER_START_ADDR;
- p_res->firmware.len = BOOTLOADER_SIZE;
- }
- else if ((p_req->firmware.image_number == 1) && SD_PRESENT)
- {
- /* If a SoftDevice is present, it will be firmware image one. */
- p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_SOFTDEVICE;
- p_res->firmware.version = SD_VERSION_GET(MBR_SIZE);
- p_res->firmware.addr = MBR_SIZE;
- p_res->firmware.len = SD_SIZE_GET(MBR_SIZE);
- }
- else if ((p_req->firmware.image_number < fw_count))
- {
- /* Either there is no SoftDevice and the firmware image requested is one,
- * or there is a SoftDevice and the firmware image requested is two.
- */
- p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_APPLICATION;
- p_res->firmware.version = s_dfu_settings.app_version;
- p_res->firmware.addr = nrf_dfu_app_start_address();
- p_res->firmware.len = s_dfu_settings.bank_0.image_size;
- }
- else
- {
- NRF_LOG_DEBUG("No such firmware image");
- p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_UNKNOWN;
- p_res->firmware.version = 0x00;
- p_res->firmware.addr = 0x00;
- p_res->firmware.len = 0x00;
- }
- }
- else
- {
- NRF_LOG_DEBUG("NRF_DFU_OP_FIRMWARE_VERSION disabled.");
- p_res->result = NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED;
- p_res->firmware.type = NRF_DFU_FIRMWARE_TYPE_UNKNOWN;
- }
- }
- static void on_ping_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
- {
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_PING");
- p_res->ping.id = p_req->ping.id;
- }
- static void on_mtu_get_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
- {
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_MTU_GET");
- p_res->mtu.size = p_req->mtu.size;
- }
- #endif // !NRF_DFU_PROTOCOL_REDUCED
- static void on_prn_set_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
- {
- UNUSED_PARAMETER(p_req);
- UNUSED_PARAMETER(p_res);
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_RECEIPT_NOTIF_SET");
- }
- static void on_abort_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
- {
- UNUSED_PARAMETER(p_req);
- UNUSED_PARAMETER(p_res);
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_ABORT");
- m_observer(NRF_DFU_EVT_DFU_ABORTED);
- }
- /* Set offset and CRC fields in the response for a 'command' message. */
- static void cmd_response_offset_and_crc_set(nrf_dfu_response_t * const p_res)
- {
- ASSERT(p_res);
- /* Copy the CRC and offset of the init packet. */
- p_res->crc.offset = s_dfu_settings.progress.command_offset;
- p_res->crc.crc = s_dfu_settings.progress.command_crc;
- }
- static void on_cmd_obj_select_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
- {
- UNUSED_PARAMETER(p_req);
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_SELECT (command)");
- p_res->select.max_size = INIT_COMMAND_MAX_SIZE;
- cmd_response_offset_and_crc_set(p_res);
- }
- static void on_cmd_obj_create_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
- {
- ASSERT(p_req);
- ASSERT(p_res);
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_CREATE (command)");
- m_observer(NRF_DFU_EVT_DFU_STARTED);
- nrf_dfu_result_t ret_val = nrf_dfu_validation_init_cmd_create(p_req->create.object_size);
- p_res->result = ext_err_code_handle(ret_val);
- }
- static void on_cmd_obj_write_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
- {
- ASSERT(p_req);
- ASSERT(p_req->write.p_data);
- ASSERT(p_req->write.len);
- ASSERT(p_res);
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_WRITE (command)");
- nrf_dfu_result_t ret_val;
- ret_val = nrf_dfu_validation_init_cmd_append(p_req->write.p_data, p_req->write.len);
- p_res->result = ext_err_code_handle(ret_val);
- /* Update response. This is only used when the PRN is triggered and the 'write' message
- * is answered with a CRC message and these field are copied into the response. */
- cmd_response_offset_and_crc_set(p_res);
- /* If a callback to free the request payload buffer was provided, invoke it now. */
- if (p_req->callback.write)
- {
- p_req->callback.write((void*)p_req->write.p_data);
- }
- }
- static void on_cmd_obj_execute_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
- {
- ASSERT(p_req);
- ASSERT(p_res);
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_EXECUTE (command)");
- nrf_dfu_result_t ret_val;
- ret_val = nrf_dfu_validation_init_cmd_execute(&m_firmware_start_addr, &m_firmware_size_req);
- p_res->result = ext_err_code_handle(ret_val);
- if (p_res->result == NRF_DFU_RES_CODE_SUCCESS)
- {
- if (nrf_dfu_settings_write_and_backup(NULL) == NRF_SUCCESS)
- {
- /* Setting DFU to initialized */
- NRF_LOG_DEBUG("Writing valid init command to flash.");
- }
- else
- {
- p_res->result = NRF_DFU_RES_CODE_OPERATION_FAILED;
- }
- }
- }
- static void on_cmd_obj_crc_request(nrf_dfu_request_t const * p_req, nrf_dfu_response_t * p_res)
- {
- UNUSED_PARAMETER(p_req);
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_CRC_GET (command)");
- cmd_response_offset_and_crc_set(p_res);
- }
- /** @brief Function handling command requests from the transport layer.
- *
- * @param p_req[in] Pointer to the structure holding the DFU request.
- * @param p_res[out] Pointer to the structure holding the DFU response.
- *
- * @retval NRF_SUCCESS If the command request was executed successfully.
- * Any other error code indicates that the data request
- * could not be handled.
- */
- static void nrf_dfu_command_req(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
- {
- ASSERT(p_req);
- ASSERT(p_res);
- switch (p_req->request)
- {
- case NRF_DFU_OP_OBJECT_CREATE:
- {
- on_cmd_obj_create_request(p_req, p_res);
- } break;
- case NRF_DFU_OP_CRC_GET:
- {
- on_cmd_obj_crc_request(p_req, p_res);
- } break;
- case NRF_DFU_OP_OBJECT_WRITE:
- {
- on_cmd_obj_write_request(p_req, p_res);
- } break;
- case NRF_DFU_OP_OBJECT_EXECUTE:
- {
- on_cmd_obj_execute_request(p_req, p_res);
- } break;
- case NRF_DFU_OP_OBJECT_SELECT:
- {
- on_cmd_obj_select_request(p_req, p_res);
- } break;
- default:
- {
- ASSERT(false);
- } break;
- }
- }
- static void on_data_obj_select_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
- {
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_SELECT (data)");
- p_res->select.crc = s_dfu_settings.progress.firmware_image_crc;
- p_res->select.offset = s_dfu_settings.progress.firmware_image_offset;
- p_res->select.max_size = DATA_OBJECT_MAX_SIZE;
- NRF_LOG_DEBUG("crc = 0x%x, offset = 0x%x, max_size = 0x%x",
- p_res->select.crc,
- p_res->select.offset,
- p_res->select.max_size);
- }
- static void on_data_obj_create_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
- {
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_CREATE (data)");
- if (!nrf_dfu_validation_init_cmd_present())
- {
- /* Can't accept data because DFU isn't initialized by init command. */
- NRF_LOG_ERROR("Cannot create data object without valid init command");
- p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
- return;
- }
- if (p_req->create.object_size == 0)
- {
- NRF_LOG_ERROR("Object size cannot be 0.")
- p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
- return;
- }
- if ( ((p_req->create.object_size & (CODE_PAGE_SIZE - 1)) != 0)
- && (s_dfu_settings.progress.firmware_image_offset_last + p_req->create.object_size != m_firmware_size_req))
- {
- NRF_LOG_ERROR("Object size must be page aligned");
- p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
- return;
- }
- if (p_req->create.object_size > DATA_OBJECT_MAX_SIZE)
- {
- /* It is impossible to handle the command because the size is too large */
- NRF_LOG_ERROR("Invalid size for object (too large)");
- p_res->result = NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES;
- return;
- }
- if ((s_dfu_settings.progress.firmware_image_offset_last + p_req->create.object_size) >
- m_firmware_size_req)
- {
- NRF_LOG_ERROR("Creating the object with size 0x%08x would overflow firmware size. "
- "Offset is 0x%08x and firmware size is 0x%08x.",
- p_req->create.object_size,
- s_dfu_settings.progress.firmware_image_offset_last,
- m_firmware_size_req);
- p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
- return;
- }
- s_dfu_settings.progress.data_object_size = p_req->create.object_size;
- s_dfu_settings.progress.firmware_image_crc = s_dfu_settings.progress.firmware_image_crc_last;
- s_dfu_settings.progress.firmware_image_offset = s_dfu_settings.progress.firmware_image_offset_last;
- s_dfu_settings.write_offset = s_dfu_settings.progress.firmware_image_offset_last;
- /* Erase the page we're at. */
- if (nrf_dfu_flash_erase((m_firmware_start_addr + s_dfu_settings.progress.firmware_image_offset),
- CEIL_DIV(p_req->create.object_size, CODE_PAGE_SIZE), NULL) != NRF_SUCCESS)
- {
- NRF_LOG_ERROR("Erase operation failed");
- p_res->result = NRF_DFU_RES_CODE_INVALID_OBJECT;
- return;
- }
- NRF_LOG_DEBUG("Creating object with size: %d. Offset: 0x%08x, CRC: 0x%08x",
- s_dfu_settings.progress.data_object_size,
- s_dfu_settings.progress.firmware_image_offset,
- s_dfu_settings.progress.firmware_image_crc);
- }
- static void on_data_obj_write_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
- {
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_WRITE (data)");
- if (!nrf_dfu_validation_init_cmd_present())
- {
- /* Can't accept data because DFU isn't initialized by init command. */
- p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
- return;
- }
- uint32_t const data_object_offset = s_dfu_settings.progress.firmware_image_offset -
- s_dfu_settings.progress.firmware_image_offset_last;
- if ((p_req->write.len + data_object_offset) > s_dfu_settings.progress.data_object_size)
- {
- /* Can't accept data because too much data has been received. */
- NRF_LOG_ERROR("Write request too long");
- p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER;
- return;
- }
- uint32_t const write_addr = m_firmware_start_addr + s_dfu_settings.write_offset;
- /* CRC must be calculated before handing off the data to fstorage because the data is
- * freed on write completion.
- */
- uint32_t const next_crc =
- crc32_compute(p_req->write.p_data, p_req->write.len, &s_dfu_settings.progress.firmware_image_crc);
- ASSERT(p_req->callback.write);
- ret_code_t ret =
- nrf_dfu_flash_store(write_addr, p_req->write.p_data, p_req->write.len, p_req->callback.write);
- if (ret != NRF_SUCCESS)
- {
- /* When nrf_dfu_flash_store() fails because there is no space in the queue,
- * stop processing the request so that the peer can detect a CRC error
- * and retransmit this object. Remember to manually free the buffer !
- */
- p_req->callback.write((void*)p_req->write.p_data);
- return;
- }
- /* Update the CRC of the firmware image. */
- s_dfu_settings.write_offset += p_req->write.len;
- s_dfu_settings.progress.firmware_image_offset += p_req->write.len;
- s_dfu_settings.progress.firmware_image_crc = next_crc;
- /* This is only used when the PRN is triggered and the 'write' message
- * is answered with a CRC message and these field are copied into the response.
- */
- p_res->write.crc = s_dfu_settings.progress.firmware_image_crc;
- p_res->write.offset = s_dfu_settings.progress.firmware_image_offset;
- }
- static void on_data_obj_crc_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
- {
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_CRC_GET (data)");
- NRF_LOG_DEBUG("Offset:%d, CRC:0x%08x",
- s_dfu_settings.progress.firmware_image_offset,
- s_dfu_settings.progress.firmware_image_crc);
- p_res->crc.crc = s_dfu_settings.progress.firmware_image_crc;
- p_res->crc.offset = s_dfu_settings.progress.firmware_image_offset;
- }
- static void on_data_obj_execute_request_sched(void * p_evt, uint16_t event_length)
- {
- UNUSED_PARAMETER(event_length);
- ret_code_t ret;
- nrf_dfu_request_t * p_req = (nrf_dfu_request_t *)(p_evt);
- /* Wait for all buffers to be written in flash. */
- if (nrf_fstorage_is_busy(NULL))
- {
- ret = app_sched_event_put(p_req, sizeof(nrf_dfu_request_t), on_data_obj_execute_request_sched);
- if (ret != NRF_SUCCESS)
- {
- NRF_LOG_ERROR("Failed to schedule object execute: 0x%x.", ret);
- }
- return;
- }
- nrf_dfu_response_t res =
- {
- .request = NRF_DFU_OP_OBJECT_EXECUTE,
- };
- if (s_dfu_settings.progress.firmware_image_offset == m_firmware_size_req)
- {
- NRF_LOG_DEBUG("Whole firmware image received. Postvalidating.");
- #if NRF_DFU_IN_APP
- res.result = nrf_dfu_validation_post_data_execute(m_firmware_start_addr, m_firmware_size_req);
- #else
- res.result = nrf_dfu_validation_activation_prepare(m_firmware_start_addr, m_firmware_size_req);
- #endif
- res.result = ext_err_code_handle(res.result);
- /* Provide response to transport */
- p_req->callback.response(&res, p_req->p_context);
- ret = nrf_dfu_settings_write_and_backup((nrf_dfu_flash_callback_t)on_dfu_complete);
- UNUSED_RETURN_VALUE(ret);
- }
- else
- {
- res.result = NRF_DFU_RES_CODE_SUCCESS;
- /* Provide response to transport */
- p_req->callback.response(&res, p_req->p_context);
- if (NRF_DFU_SAVE_PROGRESS_IN_FLASH)
- {
- /* Allowing skipping settings backup to save time and flash wear. */
- ret = nrf_dfu_settings_write_and_backup(NULL);
- UNUSED_RETURN_VALUE(ret);
- }
- }
- NRF_LOG_DEBUG("Request handling complete. Result: 0x%x", res.result);
- }
- static bool on_data_obj_execute_request(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
- {
- NRF_LOG_DEBUG("Handle NRF_DFU_OP_OBJECT_EXECUTE (data)");
- uint32_t const data_object_size = s_dfu_settings.progress.firmware_image_offset -
- s_dfu_settings.progress.firmware_image_offset_last;
- if (s_dfu_settings.progress.data_object_size != data_object_size)
- {
- /* The size of the written object was not as expected. */
- NRF_LOG_ERROR("Invalid data. expected: %d, got: %d",
- s_dfu_settings.progress.data_object_size,
- data_object_size);
- p_res->result = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED;
- return true;
- }
- /* Update the offset and crc values for the last object written. */
- s_dfu_settings.progress.data_object_size = 0;
- s_dfu_settings.progress.firmware_image_crc_last = s_dfu_settings.progress.firmware_image_crc;
- s_dfu_settings.progress.firmware_image_offset_last = s_dfu_settings.progress.firmware_image_offset;
- on_data_obj_execute_request_sched(p_req, 0);
- m_observer(NRF_DFU_EVT_OBJECT_RECEIVED);
- return false;
- }
- static bool nrf_dfu_data_req(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
- {
- ASSERT(p_req);
- ASSERT(p_res);
- bool response_ready = true;
- switch (p_req->request)
- {
- case NRF_DFU_OP_OBJECT_CREATE:
- {
- on_data_obj_create_request(p_req, p_res);
- } break;
- case NRF_DFU_OP_OBJECT_WRITE:
- {
- on_data_obj_write_request(p_req, p_res);
- } break;
- case NRF_DFU_OP_CRC_GET:
- {
- on_data_obj_crc_request(p_req, p_res);
- } break;
- case NRF_DFU_OP_OBJECT_EXECUTE:
- {
- response_ready = on_data_obj_execute_request(p_req, p_res);
- } break;
- case NRF_DFU_OP_OBJECT_SELECT:
- {
- on_data_obj_select_request(p_req, p_res);
- } break;
- default:
- {
- ASSERT(false);
- } break;
- }
- return response_ready;
- }
- /**@brief Function for handling requests to manipulate data or command objects.
- *
- * @param[in] p_req Request.
- * @param[out] p_res Response.
- *
- * @return Whether response is ready to be sent.
- */
- static bool nrf_dfu_obj_op(nrf_dfu_request_t * p_req, nrf_dfu_response_t * p_res)
- {
- /* Keep track of the current object type since write and execute requests don't contain it. */
- static nrf_dfu_obj_type_t current_object = NRF_DFU_OBJ_TYPE_COMMAND;
- if ( (p_req->request == NRF_DFU_OP_OBJECT_SELECT)
- || (p_req->request == NRF_DFU_OP_OBJECT_CREATE))
- {
- STATIC_ASSERT(offsetof(nrf_dfu_request_select_t, object_type) ==
- offsetof(nrf_dfu_request_create_t, object_type),
- "Wrong object_type offset!");
- current_object = (nrf_dfu_obj_type_t)(p_req->select.object_type);
- }
- bool response_ready = true;
- switch (current_object)
- {
- case NRF_DFU_OBJ_TYPE_COMMAND:
- nrf_dfu_command_req(p_req, p_res);
- break;
- case NRF_DFU_OBJ_TYPE_DATA:
- response_ready = nrf_dfu_data_req(p_req, p_res);
- break;
- default:
- /* The select request had an invalid object type. */
- NRF_LOG_ERROR("Invalid object type in request.");
- current_object = NRF_DFU_OBJ_TYPE_INVALID;
- p_res->result = NRF_DFU_RES_CODE_INVALID_OBJECT;
- break;
- }
- return response_ready;
- }
- static void nrf_dfu_req_handler_req_process(nrf_dfu_request_t * p_req)
- {
- ASSERT(p_req->callback.response);
- bool response_ready = true;
- /* The request handlers assume these values to be set. */
- nrf_dfu_response_t response =
- {
- .request = p_req->request,
- .result = NRF_DFU_RES_CODE_SUCCESS,
- };
- switch (p_req->request)
- {
- #if !NRF_DFU_PROTOCOL_REDUCED
- case NRF_DFU_OP_PROTOCOL_VERSION:
- {
- on_protocol_version_request(p_req, &response);
- } break;
- case NRF_DFU_OP_HARDWARE_VERSION:
- {
- on_hw_version_request(p_req, &response);
- } break;
- case NRF_DFU_OP_FIRMWARE_VERSION:
- {
- on_fw_version_request(p_req, &response);
- } break;
- case NRF_DFU_OP_PING:
- {
- on_ping_request(p_req, &response);
- } break;
- case NRF_DFU_OP_MTU_GET:
- {
- on_mtu_get_request(p_req, &response);
- } break;
- #endif
- case NRF_DFU_OP_RECEIPT_NOTIF_SET:
- {
- on_prn_set_request(p_req, &response);
- } break;
- case NRF_DFU_OP_ABORT:
- {
- on_abort_request(p_req, &response);
- } break;
- case NRF_DFU_OP_OBJECT_CREATE:
- /* Restart the inactivity timer on CREATE messages. */
- /* Fallthrough. */
- case NRF_DFU_OP_OBJECT_SELECT:
- case NRF_DFU_OP_OBJECT_WRITE:
- case NRF_DFU_OP_OBJECT_EXECUTE:
- case NRF_DFU_OP_CRC_GET:
- {
- response_ready = nrf_dfu_obj_op(p_req, &response);
- } break;
- default:
- NRF_LOG_INFO("Invalid opcode received: 0x%x.", p_req->request);
- response.result = NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED;
- break;
- }
- if (response_ready)
- {
- NRF_LOG_DEBUG("Request handling complete. Result: 0x%x", response.result);
- p_req->callback.response(&response, p_req->p_context);
- if (response.result != NRF_DFU_RES_CODE_SUCCESS)
- {
- m_observer(NRF_DFU_EVT_DFU_FAILED);
- }
- }
- }
- static void nrf_dfu_req_handler_req(void * p_evt, uint16_t event_length)
- {
- nrf_dfu_request_t * p_req = (nrf_dfu_request_t *)(p_evt);
- nrf_dfu_req_handler_req_process(p_req);
- }
- ret_code_t nrf_dfu_req_handler_on_req(nrf_dfu_request_t * p_req)
- {
- ret_code_t ret;
- if (p_req->callback.response == NULL)
- {
- return NRF_ERROR_INVALID_PARAM;
- }
- ret = app_sched_event_put(p_req, sizeof(nrf_dfu_request_t), nrf_dfu_req_handler_req);
- if (ret != NRF_SUCCESS)
- {
- NRF_LOG_WARNING("Scheduler ran out of space!");
- }
- return ret;
- }
- ret_code_t nrf_dfu_req_handler_init(nrf_dfu_observer_t observer)
- {
- ret_code_t ret_val;
- nrf_dfu_result_t result;
- if (observer == NULL)
- {
- return NRF_ERROR_INVALID_PARAM;
- }
- #if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
- ret_val = nrf_dfu_flash_init(true);
- #else
- ret_val = nrf_dfu_flash_init(false);
- #endif
- if (ret_val != NRF_SUCCESS)
- {
- return ret_val;
- }
- nrf_dfu_validation_init();
- if (nrf_dfu_validation_init_cmd_present())
- {
- /* Execute a previously received init packed. Subsequent executes will have no effect. */
- result = nrf_dfu_validation_init_cmd_execute(&m_firmware_start_addr, &m_firmware_size_req);
- if (result != NRF_DFU_RES_CODE_SUCCESS)
- {
- /* Init packet in flash is not valid! */
- return NRF_ERROR_INTERNAL;
- }
- }
- m_observer = observer;
- /* Initialize extended error handling with "No error" as the most recent error. */
- result = ext_error_set(NRF_DFU_EXT_ERROR_NO_ERROR);
- UNUSED_RETURN_VALUE(result);
- return NRF_SUCCESS;
- }
|