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

SPI DFU write assert error

Hi,

I am working on having my device to perform a dfu over spi. I have been able to get through the init packet initialization and transfer, however, I am getting an error when I go when I call the on_data_obj_write_request(). Specifically when ASSERT(p_req->callback.write) is called. I get the error "received a fault! id: 0x00004002 , pc: 0x00000000" I have no idea how to go about solving this issue. If anyone can please at least help me to understand why this is happening, I would greatly appreciate it!

Parents
  • That is the guide I have followed. I am currently using sdk 15.2.0 and have updated it to work with the code found in your link. However, like I said, I am still having trouble with the assert error coming from when the DFU_Master is trying to write the firmware image to the bootloader through SPI.

  • Hi,

    The 0x00004002 refers to this error NRF_FAULT_ID_SDK_ASSERT, so the callback.write (call back for flash after writing is done) was not set to anything so ASSERT(p_req->callback.write) will fail. So seems like the function on_data_obj_write_request() was called with nothing inside p_req->callback.write.

    Regards,
    Jonathan

  • After debugging my code I can see what you mean that p_req->callback.write having no value. How would I go about solving this error. What is the point of p_req->callback.write? I have tried to look through nrf_dfu_req_handler.c to see where else is it called/set to a specific value and I still cant understand why it is there. I have attached my nrf_dfu_req_handler.c and the nrf_spis_dfu.c file that I have been using as I have made some modifications to both.

    nrf_spis_dfu.c : 

    /**
     * Copyright (c) 2016 - 2017, 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 <string.h>
    #include <stdlib.h>
    #include "boards.h"
    #include "app_util_platform.h"
    #include "nrf_dfu_transport.h"
    #include "nrf_dfu_req_handler.h"
    #include "nrf_dfu_handling_error.h"
    #include "sdk_config.h"
    #include "nrf_delay.h"
    
    #include "nrf_log.h"
    #include "nrf_drv_spis.h"
    #include "nrf_spis_dfu.h"
    #define AVAILABLE_LED_PIN_NO            BSP_LED_0                                                   /**< Is on when serial DFU transport is enabled (but not connected). */
    #define CONNECTED_LED_PIN_NO            BSP_LED_1                                                   /**< Is on when device has connected. */
    
    
    #define CREATE_OBJECT_REQUEST_LEN       (sizeof(uint8_t)+sizeof(uint32_t))
    #define SET_RECEIPT_NOTIF_REQUEST_LEN   (sizeof(uint16_t))
    #define CALCULATE_CRC_REQUEST_LEN       0
    #define EXECUTE_OBJECT_REQUEST_LEN      0
    #define SELECT_OBJECT_REQUEST_LEN       (sizeof(uint8_t))
    #define GET_SERIAL_MTU_REQUEST_LEN      0
    
    #define MAX_RESPONSE_SIZE               (1+1+3*4)
    
    static spi_dfu_t m_dfu;
    #define SPIS_INSTANCE 1 /**< SPIS instance index. */
    static const nrf_drv_spis_t spis = NRF_DRV_SPIS_INSTANCE(SPIS_INSTANCE);/**< SPIS instance. */
    static volatile bool spis_xfer_done; /**< Flag used to indicate that SPIS instance completed the transfer. */
    
    static uint8_t spi_rx_buffer[128+1];
    static const uint8_t m_length = sizeof(spi_rx_buffer);        /**< Transfer length. */
    static uint8_t       m_tx_buf[MAX_RESPONSE_SIZE];          /**< TX buffer. */
    
    
    DFU_TRANSPORT_REGISTER(nrf_dfu_transport_t const dfu_trans) =
    {
        .init_func  = spis_dfu_transport_init,
        .close_func = spis_dfu_transport_close
    };
    
    
    ANON_UNIONS_ENABLE;
    
    typedef struct
    {
        uint8_t            op_code;
        nrf_dfu_result_t resp_val;
        union
        {
            struct
            {
                uint32_t offset;
                uint32_t crc;
            }crc_response;
    
            struct
            {
                uint32_t max_size;
                uint32_t offset;
                uint32_t crc;
            }select_response;
    
            struct
            {
                uint16_t mtu;
            }serial_mtu_response;
    
            struct
            {
                uint8_t ping_id;
            }ping_response;
        };
    
    }spi_dfu_response_t;
    
    ANON_UNIONS_DISABLE;
    
    
    /**@brief       Function for the LEDs initialization.
     *
     * @details     Initializes all LEDs used by this application.
     */
    static void leds_init(void)
    {
        nrf_gpio_cfg_output(AVAILABLE_LED_PIN_NO);
        nrf_gpio_cfg_output(CONNECTED_LED_PIN_NO);
        nrf_gpio_pin_clear(AVAILABLE_LED_PIN_NO);
        nrf_gpio_pin_set(CONNECTED_LED_PIN_NO);
    }
    
    static void response_send(spi_dfu_t          * p_dfu,
                              spi_dfu_response_t * p_response)
    {
        uint8_t response_buffer[MAX_RESPONSE_SIZE] = {0};
        uint16_t index = 0;
    
        NRF_LOG_DEBUG("Sending Response: [0x%01x, 0x%01x]", p_response->op_code, p_response->resp_val);
    
        response_buffer[index++] = SERIAL_DFU_OP_CODE_RESPONSE;
    
        // Encode the Request Op code
        response_buffer[index++] = p_response->op_code;
    
        // Encode the Response Value.
        response_buffer[index++] = (uint8_t)p_response->resp_val;
    
        if (p_response->resp_val == NRF_DFU_RES_CODE_SUCCESS)
        {
            switch (p_response->op_code)
            {
                case SERIAL_DFU_OP_CODE_CALCULATE_CRC:
                    index += uint32_encode(p_response->crc_response.offset, &response_buffer[index]);
                    index += uint32_encode(p_response->crc_response.crc, &response_buffer[index]);
                    break;
    
                case SERIAL_DFU_OP_CODE_SELECT_OBJECT:
                    index += uint32_encode(p_response->select_response.max_size, &response_buffer[index]);
                    index += uint32_encode(p_response->select_response.offset, &response_buffer[index-1]);
                    index += uint32_encode(p_response->select_response.crc, &response_buffer[index-1]);
                    break;
    
                case SERIAL_DFU_OP_CODE_GET_SERIAL_MTU:
                    index += uint16_encode(p_response->serial_mtu_response.mtu, &response_buffer[index]);
                    break;
    
                case SERIAL_DFU_OP_CODE_PING:
                    response_buffer[index] = p_response->ping_response.ping_id;
                    index += sizeof(uint8_t);
                    break;
    
                default:
                    // no implementation
                    break;
            }
        }
        else if (p_response->resp_val == NRF_DFU_RES_CODE_EXT_ERROR)
        {
            response_buffer[index++] = ext_error_get();
            // Clear the last extended error code
            (void) ext_error_set(NRF_DFU_EXT_ERROR_NO_ERROR);
        }
    
        // send
          memcpy(m_tx_buf,response_buffer,index);
          nrf_drv_spis_buffers_set(&spis, m_tx_buf, index, spi_rx_buffer, m_length);
          //NRF_LOG_DEBUG("response send spi_rx_buffer[0]: 0x%X",spi_rx_buffer[0]);
     
    }
    
    static void on_packet_received(spi_dfu_t * p_dfu)
    {   
        //NRF_LOG_DEBUG("Received: %p",p_dfu);
        nrf_dfu_request_t dfu_req;
        nrf_dfu_response_t dfu_res = {0};
        spi_dfu_response_t serial_response = {0};
        
        //NRF_LOG_DEBUG("payload length: %i",p_dfu->recv_length);
    
        memset(&dfu_req, 0, sizeof(nrf_dfu_request_t));
    
        const serial_dfu_op_code_t op_code             = (serial_dfu_op_code_t)p_dfu->recv_buffer[0];
        //for(int loop = 0; loop < 5; loop++)
          //  NRF_LOG_DEBUG("recv_buffer[%i]: 0x%X", loop, p_dfu->recv_buffer[loop]);
        const uint16_t             packet_payload_len  = p_dfu->recv_length;
        NRF_LOG_DEBUG("payload length: %i",packet_payload_len);
        uint8_t * p_payload                            = &p_dfu->recv_buffer[1];
    
        serial_response.op_code = op_code;
    
        NRF_LOG_DEBUG("Opcode received: 0x%x",op_code);
    
        nrf_gpio_pin_clear(CONNECTED_LED_PIN_NO);
        nrf_gpio_pin_set(AVAILABLE_LED_PIN_NO);
        switch (op_code)
        {
            case SERIAL_DFU_OP_CODE_CREATE_OBJECT:
    
                if (packet_payload_len != CREATE_OBJECT_REQUEST_LEN)
                {
                    serial_response.resp_val = NRF_DFU_RES_CODE_INVALID_PARAMETER;
                    break;
                }
    
                NRF_LOG_DEBUG("Received create object");
    
                // Reset the packet receipt notification on create object
                p_dfu->pkt_notif_target_count = p_dfu->pkt_notif_target;
    
                // Get type parameter
                dfu_req.create.object_type =  p_payload[0];
    
                // Get length value
                dfu_req.create.object_size = uint32_decode(&p_payload[1]);
    
                // Set req type
                dfu_req.request = NRF_DFU_OP_OBJECT_CREATE;
    
                serial_response.resp_val = nrf_dfu_req_handler_on_req(&dfu_req, &dfu_res);
                break;
    
            case SERIAL_DFU_OP_CODE_SET_RECEIPT_NOTIF:
                NRF_LOG_DEBUG("Set receipt notif");
                if (packet_payload_len != SET_RECEIPT_NOTIF_REQUEST_LEN)
                {
                    serial_response.resp_val = NRF_DFU_RES_CODE_INVALID_PARAMETER;
                    break;
                }
    
                p_dfu->pkt_notif_target       = uint16_decode(&p_payload[0]);
                p_dfu->pkt_notif_target_count = p_dfu->pkt_notif_target;
    
                serial_response.resp_val = NRF_DFU_RES_CODE_SUCCESS;
                break;
    
            case SERIAL_DFU_OP_CODE_CALCULATE_CRC:
                NRF_LOG_DEBUG("Received calculate CRC");
    
                dfu_req.request =  NRF_DFU_OP_CRC_GET;
    
                serial_response.resp_val            = nrf_dfu_req_handler_on_req(&dfu_req, &dfu_res);
                serial_response.crc_response.offset = dfu_res.crc.offset;
                serial_response.crc_response.crc    = dfu_res.crc.crc;
                break;
    
            case SERIAL_DFU_OP_CODE_EXECUTE_OBJECT:
                NRF_LOG_DEBUG("Received execute object");
    
                // Set req type
                dfu_req.request =  NRF_DFU_OP_OBJECT_EXECUTE;
    
                serial_response.resp_val =nrf_dfu_req_handler_on_req(&dfu_req, &dfu_res);
                break;
    
            case SERIAL_DFU_OP_CODE_SELECT_OBJECT:
    
                NRF_LOG_DEBUG("Received select object");
                if (packet_payload_len != SELECT_OBJECT_REQUEST_LEN)
                {
                    serial_response.resp_val = NRF_DFU_RES_CODE_INVALID_PARAMETER;
                    break;
                }
    
                // Set object type to read info about
                dfu_req.select.object_type = p_payload[0];
    
                dfu_req.request = NRF_DFU_OP_OBJECT_SELECT;
    
                serial_response.resp_val = nrf_dfu_req_handler_on_req(&dfu_req, &dfu_res);
                serial_response.select_response.max_size = dfu_res.select.max_size;
                serial_response.select_response.offset   = dfu_res.select.offset;
                serial_response.select_response.crc      = dfu_res.select.crc;
                break;
    
            case SERIAL_DFU_OP_CODE_GET_SERIAL_MTU:
                NRF_LOG_DEBUG("Received get serial mtu");
    
                serial_response.resp_val = NRF_DFU_RES_CODE_SUCCESS;
                serial_response.serial_mtu_response.mtu = sizeof(p_dfu->recv_buffer);
                break;
    
            case SERIAL_DFU_OP_CODE_WRITE_OBJECT:
                 // Set req type
                dfu_req.request =   NRF_DFU_OP_OBJECT_WRITE;
                NRF_LOG_DEBUG("dfu request: %X", dfu_req.request);
    
                // Set data and length
                dfu_req.write.p_data   = &p_payload[0];
                NRF_LOG_DEBUG("write.p_data: 0x%x", dfu_req.write.p_data);
                //for(int loop = 0; loop<sizeof(p_payload); loop++)
                      //NRF_LOG_DEBUG("dfu request write p_payload[%i]: 0x%X", loop,p_payload[loop]);
                dfu_req.write.len = packet_payload_len;
                NRF_LOG_DEBUG("dfu request write length: 0x%X", packet_payload_len);
    
                serial_response.resp_val = nrf_dfu_req_handler_on_req(&dfu_req, &dfu_res);
                if (serial_response.resp_val != NRF_DFU_RES_CODE_SUCCESS)
                {
                    NRF_LOG_ERROR("Failure to run packet write");
                }
    
                    serial_response.op_code             = SERIAL_DFU_OP_CODE_CALCULATE_CRC;
                    serial_response.crc_response.offset = dfu_res.crc.offset;
                    serial_response.crc_response.crc    = dfu_res.crc.crc;
    
                    // Reset the counter for the number of firmware packets.
                    p_dfu->pkt_notif_target_count = p_dfu->pkt_notif_target;
    
                    response_send(p_dfu, &serial_response);
                
               
                break;
    
            case SERIAL_DFU_OP_CODE_PING:
                if (packet_payload_len != sizeof(serial_response.ping_response))
                {
                    serial_response.resp_val = NRF_DFU_RES_CODE_INVALID_PARAMETER;
                    break;
                }
    
                serial_response.resp_val = NRF_DFU_RES_CODE_SUCCESS;
                serial_response.ping_response.ping_id = p_payload[0];
    
                NRF_LOG_DEBUG("Received ping %d", p_payload[0]);
                break;
    
            default:
                // Unsupported op code.
                NRF_LOG_WARNING("Received unsupported OP code");
                serial_response.resp_val = NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED;
                break;
        }
    
        if (op_code != SERIAL_DFU_OP_CODE_WRITE_OBJECT)
        {
            response_send(p_dfu, &serial_response);
        }
       
    }
    
    
    
    /**
     * @brief SPIS user event handler.
     *
     * @param event
     */
    void spis_event_handler(nrf_drv_spis_event_t event)
    {
        if (event.evt_type == NRF_DRV_SPIS_XFER_DONE)
        {
            //spis_xfer_done = true;
            NRF_LOG_INFO(" Transfer completed. Received: %d bytes",event.rx_amount);
            NRF_LOG_DEBUG("event handler spi_rx_buffer[0]: 0x%X",spi_rx_buffer[0]);
    
            if ((event.rx_amount)&&(spi_rx_buffer[0]!=0xFF))
            {
                memcpy(m_dfu.recv_buffer,spi_rx_buffer,event.rx_amount);
                m_dfu.recv_length= event.rx_amount-1;
                on_packet_received(&m_dfu);
            }
             
            else{
                 NRF_LOG_INFO(" No command received start RX again");
                 nrf_drv_spis_buffers_set(&spis, m_tx_buf, 0, spi_rx_buffer, m_length);
                
                 //Could be the last response, check if dfu is waiting for a reset
                 //nrf_dfu_req_handler_reset_if_dfu_complete();
            }
        }
        
        if (event.evt_type == NRF_DRV_SPIS_BUFFERS_SET_DONE)
        {
            
        }
        
            
    }
    
    uint32_t spis_dfu_transport_init(void)
    {
        uint32_t err_code;
        
        leds_init();
        
        // Enable the constant latency sub power mode to minimize the time it takes
        // for the SPIS peripheral to become active after the CSN line is asserted
        // (when the CPU is in sleep mode).
        NRF_POWER->TASKS_CONSTLAT = 1;
        nrf_drv_spis_config_t spis_config = NRF_DRV_SPIS_DEFAULT_CONFIG;
        spis_config.csn_pin               = APP_SPIS_CS_PIN;
        spis_config.miso_pin              = APP_SPIS_MISO_PIN;
        spis_config.mosi_pin              = APP_SPIS_MOSI_PIN;
        spis_config.sck_pin               = APP_SPIS_SCK_PIN;
    
        err_code = nrf_drv_spis_init(&spis, &spis_config, spis_event_handler);
    
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Failed initializing SPIS");
            return err_code;
        }
        //Start RX
        //NRF_LOG_DEBUG("dfu transport spi_rx_buffer[0]: 0x%X",spi_rx_buffer[0]);
        err_code = nrf_drv_spis_buffers_set(&spis, m_tx_buf, 0, spi_rx_buffer, m_length);
        APP_ERROR_CHECK(err_code);
        return NRF_SUCCESS;
    }
    
    
    uint32_t spis_dfu_transport_close(void)
    {
        NRF_POWER->TASKS_LOWPWR = 1;
        nrf_drv_spis_uninit(&spis);
        return NRF_SUCCESS;
    }
    

    nrf_dfu_req_handler.c

    /**
     * Copyright (c) 2016 - 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.
     *
     */
    #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)
    
    
    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);
        }
    }
    
    
    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;
    }
    
    
    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;
    
        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     =
            crc32_compute(p_req->write.p_data, p_req->write.len, &s_dfu_settings.progress.firmware_image_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.");
    
            res.result = nrf_dfu_validation_post_data_execute(m_firmware_start_addr, m_firmware_size_req);
            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)
        {
            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_RECEIPT_NOTIF_SET:
            {
                on_prn_set_request(p_req, &response);
            } break;
    
            case NRF_DFU_OP_MTU_GET:
            {
                on_mtu_get_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, nrf_dfu_response_t * p_res)
    {
        nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
    
        static nrf_dfu_obj_type_t cur_obj_type = NRF_DFU_OBJ_TYPE_COMMAND;
        switch (p_req->request)
        {
            case NRF_DFU_OP_OBJECT_CREATE:
                if ((nrf_dfu_obj_type_t)p_req->create.object_type == NRF_DFU_OBJ_TYPE_COMMAND)
                {
                    cur_obj_type = NRF_DFU_OBJ_TYPE_COMMAND;
                }
                else if ((nrf_dfu_obj_type_t)p_req->create.object_type == NRF_DFU_OBJ_TYPE_DATA)
                {
                    cur_obj_type = NRF_DFU_OBJ_TYPE_DATA;
                }
                else
                {
                    return NRF_DFU_RES_CODE_UNSUPPORTED_TYPE;
                }
                break;
            case NRF_DFU_OP_OBJECT_SELECT:
                if ((nrf_dfu_obj_type_t)p_req->select.object_type == NRF_DFU_OBJ_TYPE_COMMAND)
                {
                    cur_obj_type = NRF_DFU_OBJ_TYPE_COMMAND;
                }
                else if ((nrf_dfu_obj_type_t)p_req->select.object_type == NRF_DFU_OBJ_TYPE_DATA)
                {
                    cur_obj_type = NRF_DFU_OBJ_TYPE_DATA;
                }
                else
                {
                    return NRF_DFU_RES_CODE_UNSUPPORTED_TYPE;
                }
                break;
            default:
                // no implementation
                break;
        }
    
        switch (cur_obj_type)
        {
            case NRF_DFU_OBJ_TYPE_COMMAND:
                nrf_dfu_command_req(p_req, p_res);
                break;
    
            case NRF_DFU_OBJ_TYPE_DATA:
                nrf_dfu_data_req(p_req, p_res);
                break;
    
            default:
                NRF_LOG_ERROR("Invalid request type");
                ret_val = NRF_DFU_RES_CODE_INVALID_OBJECT;
                break;
        }
    
        return ret_val;
    }
    
    
    /*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;
        }
    
    #ifdef BLE_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;
    }
    

Reply
  • After debugging my code I can see what you mean that p_req->callback.write having no value. How would I go about solving this error. What is the point of p_req->callback.write? I have tried to look through nrf_dfu_req_handler.c to see where else is it called/set to a specific value and I still cant understand why it is there. I have attached my nrf_dfu_req_handler.c and the nrf_spis_dfu.c file that I have been using as I have made some modifications to both.

    nrf_spis_dfu.c : 

    /**
     * Copyright (c) 2016 - 2017, 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 <string.h>
    #include <stdlib.h>
    #include "boards.h"
    #include "app_util_platform.h"
    #include "nrf_dfu_transport.h"
    #include "nrf_dfu_req_handler.h"
    #include "nrf_dfu_handling_error.h"
    #include "sdk_config.h"
    #include "nrf_delay.h"
    
    #include "nrf_log.h"
    #include "nrf_drv_spis.h"
    #include "nrf_spis_dfu.h"
    #define AVAILABLE_LED_PIN_NO            BSP_LED_0                                                   /**< Is on when serial DFU transport is enabled (but not connected). */
    #define CONNECTED_LED_PIN_NO            BSP_LED_1                                                   /**< Is on when device has connected. */
    
    
    #define CREATE_OBJECT_REQUEST_LEN       (sizeof(uint8_t)+sizeof(uint32_t))
    #define SET_RECEIPT_NOTIF_REQUEST_LEN   (sizeof(uint16_t))
    #define CALCULATE_CRC_REQUEST_LEN       0
    #define EXECUTE_OBJECT_REQUEST_LEN      0
    #define SELECT_OBJECT_REQUEST_LEN       (sizeof(uint8_t))
    #define GET_SERIAL_MTU_REQUEST_LEN      0
    
    #define MAX_RESPONSE_SIZE               (1+1+3*4)
    
    static spi_dfu_t m_dfu;
    #define SPIS_INSTANCE 1 /**< SPIS instance index. */
    static const nrf_drv_spis_t spis = NRF_DRV_SPIS_INSTANCE(SPIS_INSTANCE);/**< SPIS instance. */
    static volatile bool spis_xfer_done; /**< Flag used to indicate that SPIS instance completed the transfer. */
    
    static uint8_t spi_rx_buffer[128+1];
    static const uint8_t m_length = sizeof(spi_rx_buffer);        /**< Transfer length. */
    static uint8_t       m_tx_buf[MAX_RESPONSE_SIZE];          /**< TX buffer. */
    
    
    DFU_TRANSPORT_REGISTER(nrf_dfu_transport_t const dfu_trans) =
    {
        .init_func  = spis_dfu_transport_init,
        .close_func = spis_dfu_transport_close
    };
    
    
    ANON_UNIONS_ENABLE;
    
    typedef struct
    {
        uint8_t            op_code;
        nrf_dfu_result_t resp_val;
        union
        {
            struct
            {
                uint32_t offset;
                uint32_t crc;
            }crc_response;
    
            struct
            {
                uint32_t max_size;
                uint32_t offset;
                uint32_t crc;
            }select_response;
    
            struct
            {
                uint16_t mtu;
            }serial_mtu_response;
    
            struct
            {
                uint8_t ping_id;
            }ping_response;
        };
    
    }spi_dfu_response_t;
    
    ANON_UNIONS_DISABLE;
    
    
    /**@brief       Function for the LEDs initialization.
     *
     * @details     Initializes all LEDs used by this application.
     */
    static void leds_init(void)
    {
        nrf_gpio_cfg_output(AVAILABLE_LED_PIN_NO);
        nrf_gpio_cfg_output(CONNECTED_LED_PIN_NO);
        nrf_gpio_pin_clear(AVAILABLE_LED_PIN_NO);
        nrf_gpio_pin_set(CONNECTED_LED_PIN_NO);
    }
    
    static void response_send(spi_dfu_t          * p_dfu,
                              spi_dfu_response_t * p_response)
    {
        uint8_t response_buffer[MAX_RESPONSE_SIZE] = {0};
        uint16_t index = 0;
    
        NRF_LOG_DEBUG("Sending Response: [0x%01x, 0x%01x]", p_response->op_code, p_response->resp_val);
    
        response_buffer[index++] = SERIAL_DFU_OP_CODE_RESPONSE;
    
        // Encode the Request Op code
        response_buffer[index++] = p_response->op_code;
    
        // Encode the Response Value.
        response_buffer[index++] = (uint8_t)p_response->resp_val;
    
        if (p_response->resp_val == NRF_DFU_RES_CODE_SUCCESS)
        {
            switch (p_response->op_code)
            {
                case SERIAL_DFU_OP_CODE_CALCULATE_CRC:
                    index += uint32_encode(p_response->crc_response.offset, &response_buffer[index]);
                    index += uint32_encode(p_response->crc_response.crc, &response_buffer[index]);
                    break;
    
                case SERIAL_DFU_OP_CODE_SELECT_OBJECT:
                    index += uint32_encode(p_response->select_response.max_size, &response_buffer[index]);
                    index += uint32_encode(p_response->select_response.offset, &response_buffer[index-1]);
                    index += uint32_encode(p_response->select_response.crc, &response_buffer[index-1]);
                    break;
    
                case SERIAL_DFU_OP_CODE_GET_SERIAL_MTU:
                    index += uint16_encode(p_response->serial_mtu_response.mtu, &response_buffer[index]);
                    break;
    
                case SERIAL_DFU_OP_CODE_PING:
                    response_buffer[index] = p_response->ping_response.ping_id;
                    index += sizeof(uint8_t);
                    break;
    
                default:
                    // no implementation
                    break;
            }
        }
        else if (p_response->resp_val == NRF_DFU_RES_CODE_EXT_ERROR)
        {
            response_buffer[index++] = ext_error_get();
            // Clear the last extended error code
            (void) ext_error_set(NRF_DFU_EXT_ERROR_NO_ERROR);
        }
    
        // send
          memcpy(m_tx_buf,response_buffer,index);
          nrf_drv_spis_buffers_set(&spis, m_tx_buf, index, spi_rx_buffer, m_length);
          //NRF_LOG_DEBUG("response send spi_rx_buffer[0]: 0x%X",spi_rx_buffer[0]);
     
    }
    
    static void on_packet_received(spi_dfu_t * p_dfu)
    {   
        //NRF_LOG_DEBUG("Received: %p",p_dfu);
        nrf_dfu_request_t dfu_req;
        nrf_dfu_response_t dfu_res = {0};
        spi_dfu_response_t serial_response = {0};
        
        //NRF_LOG_DEBUG("payload length: %i",p_dfu->recv_length);
    
        memset(&dfu_req, 0, sizeof(nrf_dfu_request_t));
    
        const serial_dfu_op_code_t op_code             = (serial_dfu_op_code_t)p_dfu->recv_buffer[0];
        //for(int loop = 0; loop < 5; loop++)
          //  NRF_LOG_DEBUG("recv_buffer[%i]: 0x%X", loop, p_dfu->recv_buffer[loop]);
        const uint16_t             packet_payload_len  = p_dfu->recv_length;
        NRF_LOG_DEBUG("payload length: %i",packet_payload_len);
        uint8_t * p_payload                            = &p_dfu->recv_buffer[1];
    
        serial_response.op_code = op_code;
    
        NRF_LOG_DEBUG("Opcode received: 0x%x",op_code);
    
        nrf_gpio_pin_clear(CONNECTED_LED_PIN_NO);
        nrf_gpio_pin_set(AVAILABLE_LED_PIN_NO);
        switch (op_code)
        {
            case SERIAL_DFU_OP_CODE_CREATE_OBJECT:
    
                if (packet_payload_len != CREATE_OBJECT_REQUEST_LEN)
                {
                    serial_response.resp_val = NRF_DFU_RES_CODE_INVALID_PARAMETER;
                    break;
                }
    
                NRF_LOG_DEBUG("Received create object");
    
                // Reset the packet receipt notification on create object
                p_dfu->pkt_notif_target_count = p_dfu->pkt_notif_target;
    
                // Get type parameter
                dfu_req.create.object_type =  p_payload[0];
    
                // Get length value
                dfu_req.create.object_size = uint32_decode(&p_payload[1]);
    
                // Set req type
                dfu_req.request = NRF_DFU_OP_OBJECT_CREATE;
    
                serial_response.resp_val = nrf_dfu_req_handler_on_req(&dfu_req, &dfu_res);
                break;
    
            case SERIAL_DFU_OP_CODE_SET_RECEIPT_NOTIF:
                NRF_LOG_DEBUG("Set receipt notif");
                if (packet_payload_len != SET_RECEIPT_NOTIF_REQUEST_LEN)
                {
                    serial_response.resp_val = NRF_DFU_RES_CODE_INVALID_PARAMETER;
                    break;
                }
    
                p_dfu->pkt_notif_target       = uint16_decode(&p_payload[0]);
                p_dfu->pkt_notif_target_count = p_dfu->pkt_notif_target;
    
                serial_response.resp_val = NRF_DFU_RES_CODE_SUCCESS;
                break;
    
            case SERIAL_DFU_OP_CODE_CALCULATE_CRC:
                NRF_LOG_DEBUG("Received calculate CRC");
    
                dfu_req.request =  NRF_DFU_OP_CRC_GET;
    
                serial_response.resp_val            = nrf_dfu_req_handler_on_req(&dfu_req, &dfu_res);
                serial_response.crc_response.offset = dfu_res.crc.offset;
                serial_response.crc_response.crc    = dfu_res.crc.crc;
                break;
    
            case SERIAL_DFU_OP_CODE_EXECUTE_OBJECT:
                NRF_LOG_DEBUG("Received execute object");
    
                // Set req type
                dfu_req.request =  NRF_DFU_OP_OBJECT_EXECUTE;
    
                serial_response.resp_val =nrf_dfu_req_handler_on_req(&dfu_req, &dfu_res);
                break;
    
            case SERIAL_DFU_OP_CODE_SELECT_OBJECT:
    
                NRF_LOG_DEBUG("Received select object");
                if (packet_payload_len != SELECT_OBJECT_REQUEST_LEN)
                {
                    serial_response.resp_val = NRF_DFU_RES_CODE_INVALID_PARAMETER;
                    break;
                }
    
                // Set object type to read info about
                dfu_req.select.object_type = p_payload[0];
    
                dfu_req.request = NRF_DFU_OP_OBJECT_SELECT;
    
                serial_response.resp_val = nrf_dfu_req_handler_on_req(&dfu_req, &dfu_res);
                serial_response.select_response.max_size = dfu_res.select.max_size;
                serial_response.select_response.offset   = dfu_res.select.offset;
                serial_response.select_response.crc      = dfu_res.select.crc;
                break;
    
            case SERIAL_DFU_OP_CODE_GET_SERIAL_MTU:
                NRF_LOG_DEBUG("Received get serial mtu");
    
                serial_response.resp_val = NRF_DFU_RES_CODE_SUCCESS;
                serial_response.serial_mtu_response.mtu = sizeof(p_dfu->recv_buffer);
                break;
    
            case SERIAL_DFU_OP_CODE_WRITE_OBJECT:
                 // Set req type
                dfu_req.request =   NRF_DFU_OP_OBJECT_WRITE;
                NRF_LOG_DEBUG("dfu request: %X", dfu_req.request);
    
                // Set data and length
                dfu_req.write.p_data   = &p_payload[0];
                NRF_LOG_DEBUG("write.p_data: 0x%x", dfu_req.write.p_data);
                //for(int loop = 0; loop<sizeof(p_payload); loop++)
                      //NRF_LOG_DEBUG("dfu request write p_payload[%i]: 0x%X", loop,p_payload[loop]);
                dfu_req.write.len = packet_payload_len;
                NRF_LOG_DEBUG("dfu request write length: 0x%X", packet_payload_len);
    
                serial_response.resp_val = nrf_dfu_req_handler_on_req(&dfu_req, &dfu_res);
                if (serial_response.resp_val != NRF_DFU_RES_CODE_SUCCESS)
                {
                    NRF_LOG_ERROR("Failure to run packet write");
                }
    
                    serial_response.op_code             = SERIAL_DFU_OP_CODE_CALCULATE_CRC;
                    serial_response.crc_response.offset = dfu_res.crc.offset;
                    serial_response.crc_response.crc    = dfu_res.crc.crc;
    
                    // Reset the counter for the number of firmware packets.
                    p_dfu->pkt_notif_target_count = p_dfu->pkt_notif_target;
    
                    response_send(p_dfu, &serial_response);
                
               
                break;
    
            case SERIAL_DFU_OP_CODE_PING:
                if (packet_payload_len != sizeof(serial_response.ping_response))
                {
                    serial_response.resp_val = NRF_DFU_RES_CODE_INVALID_PARAMETER;
                    break;
                }
    
                serial_response.resp_val = NRF_DFU_RES_CODE_SUCCESS;
                serial_response.ping_response.ping_id = p_payload[0];
    
                NRF_LOG_DEBUG("Received ping %d", p_payload[0]);
                break;
    
            default:
                // Unsupported op code.
                NRF_LOG_WARNING("Received unsupported OP code");
                serial_response.resp_val = NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED;
                break;
        }
    
        if (op_code != SERIAL_DFU_OP_CODE_WRITE_OBJECT)
        {
            response_send(p_dfu, &serial_response);
        }
       
    }
    
    
    
    /**
     * @brief SPIS user event handler.
     *
     * @param event
     */
    void spis_event_handler(nrf_drv_spis_event_t event)
    {
        if (event.evt_type == NRF_DRV_SPIS_XFER_DONE)
        {
            //spis_xfer_done = true;
            NRF_LOG_INFO(" Transfer completed. Received: %d bytes",event.rx_amount);
            NRF_LOG_DEBUG("event handler spi_rx_buffer[0]: 0x%X",spi_rx_buffer[0]);
    
            if ((event.rx_amount)&&(spi_rx_buffer[0]!=0xFF))
            {
                memcpy(m_dfu.recv_buffer,spi_rx_buffer,event.rx_amount);
                m_dfu.recv_length= event.rx_amount-1;
                on_packet_received(&m_dfu);
            }
             
            else{
                 NRF_LOG_INFO(" No command received start RX again");
                 nrf_drv_spis_buffers_set(&spis, m_tx_buf, 0, spi_rx_buffer, m_length);
                
                 //Could be the last response, check if dfu is waiting for a reset
                 //nrf_dfu_req_handler_reset_if_dfu_complete();
            }
        }
        
        if (event.evt_type == NRF_DRV_SPIS_BUFFERS_SET_DONE)
        {
            
        }
        
            
    }
    
    uint32_t spis_dfu_transport_init(void)
    {
        uint32_t err_code;
        
        leds_init();
        
        // Enable the constant latency sub power mode to minimize the time it takes
        // for the SPIS peripheral to become active after the CSN line is asserted
        // (when the CPU is in sleep mode).
        NRF_POWER->TASKS_CONSTLAT = 1;
        nrf_drv_spis_config_t spis_config = NRF_DRV_SPIS_DEFAULT_CONFIG;
        spis_config.csn_pin               = APP_SPIS_CS_PIN;
        spis_config.miso_pin              = APP_SPIS_MISO_PIN;
        spis_config.mosi_pin              = APP_SPIS_MOSI_PIN;
        spis_config.sck_pin               = APP_SPIS_SCK_PIN;
    
        err_code = nrf_drv_spis_init(&spis, &spis_config, spis_event_handler);
    
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Failed initializing SPIS");
            return err_code;
        }
        //Start RX
        //NRF_LOG_DEBUG("dfu transport spi_rx_buffer[0]: 0x%X",spi_rx_buffer[0]);
        err_code = nrf_drv_spis_buffers_set(&spis, m_tx_buf, 0, spi_rx_buffer, m_length);
        APP_ERROR_CHECK(err_code);
        return NRF_SUCCESS;
    }
    
    
    uint32_t spis_dfu_transport_close(void)
    {
        NRF_POWER->TASKS_LOWPWR = 1;
        nrf_drv_spis_uninit(&spis);
        return NRF_SUCCESS;
    }
    

    nrf_dfu_req_handler.c

    /**
     * Copyright (c) 2016 - 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.
     *
     */
    #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)
    
    
    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);
        }
    }
    
    
    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;
    }
    
    
    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;
    
        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     =
            crc32_compute(p_req->write.p_data, p_req->write.len, &s_dfu_settings.progress.firmware_image_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.");
    
            res.result = nrf_dfu_validation_post_data_execute(m_firmware_start_addr, m_firmware_size_req);
            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)
        {
            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_RECEIPT_NOTIF_SET:
            {
                on_prn_set_request(p_req, &response);
            } break;
    
            case NRF_DFU_OP_MTU_GET:
            {
                on_mtu_get_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, nrf_dfu_response_t * p_res)
    {
        nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS;
    
        static nrf_dfu_obj_type_t cur_obj_type = NRF_DFU_OBJ_TYPE_COMMAND;
        switch (p_req->request)
        {
            case NRF_DFU_OP_OBJECT_CREATE:
                if ((nrf_dfu_obj_type_t)p_req->create.object_type == NRF_DFU_OBJ_TYPE_COMMAND)
                {
                    cur_obj_type = NRF_DFU_OBJ_TYPE_COMMAND;
                }
                else if ((nrf_dfu_obj_type_t)p_req->create.object_type == NRF_DFU_OBJ_TYPE_DATA)
                {
                    cur_obj_type = NRF_DFU_OBJ_TYPE_DATA;
                }
                else
                {
                    return NRF_DFU_RES_CODE_UNSUPPORTED_TYPE;
                }
                break;
            case NRF_DFU_OP_OBJECT_SELECT:
                if ((nrf_dfu_obj_type_t)p_req->select.object_type == NRF_DFU_OBJ_TYPE_COMMAND)
                {
                    cur_obj_type = NRF_DFU_OBJ_TYPE_COMMAND;
                }
                else if ((nrf_dfu_obj_type_t)p_req->select.object_type == NRF_DFU_OBJ_TYPE_DATA)
                {
                    cur_obj_type = NRF_DFU_OBJ_TYPE_DATA;
                }
                else
                {
                    return NRF_DFU_RES_CODE_UNSUPPORTED_TYPE;
                }
                break;
            default:
                // no implementation
                break;
        }
    
        switch (cur_obj_type)
        {
            case NRF_DFU_OBJ_TYPE_COMMAND:
                nrf_dfu_command_req(p_req, p_res);
                break;
    
            case NRF_DFU_OBJ_TYPE_DATA:
                nrf_dfu_data_req(p_req, p_res);
                break;
    
            default:
                NRF_LOG_ERROR("Invalid request type");
                ret_val = NRF_DFU_RES_CODE_INVALID_OBJECT;
                break;
        }
    
        return ret_val;
    }
    
    
    /*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;
        }
    
    #ifdef BLE_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;
    }
    

Children
No Data
Related