diff options
Diffstat (limited to 'thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader')
50 files changed, 10316 insertions, 0 deletions
diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/ble_dfu/nrf_dfu_ble.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/ble_dfu/nrf_dfu_ble.c new file mode 100644 index 0000000..44b0072 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/ble_dfu/nrf_dfu_ble.c @@ -0,0 +1,1238 @@ +/** + * 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 "nrf_dfu_ble.h" + +#include <stddef.h> +#include "sdk_common.h" +#include "nrf_dfu_transport.h" +#include "nrf_dfu_types.h" +#include "nrf_dfu_req_handler.h" +#include "nrf_dfu_handling_error.h" +#include "nrf_sdm.h" +#include "nrf_dfu_mbr.h" +#include "nrf_bootloader_info.h" +#include "ble.h" +#include "ble_srv_common.h" +#include "ble_hci.h" +#include "nrf_sdh.h" +#include "nrf_sdh_ble.h" +#include "nrf_balloc.h" +#include "nrf_delay.h" +#include "nrf_dfu_settings.h" + +#define NRF_LOG_MODULE_NAME nrf_dfu_ble +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + + +#define APP_BLE_CONN_CFG_TAG 1 /**< A tag identifying the SoftDevice BLE configuration. */ + +#define APP_ADV_DATA_HEADER_SIZE 9 /**< Size of encoded advertisement data header (not including device name). */ +#define APP_ADV_DURATION BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED /**< The advertising duration in units of 10 milliseconds. This is set to @ref BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED so that the advertisement is done as long as there there is a call to @ref dfu_transport_close function.*/ +#define APP_ADV_INTERVAL MSEC_TO_UNITS(25, UNIT_0_625_MS) /**< The advertising interval (25 ms.). */ + +#define GATT_HEADER_LEN 3 /**< GATT header length. */ +#define GATT_PAYLOAD(mtu) ((mtu) - GATT_HEADER_LEN) /**< Length of the ATT payload for a given ATT MTU. */ +#define MAX_DFU_PKT_LEN (NRF_SDH_BLE_GATT_MAX_MTU_SIZE - GATT_HEADER_LEN) /**< Maximum length (in bytes) of the DFU Packet characteristic (3 bytes are used for the GATT opcode and handle). */ +#define MAX_RESPONSE_LEN 17 /**< Maximum length (in bytes) of the response to a Control Point command. */ +#define RESPONSE_HEADER_LEN 3 /**< The length of the header of a response. I.E. the index of the opcode-specific payload. */ + +#define DFU_BLE_FLAG_INITIALIZED (1 << 0) /**< Flag to check if the DFU service was initialized by the application.*/ +#define DFU_BLE_FLAG_USE_ADV_NAME (1 << 1) /**< Flag to indicate that advertisement name is to be used. */ +#define DFU_BLE_RESETTING_SOON (1 << 2) /**< Flag to indicate that the device will reset soon. */ + +#define BLE_OBSERVER_PRIO 2 /**< BLE observer priority. Controls the priority for BLE event handler. */ + +#if (NRF_DFU_BLE_BUFFERS_OVERRIDE) +/* If selected, use the override value. */ +#define MAX_DFU_BUFFERS NRF_DFU_BLE_BUFFERS +#else +#define MAX_DFU_BUFFERS ((CODE_PAGE_SIZE / MAX_DFU_PKT_LEN) + 1) +#endif + +#if (NRF_DFU_BLE_REQUIRES_BONDS) && (!NRF_SDH_BLE_SERVICE_CHANGED) +#error NRF_DFU_BLE_REQUIRES_BONDS requires NRF_SDH_BLE_SERVICE_CHANGED. \ + Please update the SoftDevice BLE stack configuration in sdk_config.h +#endif + +#if (MAX_DFU_PKT_LEN % 4) +#error Payload length should be a multiple of four. \ + Payload length is set to NRF_SDH_BLE_GATT_MAX_MTU_SIZE - 3. +#endif + + +static uint32_t ble_dfu_transport_init(nrf_dfu_observer_t observer); +static uint32_t ble_dfu_transport_close(nrf_dfu_transport_t const * p_exception); + +DFU_TRANSPORT_REGISTER(nrf_dfu_transport_t const ble_dfu_transport) = +{ + .init_func = ble_dfu_transport_init, + .close_func = ble_dfu_transport_close, +}; + +#if (NRF_DFU_BLE_REQUIRES_BONDS) +static nrf_dfu_peer_data_t m_peer_data; +#else +static nrf_dfu_adv_name_t m_adv_name; +#endif + +static uint32_t m_flags; +static ble_dfu_t m_dfu; /**< Structure used to identify the Device Firmware Update service. */ +static uint16_t m_pkt_notif_target; /**< Number of packets of firmware data to be received before transmitting the next Packet Receipt Notification to the DFU Controller. */ +static uint16_t m_pkt_notif_target_cnt; /**< Number of packets of firmware data received after sending last Packet Receipt Notification or since the receipt of a @ref BLE_DFU_PKT_RCPT_NOTIF_ENABLED event from the DFU service, which ever occurs later.*/ +static uint16_t m_conn_handle = BLE_CONN_HANDLE_INVALID; /**< Handle of the current connection. */ +static uint8_t m_adv_handle = BLE_GAP_ADV_SET_HANDLE_NOT_SET; /**< Advertising handle used to identify an advertising set. */ +static nrf_dfu_observer_t m_observer; /**< Observer function called on certain events. */ + +static ble_gap_conn_params_t const m_gap_conn_params = +{ + .min_conn_interval = NRF_DFU_BLE_MIN_CONN_INTERVAL, + .max_conn_interval = NRF_DFU_BLE_MAX_CONN_INTERVAL, + /* This value is expressed in units of 10 ms, rather than 1 ms. */ + .conn_sup_timeout = NRF_DFU_BLE_CONN_SUP_TIMEOUT_MS / 10, + .slave_latency = 0, +}; + +NRF_BALLOC_DEF(m_buffer_pool, MAX_DFU_PKT_LEN, MAX_DFU_BUFFERS); + + +/**@brief Function for the Advertising functionality initialization. + * + * @details Encodes the required advertising data and passes it to the stack. + * The advertising data encoded here is specific for DFU. + */ +static uint32_t advertising_init(uint8_t adv_flags, ble_gap_adv_params_t const * const p_adv_params) +{ + uint32_t err_code; + uint16_t actual_device_name_length = BLE_GAP_ADV_SET_DATA_SIZE_MAX - APP_ADV_DATA_HEADER_SIZE; + + /* This needs to be static because of SoftDevice API requirements. */ + static uint8_t m_enc_advdata[BLE_GAP_ADV_SET_DATA_SIZE_MAX]; + + ble_gap_adv_data_t m_adv_data = + { + .adv_data = + { + .p_data = m_enc_advdata, + .len = APP_ADV_DATA_HEADER_SIZE, + } + }; + + /* Encode flags. */ + m_enc_advdata[0] = 0x2; + m_enc_advdata[1] = BLE_GAP_AD_TYPE_FLAGS; + m_enc_advdata[2] = adv_flags; + + /* Encode 'more available' UUID list. */ + m_enc_advdata[3] = 0x3; + m_enc_advdata[4] = BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE; + m_enc_advdata[5] = LSB_16(BLE_DFU_SERVICE_UUID); + m_enc_advdata[6] = MSB_16(BLE_DFU_SERVICE_UUID); + + /* Get GAP device name and length. */ + err_code = sd_ble_gap_device_name_get(&m_enc_advdata[9], &actual_device_name_length); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + // Set GAP device in advertising data. + m_enc_advdata[7] = actual_device_name_length + 1; // (actual_length + ADV_AD_TYPE_FIELD_SIZE(1)) + m_enc_advdata[8] = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME; + + m_adv_data.adv_data.len += actual_device_name_length; + + return sd_ble_gap_adv_set_configure(&m_adv_handle, &m_adv_data, p_adv_params); +} + + +/**@brief Function for starting advertising. + */ +static uint32_t advertising_start(void) +{ + uint32_t err_code; + uint8_t adv_flag = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE; + + ble_gap_adv_params_t adv_params = + { + .properties.type = BLE_GAP_ADV_TYPE_CONNECTABLE_SCANNABLE_UNDIRECTED, + .p_peer_addr = NULL, + .filter_policy = BLE_GAP_ADV_FP_ANY, + .interval = APP_ADV_INTERVAL, + .duration = APP_ADV_DURATION, + .primary_phy = BLE_GAP_PHY_1MBPS, + }; + + NRF_LOG_DEBUG("Advertising..."); + +#if (NRF_DFU_BLE_REQUIRES_BONDS) + ble_gap_irk_t empty_irk = {{0}}; + + if (memcmp(m_peer_data.ble_id.id_info.irk, empty_irk.irk, sizeof(ble_gap_irk_t)) == 0) + { + NRF_LOG_DEBUG("No IRK found, general discovery"); + } + else + { + NRF_LOG_DEBUG("IRK Found, setting up whitelist"); + + adv_flag = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED; + adv_params.filter_policy = BLE_GAP_ADV_FP_FILTER_CONNREQ; + + ble_gap_addr_t const * const p_gap_addr = &m_peer_data.ble_id.id_addr_info; + ble_gap_id_key_t const * const p_gap_id_key = &m_peer_data.ble_id; + + err_code = sd_ble_gap_whitelist_set(&p_gap_addr, 1); + if (err_code != NRF_SUCCESS) + { + NRF_LOG_WARNING("sd_ble_gap_whitelist_set() returned %s", + NRF_LOG_ERROR_STRING_GET(err_code)); + } + + err_code = sd_ble_gap_device_identities_set(&p_gap_id_key, NULL, 1); + if (err_code != NRF_SUCCESS) + { + NRF_LOG_WARNING("sd_ble_gap_device_identities_set() returned %s", + NRF_LOG_ERROR_STRING_GET(err_code)); + } + } +#endif /* NRF_DFU_BLE_REQUIRES_BONDS */ + + err_code = advertising_init(adv_flag, &adv_params); + VERIFY_SUCCESS(err_code); + + err_code = sd_ble_gap_adv_stop(m_adv_handle); + UNUSED_RETURN_VALUE(err_code); + + return sd_ble_gap_adv_start(m_adv_handle, APP_BLE_CONN_CFG_TAG); +} + + +static bool is_cccd_configured(ble_dfu_t * p_dfu) +{ + uint8_t cccd_val_buf[BLE_CCCD_VALUE_LEN]; + + ble_gatts_value_t gatts_value = + { + .len = BLE_CCCD_VALUE_LEN, + .p_value = cccd_val_buf + }; + + /* Check the CCCD Value of DFU Control Point. */ + uint32_t err_code = sd_ble_gatts_value_get(m_conn_handle, + p_dfu->dfu_ctrl_pt_handles.cccd_handle, + &gatts_value); + VERIFY_SUCCESS(err_code); + + return ble_srv_is_notification_enabled(cccd_val_buf); +} + + +static ret_code_t response_send(uint8_t * p_buf, uint16_t len) +{ + ble_gatts_hvx_params_t hvx_params = + { + .handle = m_dfu.dfu_ctrl_pt_handles.value_handle, + .type = BLE_GATT_HVX_NOTIFICATION, + .p_data = (uint8_t *)(p_buf), + .p_len = &len, + }; + + return sd_ble_gatts_hvx(m_conn_handle, &hvx_params); +} + + +#if (NRF_DFU_BLE_REQUIRES_BONDS) +static uint32_t service_changed_send(void) +{ + uint32_t err_code; + + NRF_LOG_DEBUG("Sending Service Changed indication"); + + err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, + m_peer_data.sys_serv_attr, + sizeof(m_peer_data.sys_serv_attr), + BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS); + VERIFY_SUCCESS(err_code); + + err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, + NULL, + 0, + BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS); + VERIFY_SUCCESS(err_code); + + err_code = sd_ble_gatts_service_changed(m_conn_handle, m_dfu.service_handle, 0xFFFF); + + if ( (err_code == BLE_ERROR_INVALID_CONN_HANDLE) + || (err_code == NRF_ERROR_INVALID_STATE) + || (err_code == NRF_ERROR_BUSY)) + { + /* These errors can be expected when trying to send a Service Changed indication */ + /* if the CCCD is not set to indicate. Thus, set the returning error code to success. */ + NRF_LOG_WARNING("Client did not have the Service Changed indication set to enabled." + "Error: 0x%08x", err_code); + err_code = NRF_SUCCESS; + } + + return err_code; +} +#endif + + +/**@brief Function for encoding the beginning of a response. + * + * @param[inout] p_buffer The buffer to encode into. + * @param[in] op_code The opcode of the response. + * @param[in] result The result of the operation. + * + * @return The length added to the buffer. + */ +static uint32_t response_prepare(uint8_t * p_buffer, uint8_t op_code, uint8_t result) +{ + ASSERT(p_buffer); + p_buffer[0] = NRF_DFU_OP_RESPONSE; + p_buffer[1] = op_code; + p_buffer[2] = result; + return RESPONSE_HEADER_LEN; +} + + +/**@brief Function for encoding a select object response into a buffer. + * + * The select object response consists of a maximum object size, a firmware offset, and a CRC value. + * + * @param[inout] p_buffer The buffer to encode the response into. + * @param[in] max_size The maximum object size value to encode. + * @param[in] fw_offset The firmware offset value to encode. + * @param[in] crc The CRC value to encode. + * + * @return The length added to the buffer. + */ +static uint32_t response_select_obj_add(uint8_t * p_buffer, + uint32_t max_size, + uint32_t fw_offset, + uint32_t crc) +{ + uint16_t offset = uint32_encode(max_size, &p_buffer[RESPONSE_HEADER_LEN]); + offset += uint32_encode(fw_offset, &p_buffer[RESPONSE_HEADER_LEN + offset]); + offset += uint32_encode(crc, &p_buffer[RESPONSE_HEADER_LEN + offset]); + return offset; +} + + +/**@brief Function for encoding a CRC response into a buffer. + * + * The CRC response consists of a firmware offset and a CRC value. + * + * @param[inout] p_buffer The buffer to encode the response into. + * @param[in] fw_offset The firmware offset value to encode. + * @param[in] crc The CRC value to encode. + * + * @return The length added to the buffer. + */ +static uint32_t response_crc_add(uint8_t * p_buffer, uint32_t fw_offset, uint32_t crc) +{ + uint16_t offset = uint32_encode(fw_offset, &p_buffer[RESPONSE_HEADER_LEN]); + offset += uint32_encode(crc, &p_buffer[RESPONSE_HEADER_LEN + offset]); + return offset; +} + + +/**@brief Function for appending an extended error code to the response buffer. + * + * @param[inout] p_buffer The buffer to append the extended error code to. + * @param[in] result The error code to append. + * @param[in] buf_offset The current length of the buffer. + * + * @return The length added to the buffer. + */ +static uint32_t response_ext_err_payload_add(uint8_t * p_buffer, uint8_t result, uint32_t buf_offset) +{ + p_buffer[buf_offset] = ext_error_get(); + (void) ext_error_set(NRF_DFU_EXT_ERROR_NO_ERROR); + return 1; +} + + +static void ble_dfu_req_handler_callback(nrf_dfu_response_t * p_res, void * p_context) +{ + ASSERT(p_res); + ASSERT(p_context); + + uint8_t len = 0; + uint8_t buffer[MAX_RESPONSE_LEN] = {0}; + + if (p_res->request == NRF_DFU_OP_OBJECT_WRITE) + { + --m_pkt_notif_target_cnt; + if ((m_pkt_notif_target == 0) || (m_pkt_notif_target_cnt && m_pkt_notif_target > 0)) + { + return; + } + + /* Reply with a CRC message and reset the packet counter. */ + m_pkt_notif_target_cnt = m_pkt_notif_target; + + p_res->request = NRF_DFU_OP_CRC_GET; + } + + len += response_prepare(buffer, p_res->request, p_res->result); + + if (p_res->result != NRF_DFU_RES_CODE_SUCCESS) + { + NRF_LOG_WARNING("DFU request %d failed with error: 0x%x", p_res->request, p_res->result); + + if (p_res->result == NRF_DFU_RES_CODE_EXT_ERROR) + { + len += response_ext_err_payload_add(buffer, p_res->result, len); + } + + (void) response_send(buffer, len); + return; + } + + switch (p_res->request) + { + case NRF_DFU_OP_OBJECT_CREATE: + case NRF_DFU_OP_OBJECT_EXECUTE: + break; + + case NRF_DFU_OP_OBJECT_SELECT: + { + len += response_select_obj_add(buffer, + p_res->select.max_size, + p_res->select.offset, + p_res->select.crc); + } break; + + case NRF_DFU_OP_OBJECT_WRITE: + { + len += response_crc_add(buffer, p_res->write.offset, p_res->write.crc); + } break; + + case NRF_DFU_OP_CRC_GET: + { + len += response_crc_add(buffer, p_res->crc.offset, p_res->crc.crc); + } break; + + default: + { + // No action. + } break; + } + + (void) response_send(buffer, len); +} + + +/**@brief Function for handling a Write event on the Control Point characteristic. + * + * @param[in] p_dfu DFU Service Structure. + * @param[in] p_ble_write_evt Pointer to the write event received from BLE stack. + * + * @return NRF_SUCCESS on successful processing of control point write. Otherwise an error code. + */ +static uint32_t on_ctrl_pt_write(ble_dfu_t * p_dfu, ble_gatts_evt_write_t const * p_ble_write_evt) +{ + //lint -save -e415 -e416 : Out-of-bounds access on p_ble_write_evt->data + nrf_dfu_request_t request = + { + .request = (nrf_dfu_op_t)(p_ble_write_evt->data[0]), + .p_context = p_dfu, + .callback.response = ble_dfu_req_handler_callback, + }; + + switch (request.request) + { + case NRF_DFU_OP_OBJECT_SELECT: + { + /* Set object type to read info about */ + request.select.object_type = p_ble_write_evt->data[1]; + } break; + + case NRF_DFU_OP_OBJECT_CREATE: + { + /* Activity on the current transport. Close all except the current one. */ + (void) nrf_dfu_transports_close(&ble_dfu_transport); + + /* Reset the packet receipt notification on create object */ + m_pkt_notif_target_cnt = m_pkt_notif_target; + + request.create.object_type = p_ble_write_evt->data[1]; + request.create.object_size = uint32_decode(&(p_ble_write_evt->data[2])); + } break; + + case NRF_DFU_OP_RECEIPT_NOTIF_SET: + { + NRF_LOG_DEBUG("Set receipt notif"); + + m_pkt_notif_target = uint16_decode(&(p_ble_write_evt->data[1])); + m_pkt_notif_target_cnt = m_pkt_notif_target; + } break; + + default: + break; + } + //lint -restore : Out-of-bounds access + + return nrf_dfu_req_handler_on_req(&request); +} + + +/**@brief Function for handling the @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event from the + * SoftDevice. + * + * @param[in] p_dfu DFU Service Structure. + * @param[in] p_ble_evt Pointer to the event received from BLE stack. + */ +static bool on_rw_authorize_req(ble_dfu_t * p_dfu, ble_evt_t const * p_ble_evt) +{ + uint32_t err_code; + + ble_gatts_evt_rw_authorize_request_t const * p_authorize_request; + ble_gatts_evt_write_t const * p_ble_write_evt; + + p_authorize_request = &(p_ble_evt->evt.gatts_evt.params.authorize_request); + p_ble_write_evt = &(p_ble_evt->evt.gatts_evt.params.authorize_request.request.write); + + if ( (p_authorize_request->type != BLE_GATTS_AUTHORIZE_TYPE_WRITE) + || (p_authorize_request->request.write.handle != p_dfu->dfu_ctrl_pt_handles.value_handle) + || (p_authorize_request->request.write.op != BLE_GATTS_OP_WRITE_REQ)) + { + return false; + } + + ble_gatts_rw_authorize_reply_params_t auth_reply = + { + .type = BLE_GATTS_AUTHORIZE_TYPE_WRITE, + .params.write.update = 1, + .params.write.offset = p_ble_write_evt->offset, + .params.write.len = p_ble_write_evt->len, + .params.write.p_data = p_ble_write_evt->data, + }; + + if (!is_cccd_configured(p_dfu)) + { + /* Send an error response to the peer indicating that the CCCD is improperly configured. */ + auth_reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR; + + /* Ignore response of auth reply */ + (void) sd_ble_gatts_rw_authorize_reply(m_conn_handle, &auth_reply); + return false; + } + else + { + auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS; + + err_code = sd_ble_gatts_rw_authorize_reply(m_conn_handle, &auth_reply); + return err_code == NRF_SUCCESS ? true : false; + } +} + + +static void on_flash_write(void * p_buf) +{ + NRF_LOG_DEBUG("Freeing buffer %p", p_buf); + nrf_balloc_free(&m_buffer_pool, p_buf); +} + + +/**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the SoftDevice. + * + * @param[in] p_dfu DFU Service Structure. + * @param[in] p_ble_evt Pointer to the event received from BLE stack. + */ +static void on_write(ble_dfu_t * p_dfu, ble_evt_t const * p_ble_evt) +{ + ble_gatts_evt_write_t const * const p_write_evt = &p_ble_evt->evt.gatts_evt.params.write; + + if (p_write_evt->handle != p_dfu->dfu_pkt_handles.value_handle) + { + return; + } + + /* Allocate a buffer to receive data. */ + uint8_t * p_balloc_buf = nrf_balloc_alloc(&m_buffer_pool); + if (p_balloc_buf == NULL) + { + /* Operations are retried by the host; do not give up here. */ + NRF_LOG_WARNING("cannot allocate memory buffer!"); + return; + } + + NRF_LOG_DEBUG("Buffer %p acquired, len %d (%d)", + p_balloc_buf, p_write_evt->len, MAX_DFU_PKT_LEN); + + /* Copy payload into buffer. */ + memcpy(p_balloc_buf, p_write_evt->data, p_write_evt->len); + + /* Set up the request. */ + nrf_dfu_request_t request = + { + .request = NRF_DFU_OP_OBJECT_WRITE, + .p_context = p_dfu, + .callback = + { + .response = ble_dfu_req_handler_callback, + .write = on_flash_write, + } + }; + + /* Set up the request buffer. */ + request.write.p_data = p_balloc_buf; + request.write.len = p_write_evt->len; + + /* Schedule handling of the request. */ + ret_code_t rc = nrf_dfu_req_handler_on_req(&request); + if (rc != NRF_SUCCESS) + { + /* The error is logged in nrf_dfu_req_handler_on_req(). + * Free the buffer. + */ + (void) nrf_balloc_free(&m_buffer_pool, p_balloc_buf); + } +} + + +/**@brief Function for the Application's SoftDevice event handler. + * + * @param[in] p_ble_evt SoftDevice event. + */ +static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) +{ + uint32_t err_code; + ble_gap_evt_t const * const p_gap = &p_ble_evt->evt.gap_evt; + + switch (p_ble_evt->header.evt_id) + { + case BLE_GAP_EVT_CONNECTED: + { + NRF_LOG_DEBUG("Connected"); + + m_conn_handle = p_gap->conn_handle; + + if (m_observer) + { + m_observer(NRF_DFU_EVT_TRANSPORT_ACTIVATED); + } + + err_code = sd_ble_gap_conn_param_update(m_conn_handle, &m_gap_conn_params); + if (err_code != NRF_SUCCESS) + { + NRF_LOG_ERROR("Failure to update connection parameters: 0x%x", err_code); + } + } break; + + case BLE_GAP_EVT_DISCONNECTED: + { + m_conn_handle = BLE_CONN_HANDLE_INVALID; + + /* Restart advertising so that the DFU Controller can reconnect if possible. */ + if (!(m_flags & DFU_BLE_RESETTING_SOON)) + { + err_code = advertising_start(); + APP_ERROR_CHECK(err_code); + } + + if (m_observer) + { + m_observer(NRF_DFU_EVT_TRANSPORT_DEACTIVATED); + } + } break; + + case BLE_GATTS_EVT_WRITE: + { + on_write(&m_dfu, p_ble_evt); + } break; + + case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST: + { + uint16_t const mtu_requested = + p_ble_evt->evt.gatts_evt.params.exchange_mtu_request.client_rx_mtu; + + /* If the requested MTU is smaller than the maximum, we can accept with the given + * stack configuration, and the payload is not word-aligned, reply with a smaller MTU + * that has a word-aligned payload. This ensures that the length of data we write to + * flash is a multiple of the word size. + */ + uint16_t mtu_reply; + + if (mtu_requested < NRF_SDH_BLE_GATT_MAX_MTU_SIZE) + { + /* Round the payload size down to a multiple of 4 so it is word-aligned. */ + if (GATT_PAYLOAD(mtu_requested) % 4) + { + mtu_reply = GATT_PAYLOAD(mtu_requested) - 4; + mtu_reply = ALIGN_NUM(4, mtu_reply); + /* Add the header len to the MTU. */ + mtu_reply += GATT_HEADER_LEN; + } + else + { + mtu_reply = mtu_requested; + } + } + else + { + mtu_reply = NRF_SDH_BLE_GATT_MAX_MTU_SIZE; + } + + NRF_LOG_DEBUG("Received BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST (request: %d, reply: %d).", + mtu_requested, mtu_reply); + + err_code = sd_ble_gatts_exchange_mtu_reply(m_conn_handle, mtu_reply); + APP_ERROR_CHECK(err_code); + } break; + + case BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST: + { + NRF_LOG_DEBUG("Received BLE_GAP_EVT_DATA_LENGTH_UPDATE_REQUEST."); + + ble_gap_data_length_params_t const dlp = + { + .max_rx_octets = BLE_GAP_DATA_LENGTH_AUTO, + .max_tx_octets = BLE_GAP_DATA_LENGTH_AUTO, + }; + + err_code = sd_ble_gap_data_length_update(p_ble_evt->evt.gatts_evt.conn_handle, + &dlp, NULL); + APP_ERROR_CHECK(err_code); + } break; + + + case BLE_GAP_EVT_DATA_LENGTH_UPDATE: + { + NRF_LOG_DEBUG("Received BLE_GAP_EVT_DATA_LENGTH_UPDATE (%u, max_rx_time %u).", + p_gap->params.data_length_update.effective_params.max_rx_octets, + p_gap->params.data_length_update.effective_params.max_rx_time_us); + } break; + + case BLE_GAP_EVT_SEC_PARAMS_REQUEST: + { + NRF_LOG_DEBUG("Received BLE_GAP_EVT_SEC_PARAMS_REQUEST"); + + uint16_t cccd; + ble_gatts_value_t gatts_value = + { + .len = BLE_CCCD_VALUE_LEN, + .p_value = (uint8_t*)&cccd + }; + + err_code = sd_ble_gatts_value_get(m_conn_handle, + BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED, + &gatts_value); + APP_ERROR_CHECK(err_code); + + NRF_LOG_DEBUG("CCCD for service changed is 0x%04x", cccd); + + err_code = sd_ble_gap_sec_params_reply(m_conn_handle, + BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, + NULL, + NULL); + APP_ERROR_CHECK(err_code); + } break; + + case BLE_GAP_EVT_CONN_PARAM_UPDATE: + { + NRF_LOG_DEBUG("Received BLE_GAP_EVT_CONN_PARAM_UPDATE"); + + ble_gap_conn_params_t const * p_conn = + &p_gap->params.conn_param_update.conn_params; + + NRF_LOG_DEBUG("max_conn_interval: %d", p_conn->max_conn_interval); + NRF_LOG_DEBUG("min_conn_interval: %d", p_conn->min_conn_interval); + NRF_LOG_DEBUG("slave_latency: %d", p_conn->slave_latency); + NRF_LOG_DEBUG("conn_sup_timeout: %d", p_conn->conn_sup_timeout); + } break; + + case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST: + { + NRF_LOG_DEBUG("Received BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST"); + + err_code = sd_ble_gap_conn_param_update(m_conn_handle, + &p_gap->params.conn_param_update_request.conn_params); + + if (err_code != NRF_SUCCESS) + { + NRF_LOG_ERROR("Failure to update connection parameter request: 0x%x", err_code); + } + + APP_ERROR_CHECK(err_code); + } break; + + case BLE_GAP_EVT_PHY_UPDATE: + { + NRF_LOG_DEBUG("Received BLE_GAP_EVT_PHY_UPDATE (RX:%d, TX:%d, status:%d)", + p_gap->params.phy_update.rx_phy, + p_gap->params.phy_update.tx_phy, + p_gap->params.phy_update.status); + break; + } + + case BLE_GAP_EVT_PHY_UPDATE_REQUEST: + { + NRF_LOG_DEBUG("Received BLE_GAP_EVT_PHY_UPDATE_REQUEST."); + + ble_gap_phys_t const phys = + { + .rx_phys = BLE_GAP_PHY_AUTO, + .tx_phys = BLE_GAP_PHY_AUTO, + }; + + err_code = sd_ble_gap_phy_update(p_gap->conn_handle, &phys); + APP_ERROR_CHECK(err_code); + } break; + + case BLE_GATTS_EVT_TIMEOUT: + { + if (p_ble_evt->evt.gatts_evt.params.timeout.src == BLE_GATT_TIMEOUT_SRC_PROTOCOL) + { + err_code = sd_ble_gap_disconnect(m_conn_handle, + BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); + APP_ERROR_CHECK(err_code); + } + } break; + + case BLE_EVT_USER_MEM_REQUEST: + { + err_code = sd_ble_user_mem_reply(m_conn_handle, NULL); + APP_ERROR_CHECK(err_code); + } break; + + case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST: + { + if (p_ble_evt->evt.gatts_evt.params.authorize_request.type + != BLE_GATTS_AUTHORIZE_TYPE_INVALID) + { + if (on_rw_authorize_req(&m_dfu, p_ble_evt)) + { + err_code = on_ctrl_pt_write(&m_dfu, + &(p_ble_evt->evt.gatts_evt.params.authorize_request.request.write)); + + if (err_code != NRF_SUCCESS) + { + NRF_LOG_ERROR("Could not handle on_ctrl_pt_write. err_code: 0x%04x", err_code); + } + } + } + } break; + + case BLE_GAP_EVT_SEC_INFO_REQUEST: + { + NRF_LOG_DEBUG("Received BLE_GAP_EVT_SEC_INFO_REQUEST"); + + ble_gap_enc_info_t * p_enc_info = NULL; + ble_gap_irk_t * p_id_info = NULL; + + #if (NRF_DFU_BLE_REQUIRES_BONDS) + /* If there is a match in diversifier, then set the correct keys. */ + if (p_gap->params.sec_info_request.master_id.ediv == + m_peer_data.enc_key.master_id.ediv) + { + p_enc_info = &m_peer_data.enc_key.enc_info; + } + p_id_info = &m_peer_data.ble_id.id_info; + #endif + + err_code = sd_ble_gap_sec_info_reply(p_gap->conn_handle, p_enc_info, p_id_info, NULL); + APP_ERROR_CHECK(err_code); + } break; + + case BLE_GAP_EVT_CONN_SEC_UPDATE: + case BLE_GATTS_EVT_SYS_ATTR_MISSING: + { + #if (NRF_DFU_BLE_REQUIRES_BONDS) + err_code = service_changed_send(); + #else + err_code = sd_ble_gatts_sys_attr_set(p_gap->conn_handle, NULL, 0, 0); + #endif + APP_ERROR_CHECK(err_code); + NRF_LOG_DEBUG("Finished handling conn sec update"); + } break; + + default: + /* No implementation needed. */ + break; + } +} + + +#if (!NRF_DFU_BLE_REQUIRES_BONDS) +static uint32_t gap_address_change(void) +{ + uint32_t err_code; + ble_gap_addr_t addr; + + err_code = sd_ble_gap_addr_get(&addr); + VERIFY_SUCCESS(err_code); + + /* Increase the BLE address by one when advertising openly. */ + addr.addr[0] += 1; + + err_code = sd_ble_gap_addr_set(&addr); + VERIFY_SUCCESS(err_code); + + return NRF_SUCCESS; +} +#endif + + +/**@brief Function for initializing GAP. + * + * @details This function sets up all necessary GAP (Generic Access Profile) parameters of + * the device. It also sets the permissions and appearance. + */ +static uint32_t gap_params_init(void) +{ + uint32_t err_code; + ble_gap_conn_sec_mode_t sec_mode; + uint8_t const * device_name; + uint32_t name_len; + + BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); + +#if (!NRF_DFU_BLE_REQUIRES_BONDS) + + err_code = gap_address_change(); + VERIFY_SUCCESS(err_code); + + if ((m_flags & DFU_BLE_FLAG_USE_ADV_NAME) != 0) + { + NRF_LOG_DEBUG("Setting adv name: %s, length: %d", m_adv_name.name, m_adv_name.len); + device_name = m_adv_name.name; + name_len = m_adv_name.len; + } + else +#endif + { + NRF_LOG_DEBUG("Using default advertising name"); + device_name = (uint8_t const *)(NRF_DFU_BLE_ADV_NAME); + name_len = strlen(NRF_DFU_BLE_ADV_NAME); + } + + err_code = sd_ble_gap_device_name_set(&sec_mode, device_name, name_len); + VERIFY_SUCCESS(err_code); + + err_code = sd_ble_gap_ppcp_set(&m_gap_conn_params); + return err_code; +} + + +static uint32_t ble_stack_init() +{ + ret_code_t err_code; + uint32_t ram_start = 0; + + /* Register as a BLE event observer to receive BLE events. */ + NRF_SDH_BLE_OBSERVER(m_ble_evt_observer, BLE_OBSERVER_PRIO, ble_evt_handler, NULL); + + err_code = nrf_dfu_mbr_init_sd(); + VERIFY_SUCCESS(err_code); + + NRF_LOG_DEBUG("Setting up vector table: 0x%08x", BOOTLOADER_START_ADDR); + err_code = sd_softdevice_vector_table_base_set(BOOTLOADER_START_ADDR); + VERIFY_SUCCESS(err_code); + + NRF_LOG_DEBUG("Enabling SoftDevice."); + err_code = nrf_sdh_enable_request(); + VERIFY_SUCCESS(err_code); + + /* Fetch the start address of the application RAM. */ + err_code = nrf_sdh_ble_app_ram_start_get(&ram_start); + VERIFY_SUCCESS(err_code); + + NRF_LOG_DEBUG("Configuring BLE stack."); + err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start); + VERIFY_SUCCESS(err_code); + + /* Enable the BLE stack. */ + NRF_LOG_DEBUG("Enabling the BLE stack."); + return nrf_sdh_ble_enable(&ram_start); +} + + +/**@brief Function for adding DFU Packet characteristic to the BLE Stack. + * + * @param[in] p_dfu DFU Service structure. + * + * @return NRF_SUCCESS on success. Otherwise an error code. + */ +static uint32_t dfu_pkt_char_add(ble_dfu_t * const p_dfu) +{ + ble_gatts_char_md_t char_md = + { + .char_props.write_wo_resp = 1, + }; + + ble_uuid_t char_uuid = + { + .type = p_dfu->uuid_type, + .uuid = BLE_DFU_PKT_CHAR_UUID, + }; + + ble_gatts_attr_md_t attr_md = + { + .vloc = BLE_GATTS_VLOC_STACK, + .vlen = 1, + .write_perm = + { + .sm = 1, + #if NRF_DFU_BLE_REQUIRES_BONDS + .lv = 2, + #else + .lv = 1, + #endif + } + }; + + ble_gatts_attr_t attr_char_value = + { + .p_uuid = &char_uuid, + .p_attr_md = &attr_md, + .max_len = MAX_DFU_PKT_LEN, + }; + + return sd_ble_gatts_characteristic_add(p_dfu->service_handle, + &char_md, + &attr_char_value, + &p_dfu->dfu_pkt_handles); +} + + +/**@brief Function for adding DFU Control Point characteristic to the BLE Stack. + * + * @param[in] p_dfu DFU Service structure. + * + * @return NRF_SUCCESS on success. Otherwise an error code. + */ +static uint32_t dfu_ctrl_pt_add(ble_dfu_t * const p_dfu) +{ + ble_gatts_char_md_t char_md = + { + .char_props.write = 1, + .char_props.notify = 1, + }; + + ble_uuid_t char_uuid = + { + .type = p_dfu->uuid_type, + .uuid = BLE_DFU_CTRL_PT_UUID, + }; + + ble_gatts_attr_md_t attr_md = + { + .vloc = BLE_GATTS_VLOC_STACK, + .wr_auth = 1, + .vlen = 1, + .write_perm = + { + .sm = 1, + #if NRF_DFU_BLE_REQUIRES_BONDS + .lv = 2, + #else + .lv = 1, + #endif + }, + }; + + ble_gatts_attr_t attr_char_value = + { + .p_uuid = &char_uuid, + .p_attr_md = &attr_md, + .max_len = BLE_GATT_ATT_MTU_DEFAULT, + }; + + return sd_ble_gatts_characteristic_add(p_dfu->service_handle, + &char_md, + &attr_char_value, + &p_dfu->dfu_ctrl_pt_handles); +} + + +/**@brief Function for checking if the CCCD of DFU Control point is configured for Notification. + * + * @details This function checks if the CCCD of DFU Control Point characteristic is configured + * for Notification by the DFU Controller. + * + * @param[in] p_dfu DFU Service structure. + * + * @return True if the CCCD of DFU Control Point characteristic is configured for Notification. + * False otherwise. + */ +uint32_t ble_dfu_init(ble_dfu_t * p_dfu) +{ + ASSERT(p_dfu != NULL); + + ble_uuid_t service_uuid; + uint32_t err_code; + + m_conn_handle = BLE_CONN_HANDLE_INVALID; + + BLE_UUID_BLE_ASSIGN(service_uuid, BLE_DFU_SERVICE_UUID); + + err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, + &service_uuid, + &(p_dfu->service_handle)); + VERIFY_SUCCESS(err_code); + + ble_uuid128_t const base_uuid128 = + { + { + 0x50, 0xEA, 0xDA, 0x30, 0x88, 0x83, 0xB8, 0x9F, + 0x60, 0x4F, 0x15, 0xF3, 0x00, 0x00, 0xC9, 0x8E + } + }; + + err_code = sd_ble_uuid_vs_add(&base_uuid128, &p_dfu->uuid_type); + VERIFY_SUCCESS(err_code); + + err_code = dfu_pkt_char_add(p_dfu); + VERIFY_SUCCESS(err_code); + + err_code = dfu_ctrl_pt_add(p_dfu); + VERIFY_SUCCESS(err_code); + + return NRF_SUCCESS; +} + + +static uint32_t ble_dfu_transport_init(nrf_dfu_observer_t observer) +{ + uint32_t err_code = NRF_SUCCESS; + + if (m_flags & DFU_BLE_FLAG_INITIALIZED) + { + return err_code; + } + + NRF_LOG_DEBUG("Initializing BLE DFU transport"); + + m_observer = observer; + + err_code = nrf_balloc_init(&m_buffer_pool); + UNUSED_RETURN_VALUE(err_code); + + err_code = ble_stack_init(); + VERIFY_SUCCESS(err_code); + +#if (NRF_DFU_BLE_REQUIRES_BONDS) + /* Copy out the peer data if bonds are required */ + if (nrf_dfu_settings_peer_data_is_valid()) + { + NRF_LOG_DEBUG("Copying peer data"); + + err_code = nrf_dfu_settings_peer_data_copy(&m_peer_data); + UNUSED_RETURN_VALUE(err_code); + } + else + { + APP_ERROR_HANDLER(NRF_ERROR_INTERNAL); + } +#else + /* Copy out the new advertisement name when bonds are not required and the name is set. */ + if (nrf_dfu_settings_adv_name_is_valid()) + { + err_code = nrf_dfu_settings_adv_name_copy(&m_adv_name); + UNUSED_RETURN_VALUE(err_code); + + /* Set flags for advertisement name that is to be used */ + m_flags |= DFU_BLE_FLAG_USE_ADV_NAME; + } + else + { + NRF_LOG_DEBUG("No advertising name found"); + } +#endif + + err_code = gap_params_init(); + VERIFY_SUCCESS(err_code); + + /* Initialize the Device Firmware Update Service. */ + err_code = ble_dfu_init(&m_dfu); + VERIFY_SUCCESS(err_code); + + err_code = advertising_start(); + VERIFY_SUCCESS(err_code); + + m_flags |= DFU_BLE_FLAG_INITIALIZED; + + NRF_LOG_DEBUG("BLE DFU transport initialized."); + + return NRF_SUCCESS; +} + + +static uint32_t ble_dfu_transport_close(nrf_dfu_transport_t const * p_exception) +{ + uint32_t err_code = NRF_SUCCESS; + + if ((m_flags & DFU_BLE_FLAG_INITIALIZED) && (p_exception != &ble_dfu_transport)) + { + NRF_LOG_DEBUG("Shutting down BLE transport."); + + if (m_conn_handle != BLE_CONN_HANDLE_INVALID) + { + NRF_LOG_DEBUG("Disconnecting."); + + /* Set flag to prevent advertisement from starting */ + m_flags |= DFU_BLE_RESETTING_SOON; + + /* Disconnect from the peer. */ + err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION); + VERIFY_SUCCESS(err_code); + + /* Wait a bit for the disconnect event to be sent on air. */ + nrf_delay_ms(200); + } + else + { + err_code = sd_ble_gap_adv_stop(m_adv_handle); + UNUSED_RETURN_VALUE(err_code); + } + + err_code = nrf_sdh_disable_request(); + if (err_code == NRF_SUCCESS) + { + NRF_LOG_DEBUG("BLE transport shut down."); + } + } + + return err_code; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/ble_dfu/nrf_dfu_ble.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/ble_dfu/nrf_dfu_ble.h new file mode 100644 index 0000000..04d2d55 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/ble_dfu/nrf_dfu_ble.h @@ -0,0 +1,93 @@ +/** + * 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. + * + */ +/**@file + * + * @defgroup nrf_dfu_ble DFU BLE Service + * @{ + * @ingroup nrf_dfu + * @brief Device Firmware Update (DFU) transport layer for <em>Bluetooth</em> low energy. + * + * @details The Device Firmware Update (DFU) Service is a GATT-based service that can be used for + * performing firmware updates over BLE. Note that this implementation uses + * vendor-specific UUIDs for the service and characteristics, and is intended to demonstrate + * firmware updates over BLE. See @ref lib_dfu_transport_ble "DFU Transport: BLE" for more information on the service and the profile. + */ + +#ifndef NRF_DFU_BLE_H__ +#define NRF_DFU_BLE_H__ + +#include <stdint.h> +#include "ble_gatts.h" +#include "ble.h" +#include "nrf_dfu_transport.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +// This is a 16-bit UUID. +#define BLE_DFU_SERVICE_UUID 0xFE59 //!< UUID of the DFU Service. + +// These UUIDs are used with the Nordic base address to create a 128-bit UUID (0x8EC9XXXXF3154F609FB8838830DAEA50). +#define BLE_DFU_CTRL_PT_UUID 0x0001 //!< UUID of the DFU Control Point. +#define BLE_DFU_PKT_CHAR_UUID 0x0002 //!< UUID of the DFU Packet Characteristic. + + +/**@brief DFU Service. + * + * @details This structure contains status information related to the service. + */ +typedef struct +{ + uint16_t service_handle; /**< Handle of the DFU Service (as provided by the SoftDevice). */ + uint8_t uuid_type; /**< UUID type assigned to the DFU Service by the SoftDevice. */ + ble_gatts_char_handles_t dfu_pkt_handles; /**< Handles related to the DFU Packet Characteristic. */ + ble_gatts_char_handles_t dfu_ctrl_pt_handles; /**< Handles related to the DFU Control Point Characteristic. */ +} ble_dfu_t; + + +#ifdef __cplusplus +} +#endif + +#endif // NRF_DFU_BLE_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/ble_dfu/nrf_dfu_ble_svci_bond_sharing.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/ble_dfu/nrf_dfu_ble_svci_bond_sharing.h new file mode 100644 index 0000000..0377a4c --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/ble_dfu/nrf_dfu_ble_svci_bond_sharing.h @@ -0,0 +1,95 @@ +/** + * 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. + * + */ +/**@file + * + * @defgroup nrf_dfu_svci_bond_sharing Supervisor call interface for bond sharing + * @{ + * @ingroup nrf_dfu + * @brief The Supervisor call interface is a thread-safe method to call into the current application or into an external application using a Supervisor instruction. + * + */ + + +#ifndef NRF_DFU_BLE_SVCI_BOND_SHARING_H__ +#define NRF_DFU_BLE_SVCI_BOND_SHARING_H__ + +#include <stdbool.h> +#include "nrf_svci.h" +#include "nrf_svci_async_function.h" +#include "sdk_config.h" +#include "nrf_dfu_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define NRF_DFU_SVCI_SET_PEER_DATA 2 +#define NRF_DFU_SVCI_SET_ADV_NAME 3 + +#if defined(NRF_DFU_TRANSPORT_BLE) && NRF_DFU_TRANSPORT_BLE + +/**@brief Sets up the async SVCI interface for exchanging peer data like bonding and the system attribute table. + * + * @details The peer data will be stored in flash by the bootloader. This requires memory management and + * handling forwarding of system events and state from the main application to the bootloader. + * + * @note This is only available in the buttonless DFU that supports bond sharing. + */ +NRF_SVCI_ASYNC_FUNC_DECLARE(NRF_DFU_SVCI_SET_PEER_DATA, nrf_dfu_set_peer_data, nrf_dfu_peer_data_t, nrf_dfu_peer_data_state_t); + +/**@brief Sets up the async SVCI interface for exchanging advertisement name to use when entering DFU mode. + * + * @details The advertisement name will be stored in flash by the bootloader. This requires memory management + * and handling forwarding of system events and state from the main application to the bootloader. + * + * @note This is only available in the buttonless DFU that does not support bond sharing. + */ +NRF_SVCI_ASYNC_FUNC_DECLARE(NRF_DFU_SVCI_SET_ADV_NAME, nrf_dfu_set_adv_name, nrf_dfu_adv_name_t, nrf_dfu_set_adv_name_state_t); + +#endif // NRF_DFU_TRANSPORT_BLE + +#ifdef __cplusplus +} +#endif + +#endif // NRF_DFU_BLE_SVCI_BOND_SHARING_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/dfu-cc.options b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/dfu-cc.options new file mode 100644 index 0000000..a9ed61e --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/dfu-cc.options @@ -0,0 +1,3 @@ +dfu.Hash.hash max_size:32 +dfu.SignedCommand.signature max_size:64 +dfu.InitCommand.sd_req max_count:16
\ No newline at end of file diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/dfu-cc.pb.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/dfu-cc.pb.c new file mode 100644 index 0000000..2396dc6 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/dfu-cc.pb.c @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.6-dev at Wed Dec 13 13:37:53 2017. */ + +#include "dfu-cc.pb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + +const bool dfu_init_command_is_debug_default = false; + + +const pb_field_t dfu_hash_fields[3] = { + PB_FIELD( 1, UENUM , REQUIRED, STATIC , FIRST, dfu_hash_t, hash_type, hash_type, 0), + PB_FIELD( 2, BYTES , REQUIRED, STATIC , OTHER, dfu_hash_t, hash, hash_type, 0), + PB_LAST_FIELD +}; + +const pb_field_t dfu_init_command_fields[10] = { + PB_FIELD( 1, UINT32 , OPTIONAL, STATIC , FIRST, dfu_init_command_t, fw_version, fw_version, 0), + PB_FIELD( 2, UINT32 , OPTIONAL, STATIC , OTHER, dfu_init_command_t, hw_version, fw_version, 0), + PB_FIELD( 3, UINT32 , REPEATED, STATIC , OTHER, dfu_init_command_t, sd_req, hw_version, 0), + PB_FIELD( 4, UENUM , OPTIONAL, STATIC , OTHER, dfu_init_command_t, type, sd_req, 0), + PB_FIELD( 5, UINT32 , OPTIONAL, STATIC , OTHER, dfu_init_command_t, sd_size, type, 0), + PB_FIELD( 6, UINT32 , OPTIONAL, STATIC , OTHER, dfu_init_command_t, bl_size, sd_size, 0), + PB_FIELD( 7, UINT32 , OPTIONAL, STATIC , OTHER, dfu_init_command_t, app_size, bl_size, 0), + PB_FIELD( 8, MESSAGE , OPTIONAL, STATIC , OTHER, dfu_init_command_t, hash, app_size, &dfu_hash_fields), + PB_FIELD( 9, BOOL , OPTIONAL, STATIC , OTHER, dfu_init_command_t, is_debug, hash, &dfu_init_command_is_debug_default), + PB_LAST_FIELD +}; + +const pb_field_t dfu_command_fields[3] = { + PB_FIELD( 1, UENUM , OPTIONAL, STATIC , FIRST, dfu_command_t, op_code, op_code, 0), + PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, dfu_command_t, init, op_code, &dfu_init_command_fields), + PB_LAST_FIELD +}; + +const pb_field_t dfu_signed_command_fields[4] = { + PB_FIELD( 1, MESSAGE , REQUIRED, STATIC , FIRST, dfu_signed_command_t, command, command, &dfu_command_fields), + PB_FIELD( 2, UENUM , REQUIRED, STATIC , OTHER, dfu_signed_command_t, signature_type, command, 0), + PB_FIELD( 3, BYTES , REQUIRED, STATIC , OTHER, dfu_signed_command_t, signature, signature_type, 0), + PB_LAST_FIELD +}; + +const pb_field_t dfu_packet_fields[3] = { + PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, dfu_packet_t, command, command, &dfu_command_fields), + PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, dfu_packet_t, signed_command, command, &dfu_signed_command_fields), + PB_LAST_FIELD +}; + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(dfu_init_command_t, hash) < 65536 && pb_membersize(dfu_command_t, init) < 65536 && pb_membersize(dfu_signed_command_t, command) < 65536 && pb_membersize(dfu_packet_t, command) < 65536 && pb_membersize(dfu_packet_t, signed_command) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_dfu_hash_dfu_init_command_dfu_command_dfu_signed_command_dfu_packet) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(dfu_init_command_t, hash) < 256 && pb_membersize(dfu_command_t, init) < 256 && pb_membersize(dfu_signed_command_t, command) < 256 && pb_membersize(dfu_packet_t, command) < 256 && pb_membersize(dfu_packet_t, signed_command) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_dfu_hash_dfu_init_command_dfu_command_dfu_signed_command_dfu_packet) +#endif + + +/* @@protoc_insertion_point(eof) */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/dfu-cc.pb.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/dfu-cc.pb.h new file mode 100644 index 0000000..fae43c5 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/dfu-cc.pb.h @@ -0,0 +1,213 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.6-dev at Wed Dec 13 13:37:53 2017. */ + +#ifndef PB_DFU_CC_PB_H_INCLUDED +#define PB_DFU_CC_PB_H_INCLUDED +#include <pb.h> + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Enum definitions */ +typedef enum +{ + DFU_FW_TYPE_APPLICATION = 0, + DFU_FW_TYPE_SOFTDEVICE = 1, + DFU_FW_TYPE_BOOTLOADER = 2, + DFU_FW_TYPE_SOFTDEVICE_BOOTLOADER = 3 +} dfu_fw_type_t; +#define DFU_FW_TYPE_MIN DFU_FW_TYPE_APPLICATION +#define DFU_FW_TYPE_MAX DFU_FW_TYPE_SOFTDEVICE_BOOTLOADER +#define DFU_FW_TYPE_ARRAYSIZE ((dfu_fw_type_t)(DFU_FW_TYPE_SOFTDEVICE_BOOTLOADER+1)) + +typedef enum +{ + DFU_HASH_TYPE_NO_HASH = 0, + DFU_HASH_TYPE_CRC = 1, + DFU_HASH_TYPE_SHA128 = 2, + DFU_HASH_TYPE_SHA256 = 3, + DFU_HASH_TYPE_SHA512 = 4 +} dfu_hash_type_t; +#define DFU_HASH_TYPE_MIN DFU_HASH_TYPE_NO_HASH +#define DFU_HASH_TYPE_MAX DFU_HASH_TYPE_SHA512 +#define DFU_HASH_TYPE_ARRAYSIZE ((dfu_hash_type_t)(DFU_HASH_TYPE_SHA512+1)) + +typedef enum +{ + DFU_SIGNATURE_TYPE_ECDSA_P256_SHA256 = 0, + DFU_SIGNATURE_TYPE_ED25519 = 1 +} dfu_signature_type_t; +#define DFU_SIGNATURE_TYPE_MIN DFU_SIGNATURE_TYPE_ECDSA_P256_SHA256 +#define DFU_SIGNATURE_TYPE_MAX DFU_SIGNATURE_TYPE_ED25519 +#define DFU_SIGNATURE_TYPE_ARRAYSIZE ((dfu_signature_type_t)(DFU_SIGNATURE_TYPE_ED25519+1)) + +typedef enum +{ + DFU_COMMAND_OP_CODE_INIT = 1 +} dfu_command_op_code_t; +#define DFU_COMMAND_OP_CODE_MIN DFU_COMMAND_OP_CODE_INIT +#define DFU_COMMAND_OP_CODE_MAX DFU_COMMAND_OP_CODE_INIT +#define DFU_COMMAND_OP_CODE_ARRAYSIZE ((dfu_command_op_code_t)(DFU_COMMAND_OP_CODE_INIT+1)) + +/* Struct definitions */ +typedef PB_BYTES_ARRAY_T(32) dfu_hash_hash_t; +typedef struct { + dfu_hash_type_t hash_type; + dfu_hash_hash_t hash; +/* @@protoc_insertion_point(struct:dfu_hash_t) */ +} dfu_hash_t; + +typedef struct { + bool has_fw_version; + uint32_t fw_version; + bool has_hw_version; + uint32_t hw_version; + pb_size_t sd_req_count; + uint32_t sd_req[16]; + bool has_type; + dfu_fw_type_t type; + bool has_sd_size; + uint32_t sd_size; + bool has_bl_size; + uint32_t bl_size; + bool has_app_size; + uint32_t app_size; + bool has_hash; + dfu_hash_t hash; + bool has_is_debug; + bool is_debug; +/* @@protoc_insertion_point(struct:dfu_init_command_t) */ +} dfu_init_command_t; + +typedef struct { + bool has_op_code; + dfu_command_op_code_t op_code; + bool has_init; + dfu_init_command_t init; +/* @@protoc_insertion_point(struct:dfu_command_t) */ +} dfu_command_t; + +typedef PB_BYTES_ARRAY_T(64) dfu_signed_command_signature_t; +typedef struct { + dfu_command_t command; + dfu_signature_type_t signature_type; + dfu_signed_command_signature_t signature; +/* @@protoc_insertion_point(struct:dfu_signed_command_t) */ +} dfu_signed_command_t; + +typedef struct { + bool has_command; + dfu_command_t command; + bool has_signed_command; + dfu_signed_command_t signed_command; +/* @@protoc_insertion_point(struct:dfu_packet_t) */ +} dfu_packet_t; + +/* Default values for struct fields */ +extern const bool dfu_init_command_is_debug_default; + +/* Initializer values for message structs */ +#define DFU_HASH_INIT_DEFAULT {(dfu_hash_type_t)0, {0, {0}}} +#define DFU_INIT_COMMAND_INIT_DEFAULT {false, 0, false, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false, (dfu_fw_type_t)0, false, 0, false, 0, false, 0, false, DFU_HASH_INIT_DEFAULT, false, false} +#define DFU_COMMAND_INIT_DEFAULT {false, (dfu_command_op_code_t)0, false, DFU_INIT_COMMAND_INIT_DEFAULT} +#define DFU_SIGNED_COMMAND_INIT_DEFAULT {DFU_COMMAND_INIT_DEFAULT, (dfu_signature_type_t)0, {0, {0}}} +#define DFU_PACKET_INIT_DEFAULT {false, DFU_COMMAND_INIT_DEFAULT, false, DFU_SIGNED_COMMAND_INIT_DEFAULT} +#define DFU_HASH_INIT_ZERO {(dfu_hash_type_t)0, {0, {0}}} +#define DFU_INIT_COMMAND_INIT_ZERO {false, 0, false, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false, (dfu_fw_type_t)0, false, 0, false, 0, false, 0, false, DFU_HASH_INIT_ZERO, false, 0} +#define DFU_COMMAND_INIT_ZERO {false, (dfu_command_op_code_t)0, false, DFU_INIT_COMMAND_INIT_ZERO} +#define DFU_SIGNED_COMMAND_INIT_ZERO {DFU_COMMAND_INIT_ZERO, (dfu_signature_type_t)0, {0, {0}}} +#define DFU_PACKET_INIT_ZERO {false, DFU_COMMAND_INIT_ZERO, false, DFU_SIGNED_COMMAND_INIT_ZERO} + +/* Field tags (for use in manual encoding/decoding) */ +#define DFU_HASH_HASH_TYPE_TAG 1 +#define DFU_HASH_HASH_TAG 2 +#define DFU_INIT_COMMAND_FW_VERSION_TAG 1 +#define DFU_INIT_COMMAND_HW_VERSION_TAG 2 +#define DFU_INIT_COMMAND_SD_REQ_TAG 3 +#define DFU_INIT_COMMAND_TYPE_TAG 4 +#define DFU_INIT_COMMAND_SD_SIZE_TAG 5 +#define DFU_INIT_COMMAND_BL_SIZE_TAG 6 +#define DFU_INIT_COMMAND_APP_SIZE_TAG 7 +#define DFU_INIT_COMMAND_HASH_TAG 8 +#define DFU_INIT_COMMAND_IS_DEBUG_TAG 9 +#define DFU_COMMAND_OP_CODE_TAG 1 +#define DFU_COMMAND_INIT_TAG 2 +#define DFU_SIGNED_COMMAND_COMMAND_TAG 1 +#define DFU_SIGNED_COMMAND_SIGNATURE_TYPE_TAG 2 +#define DFU_SIGNED_COMMAND_SIGNATURE_TAG 3 +#define DFU_PACKET_COMMAND_TAG 1 +#define DFU_PACKET_SIGNED_COMMAND_TAG 2 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t dfu_hash_fields[3]; +extern const pb_field_t dfu_init_command_fields[10]; +extern const pb_field_t dfu_command_fields[3]; +extern const pb_field_t dfu_signed_command_fields[4]; +extern const pb_field_t dfu_packet_fields[3]; + +/* Maximum encoded size of messages (where known) */ +#define DFU_HASH_SIZE 36 +#define DFU_INIT_COMMAND_SIZE 168 +#define DFU_COMMAND_SIZE 173 +#define DFU_SIGNED_COMMAND_SIZE 244 +#define DFU_PACKET_SIZE 423 + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define DFU_CC_MESSAGES \ + + +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/dfu-cc.proto b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/dfu-cc.proto new file mode 100644 index 0000000..69f9680 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/dfu-cc.proto @@ -0,0 +1,66 @@ +package dfu; + +// Version 0.1 + +enum FwType { + APPLICATION = 0; // default, compatible with proto3 + SOFTDEVICE = 1; + BOOTLOADER = 2; + SOFTDEVICE_BOOTLOADER = 3; +} + +enum HashType { + NO_HASH = 0; + CRC = 1; + SHA128 = 2; + SHA256 = 3; + SHA512 = 4; +} + +message Hash { + required HashType hash_type = 1; + required bytes hash = 2; +} + +// Commands data +message InitCommand { + optional uint32 fw_version = 1; + optional uint32 hw_version = 2; + repeated uint32 sd_req = 3 [packed = true]; // packed option is default in proto3 + optional FwType type = 4; + + optional uint32 sd_size = 5; + optional uint32 bl_size = 6; + optional uint32 app_size = 7; + + optional Hash hash = 8; + + optional bool is_debug = 9 [default = false]; +} + +// Command type +message Command { + enum OpCode { + INIT = 1; + } + optional OpCode op_code = 1; + optional InitCommand init = 2; +} + +// Signed command types +enum SignatureType { + ECDSA_P256_SHA256 = 0; + ED25519 = 1; +} + +message SignedCommand { + required Command command = 1; + required SignatureType signature_type = 2; + required bytes signature = 3; +} + +// Parent packet type +message Packet { + optional Command command = 1; + optional SignedCommand signed_command = 2; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu.c new file mode 100644 index 0000000..f2c9796 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu.c @@ -0,0 +1,100 @@ +/** + * 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 "nrf_dfu.h" + +#include "nrf_dfu_utils.h" +#include "nrf_dfu_transport.h" +#include "nrf_dfu_req_handler.h" +#include "app_timer.h" +#include "nrf_log.h" + +static nrf_dfu_observer_t m_user_observer; //<! Observer callback set by the user. + + + +/** + * @brief This function calls the user's observer (@ref m_observer) after it is done handling the event. + */ +static void dfu_observer(nrf_dfu_evt_type_t event) +{ + switch (event) + { + case NRF_DFU_EVT_DFU_COMPLETED: + { +#ifndef NRF_DFU_NO_TRANSPORT + UNUSED_RETURN_VALUE(nrf_dfu_transports_close(NULL)); +#endif + break; + } + default: + break; + } + + /* Call user's observer if present. */ + if (m_user_observer) + { + m_user_observer(event); + } +} + + + +uint32_t nrf_dfu_init(nrf_dfu_observer_t observer) +{ + uint32_t ret_val; + + m_user_observer = observer; + + NRF_LOG_INFO("Entering DFU mode."); + + dfu_observer(NRF_DFU_EVT_DFU_INITIALIZED); + + // Initializing transports + ret_val = nrf_dfu_transports_init(dfu_observer); + if (ret_val != NRF_SUCCESS) + { + NRF_LOG_ERROR("Could not initalize DFU transport: 0x%08x", ret_val); + return ret_val; + } + + ret_val = nrf_dfu_req_handler_init(dfu_observer); + + return ret_val; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu.h new file mode 100644 index 0000000..34d7aee --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu.h @@ -0,0 +1,85 @@ +/** + * 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. + * + */ +/**@file + * + * @defgroup nrf_dfu DFU modules + * @{ + * @ingroup nrf_bootloader + * @brief Modules providing Device Firmware Update (DFU) functionality. + * + * The DFU module, in combination with the @ref nrf_bootloader module, + * can be used to implement a bootloader that supports Device Firmware Updates. + */ + +#ifndef NRF_DFU_H__ +#define NRF_DFU_H__ + +#include <stdint.h> +#include <stdbool.h> +#include "nrf_dfu_types.h" +#include "nrf_dfu_req_handler.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#define NRF_DFU_SCHED_EVENT_DATA_SIZE (sizeof(nrf_dfu_request_t)) + + +/** @brief Function for initializing a DFU operation. + * + * This function initializes a DFU operation and any transports that are registered + * in the system. + * + * @param[in] observer Function for receiving DFU notifications. + * + * @retval NRF_SUCCESS If the DFU operation was successfully initialized. + */ +uint32_t nrf_dfu_init(nrf_dfu_observer_t observer); + + +#ifdef __cplusplus +} +#endif + +#endif // NRF_DFU_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_flash.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_flash.c new file mode 100644 index 0000000..c4e047a --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_flash.c @@ -0,0 +1,167 @@ +/** + * 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 "nrf_dfu_flash.h" +#include "nrf_dfu_types.h" + +#include "nrf_fstorage.h" +#include "nrf_fstorage_sd.h" +#include "nrf_fstorage_nvmc.h" + + +#define NRF_LOG_MODULE_NAME nrf_dfu_flash +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + + +void dfu_fstorage_evt_handler(nrf_fstorage_evt_t * p_evt); + + +NRF_FSTORAGE_DEF(nrf_fstorage_t m_fs) = +{ + .evt_handler = dfu_fstorage_evt_handler, + .start_addr = MBR_SIZE, + .end_addr = BOOTLOADER_SETTINGS_ADDRESS + BOOTLOADER_SETTINGS_PAGE_SIZE +}; + +static uint32_t m_flash_operations_pending; + +void dfu_fstorage_evt_handler(nrf_fstorage_evt_t * p_evt) +{ + if (NRF_LOG_ENABLED && (m_flash_operations_pending > 0)) + { + m_flash_operations_pending--; + } + + if (p_evt->result == NRF_SUCCESS) + { + NRF_LOG_DEBUG("Flash %s success: addr=%p, pending %d", + (p_evt->id == NRF_FSTORAGE_EVT_WRITE_RESULT) ? "write" : "erase", + p_evt->addr, m_flash_operations_pending); + } + else + { + NRF_LOG_DEBUG("Flash %s failed (0x%x): addr=%p, len=0x%x bytes, pending %d", + (p_evt->id == NRF_FSTORAGE_EVT_WRITE_RESULT) ? "write" : "erase", + p_evt->result, p_evt->addr, p_evt->len, m_flash_operations_pending); + } + + if (p_evt->p_param) + { + //lint -save -e611 (Suspicious cast) + ((nrf_dfu_flash_callback_t)(p_evt->p_param))((void*)p_evt->p_src); + //lint -restore + } +} + + +ret_code_t nrf_dfu_flash_init(bool sd_irq_initialized) +{ + nrf_fstorage_api_t * p_api_impl; + + /* Setup the desired API implementation. */ +#ifdef BLE_STACK_SUPPORT_REQD + if (sd_irq_initialized) + { + NRF_LOG_DEBUG("Initializing nrf_fstorage_sd backend."); + p_api_impl = &nrf_fstorage_sd; + } + else +#endif + { + NRF_LOG_DEBUG("Initializing nrf_fstorage_nvmc backend."); + p_api_impl = &nrf_fstorage_nvmc; + } + + return nrf_fstorage_init(&m_fs, p_api_impl, NULL); +} + + +ret_code_t nrf_dfu_flash_store(uint32_t dest, + void const * p_src, + uint32_t len, + nrf_dfu_flash_callback_t callback) +{ + ret_code_t rc; + + NRF_LOG_DEBUG("nrf_fstorage_write(addr=%p, src=%p, len=%d bytes), queue usage: %d", + dest, p_src, len, m_flash_operations_pending); + + //lint -save -e611 (Suspicious cast) + rc = nrf_fstorage_write(&m_fs, dest, p_src, len, (void *)callback); + //lint -restore + + if ((NRF_LOG_ENABLED) && (rc == NRF_SUCCESS)) + { + m_flash_operations_pending++; + } + else + { + NRF_LOG_WARNING("nrf_fstorage_write() failed with error 0x%x.", rc); + } + + return rc; +} + + +ret_code_t nrf_dfu_flash_erase(uint32_t page_addr, + uint32_t num_pages, + nrf_dfu_flash_callback_t callback) +{ + ret_code_t rc; + + NRF_LOG_DEBUG("nrf_fstorage_erase(addr=0x%p, len=%d pages), queue usage: %d", + page_addr, num_pages, m_flash_operations_pending); + + //lint -save -e611 (Suspicious cast) + rc = nrf_fstorage_erase(&m_fs, page_addr, num_pages, (void *)callback); + //lint -restore + + if ((NRF_LOG_ENABLED) && (rc == NRF_SUCCESS)) + { + m_flash_operations_pending++; + } + else + { + NRF_LOG_WARNING("nrf_fstorage_erase() failed with error 0x%x.", rc); + } + + return rc; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_flash.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_flash.h new file mode 100644 index 0000000..fb14610 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_flash.h @@ -0,0 +1,132 @@ +/** + * 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. + * + */ +/**@file + * + * @defgroup sdk_nrf_dfu_flash Flash operations + * @{ + * @ingroup nrf_dfu + */ + +#ifndef NRF_DFU_FLASH_H__ +#define NRF_DFU_FLASH_H__ + +#include <stdint.h> +#include <stdbool.h> +#include "sdk_errors.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/**@brief nrf_fstorage event handler function for DFU fstorage operations. + * + * This function will be called after a flash operation has completed. + */ +typedef void (*nrf_dfu_flash_callback_t)(void * p_buf); + + +/**@brief Function for initializing the flash module. + * + * Depending on whether or not the SoftDevice is present and its IRQ have been initialized, + * this function initializes the correct @ref nrf_fstorage backend. + * + * @param[in] sd_irq_initialized Whether or not the SoftDevice IRQ have been initialized. + * + * @retval NRF_SUCCESS If the operation was successful. + */ +ret_code_t nrf_dfu_flash_init(bool sd_irq_initialized); + + +/**@brief Function for storing data to flash. + * + * This functions is asynchronous when the SoftDevice is enabled and synchronous when + * the SoftDevice is not present or disabled. In both cases, if a callback function is provided, + * it will be called when the operation has completed. + * + * @note The content of @p p_src should be kept in memory until the operation has completed. + * + * @param[in] dest The address where the data should be stored. + * @param[in] p_src Pointer to the address where the data should be copied from. + * This address can be in flash or RAM. + * @param[in] len The number of bytes to be copied from @p p_src to @p dest. + * @param[in] callback Callback function. + * + * @retval NRF_SUCCESS If the operation was successful. + * @retval NRF_ERROR_INVALID_STATE If nrf_dfu_flash is not initialized. + * @retval NRF_ERROR_INVALID_ADDR If @p p_src or @p dest is not word-aligned. + * @retval NRF_ERROR_INVALID_LENGTH If @p len is zero. + * @retval NRF_ERROR_NULL If @p p_src is NULL. + * @retval NRF_ERROR_NO_MEM If nrf_fstorage is out of memory. + */ +ret_code_t nrf_dfu_flash_store(uint32_t dest, + void const * p_src, + uint32_t len, + nrf_dfu_flash_callback_t callback); + + +/**@brief Function for erasing data from flash. + * + * This functions is asynchronous when the SoftDevice is enabled and synchronous when + * the SoftDevice is not present or disabled. In both cases, if a callback function is provided, + * it will be called when the operation has completed. + * + * @param[in] page_addr The address of the first flash page to be deleted. + * @param[in] num_pages The number of flash pages to be deleted. + * @param[in] callback Callback function. + * + * @retval NRF_SUCCESS If the operation was successful. + * @retval NRF_ERROR_INVALID_STATE If nrf_dfu_flash is not initialized. + * @retval NRF_ERROR_INVALID_ADDR If @p page_addr is not aligned to a page boundary or the + * operation would go beyond the flash memory boundaries. + * @retval NRF_ERROR_INVALID_LENGTH If @p num_pages is zero. + * @retval NRF_ERROR_NULL If @p page_addr is NULL. + * @retval NRF_ERROR_NO_MEM If the queue of nrf_fstorage is full. + */ +ret_code_t nrf_dfu_flash_erase(uint32_t page_addr, uint32_t num_pages, nrf_dfu_flash_callback_t callback); + + +#ifdef __cplusplus +} +#endif + + +#endif // NRF_DFU_FLASH_H__ +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_handling_error.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_handling_error.c new file mode 100644 index 0000000..ba42123 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_handling_error.c @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "nrf_dfu_handling_error.h" + +#include "nrf_log.h" +#include "nrf_dfu_req_handler.h" + +static nrf_dfu_ext_error_code_t m_last_error = NRF_DFU_EXT_ERROR_NO_ERROR; + +nrf_dfu_result_t ext_error_set(nrf_dfu_ext_error_code_t error_code) +{ + m_last_error = error_code; + + return NRF_DFU_RES_CODE_EXT_ERROR; +} + +nrf_dfu_ext_error_code_t ext_error_get() +{ + nrf_dfu_ext_error_code_t last_error = m_last_error; + m_last_error = NRF_DFU_EXT_ERROR_NO_ERROR; + + return last_error; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_handling_error.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_handling_error.h new file mode 100644 index 0000000..5a459e9 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_handling_error.h @@ -0,0 +1,124 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + /**@file + * + * @defgroup nrf_dfu_rescodes DFU result codes + * @{ + * @ingroup sdk_nrf_dfu_transport + * @brief When the DFU controller sends requests to the DFU bootloader on + * the DFU target, the DFU bootloader answers with any of these result codes. + */ + + +#ifndef DFU_HANDLING_ERROR_H__ +#define DFU_HANDLING_ERROR_H__ + +#include "nrf_dfu_types.h" +#include "nrf_dfu_req_handler.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + +/**@brief DFU request extended result codes. + * + * @details When an event returns @ref NRF_DFU_RES_CODE_EXT_ERROR, it also stores an extended error code. + * The transport layer can then send the extended error code together with the error code to give + * the controller additional information about the cause of the error. + */ +typedef enum +{ + NRF_DFU_EXT_ERROR_NO_ERROR = 0x00, /**< No extended error code has been set. This error indicates an implementation problem. */ + NRF_DFU_EXT_ERROR_INVALID_ERROR_CODE = 0x01, /**< Invalid error code. This error code should never be used outside of development. */ + NRF_DFU_EXT_ERROR_WRONG_COMMAND_FORMAT = 0x02, /**< The format of the command was incorrect. This error code is not used in the + current implementation, because @ref NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED + and @ref NRF_DFU_RES_CODE_INVALID_PARAMETER cover all + possible format errors. */ + NRF_DFU_EXT_ERROR_UNKNOWN_COMMAND = 0x03, /**< The command was successfully parsed, but it is not supported or unknown. */ + NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID = 0x04, /**< The init command is invalid. The init packet either has + an invalid update type or it is missing required fields for the update type + (for example, the init packet for a SoftDevice update is missing the SoftDevice size field). */ + NRF_DFU_EXT_ERROR_FW_VERSION_FAILURE = 0x05, /**< The firmware version is too low. For an application, the version must be greater than + the current application. For a bootloader, it must be greater than or equal + to the current version. This requirement prevents downgrade attacks.*/ + NRF_DFU_EXT_ERROR_HW_VERSION_FAILURE = 0x06, /**< The hardware version of the device does not match the required + hardware version for the update. */ + NRF_DFU_EXT_ERROR_SD_VERSION_FAILURE = 0x07, /**< The array of supported SoftDevices for the update does not contain + the FWID of the current SoftDevice. */ + NRF_DFU_EXT_ERROR_SIGNATURE_MISSING = 0x08, /**< The init packet does not contain a signature. This error code is not used in the + current implementation, because init packets without a signature + are regarded as invalid. */ + NRF_DFU_EXT_ERROR_WRONG_HASH_TYPE = 0x09, /**< The hash type that is specified by the init packet is not supported by the DFU bootloader. */ + NRF_DFU_EXT_ERROR_HASH_FAILED = 0x0A, /**< The hash of the firmware image cannot be calculated. */ + NRF_DFU_EXT_ERROR_WRONG_SIGNATURE_TYPE = 0x0B, /**< The type of the signature is unknown or not supported by the DFU bootloader. */ + NRF_DFU_EXT_ERROR_VERIFICATION_FAILED = 0x0C, /**< The hash of the received firmware image does not match the hash in the init packet. */ + NRF_DFU_EXT_ERROR_INSUFFICIENT_SPACE = 0x0D, /**< The available space on the device is insufficient to hold the firmware. */ +} nrf_dfu_ext_error_code_t; + + +/**@brief Function for setting an extended error code that can be retrieved later. + * + * @details When an extended error occurs in the DFU process, this function can be used to store the error. + * + * @param error_code The error code to store. + * + * @retval NRF_DFU_RES_CODE_EXT_ERROR + */ +nrf_dfu_result_t ext_error_set(nrf_dfu_ext_error_code_t error_code); + +/**@brief Function for getting the most recent extended error code. + * + * @details This function is used by the transport layer to fetch the most recent extended error code. + * + * @return The most recent error code. If the function is called again before a new error occurs, @ref NRF_DFU_EXT_ERROR_NO_ERROR is returned. + */ +nrf_dfu_ext_error_code_t ext_error_get( void ); + + +#ifdef __cplusplus +} +#endif + +#endif // DFU_HANDLING_ERROR_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_mbr.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_mbr.c new file mode 100644 index 0000000..974a466 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_mbr.c @@ -0,0 +1,109 @@ +/** + * 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 "nrf_dfu_mbr.h" +#include "nrf_mbr.h" +#include "nrf_dfu_types.h" +#include "nrf_log.h" +#include "nrf_bootloader_info.h" + +#define MBR_IRQ_FORWARD_ADDRESS_ADDRESS (0x20000000) //!< The address of the variable that decides where the MBR forwards interrupts + +uint32_t nrf_dfu_mbr_copy_bl(uint32_t * p_src, uint32_t len) +{ + uint32_t ret_val; + uint32_t const len_words = len / sizeof(uint32_t); + + sd_mbr_command_t command = + { + .command = SD_MBR_COMMAND_COPY_BL, + .params.copy_bl.bl_src = p_src, + .params.copy_bl.bl_len = len_words + }; + + ret_val = sd_mbr_command(&command); + + return ret_val; +} + + +uint32_t nrf_dfu_mbr_init_sd(void) +{ + uint32_t ret_val; + + sd_mbr_command_t command = + { + .command = SD_MBR_COMMAND_INIT_SD + }; + + ret_val = sd_mbr_command(&command); + + return ret_val; +} + + +uint32_t nrf_dfu_mbr_irq_forward_address_set(void) +{ + uint32_t ret_val = NRF_ERROR_INVALID_PARAM; + uint32_t address = MBR_SIZE; + + NRF_LOG_DEBUG("running irq table set"); + +#ifndef BLE_STACK_SUPPORT_REQD + sd_mbr_command_t command = + { + .command = SD_MBR_COMMAND_IRQ_FORWARD_ADDRESS_SET, + .params.irq_forward_address_set.address = address, + }; + + ret_val = sd_mbr_command(&command); +#endif + + if (ret_val == NRF_ERROR_INVALID_PARAM) + { + // Manually set the forward address if this MBR doesn't have the command. + *(uint32_t *)(MBR_IRQ_FORWARD_ADDRESS_ADDRESS) = address; + + ret_val = NRF_SUCCESS; + } + + NRF_LOG_DEBUG("After running irq table set"); + + return ret_val; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_mbr.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_mbr.h new file mode 100644 index 0000000..2fcd1b3 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_mbr.h @@ -0,0 +1,90 @@ +/** + * 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. + * + */ +/**@file + * + * @defgroup sdk_nrf_dfu_mbr MBR functions + * @{ + * @ingroup nrf_dfu + */ + +#ifndef NRF_DFU_MBR_H__ +#define NRF_DFU_MBR_H__ + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Function for copying the bootloader using an MBR command. + * + * @param[in] p_src Source address of the bootloader data to copy. + * @param[in] len Length of the data to copy in bytes. + * + * @return This function will return only if the command request could not be run. + * See @ref sd_mbr_command_copy_bl_t for possible return values. + */ +uint32_t nrf_dfu_mbr_copy_bl(uint32_t * p_src, uint32_t len); + + +/** @brief Function for initializing the SoftDevice using an MBR command. + * + * @retval NRF_SUCCESS If the SoftDevice was initialized successfully. + * Any other return value indicates that the SoftDevice + * could not be initialized. + */ +uint32_t nrf_dfu_mbr_init_sd(void); + + +/** @brief Function for setting the address of the IRQ table to the app's using an MBR command. + * + * @retval NRF_SUCCESS If the address of the new irq table was set. Any other + * return value indicates that the address could not be set. + */ +uint32_t nrf_dfu_mbr_irq_forward_address_set(void); + + +#ifdef __cplusplus +} +#endif + +#endif // NRF_DFU_MBR_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_req_handler.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_req_handler.c new file mode 100644 index 0000000..6dfb1cc --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_req_handler.c @@ -0,0 +1,855 @@ +/** + * 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(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); + + 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_code_t 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, + }; + + nrf_dfu_flash_callback_t dfu_settings_callback; + + /* Whole firmware image was received, validate it. */ + if (s_dfu_settings.progress.firmware_image_offset == m_firmware_size_req) + { + NRF_LOG_DEBUG("Postvalidation of firmware image."); + + res.result = nrf_dfu_validation_post_data_execute(m_firmware_start_addr, m_firmware_size_req); + res.result = ext_err_code_handle(res.result); + + /* Callback to on_dfu_complete() after updating the settings. */ + dfu_settings_callback = (nrf_dfu_flash_callback_t)(on_dfu_complete); + } + else + { + res.result = NRF_DFU_RES_CODE_SUCCESS; + /* No callback required. */ + dfu_settings_callback = NULL; + } + + /* Provide response to transport */ + p_req->callback.response(&res, p_req->p_context); + + /* Store settings to flash if the whole image was received or if configured + * to save progress information in flash. + */ + if ((dfu_settings_callback != NULL) || NRF_DFU_SAVE_PROGRESS_IN_FLASH) + { + ret_code_t ret = nrf_dfu_settings_write(dfu_settings_callback); + 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) +{ + 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; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_req_handler.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_req_handler.h new file mode 100644 index 0000000..c9d10d2 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_req_handler.h @@ -0,0 +1,345 @@ +/** + * 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. + * + */ +/**@file + * + * @defgroup sdk_nrf_dfu_req_handler Request handling + * @{ + * @ingroup nrf_dfu + */ + +#ifndef NRF_DFU_REQ_HANDLER_H__ +#define NRF_DFU_REQ_HANDLER_H__ + +#include <stdint.h> +#include <stdbool.h> +#include "app_util_platform.h" +#include "nrf_dfu_flash.h" +#include "nrf_dfu_types.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +ANON_UNIONS_ENABLE; + +/** + * @brief DFU object types. + */ +typedef enum +{ + NRF_DFU_OBJ_TYPE_INVALID, //!< Invalid object type. + NRF_DFU_OBJ_TYPE_COMMAND, //!< Command object. + NRF_DFU_OBJ_TYPE_DATA, //!< Data object. +} nrf_dfu_obj_type_t; + +/** + * @brief DFU protocol operation. + */ +typedef enum +{ + NRF_DFU_OP_PROTOCOL_VERSION = 0x00, //!< Retrieve protocol version. + NRF_DFU_OP_OBJECT_CREATE = 0x01, //!< Create selected object. + NRF_DFU_OP_RECEIPT_NOTIF_SET = 0x02, //!< Set receipt notification. + NRF_DFU_OP_CRC_GET = 0x03, //!< Request CRC of selected object. + NRF_DFU_OP_OBJECT_EXECUTE = 0x04, //!< Execute selected object. + NRF_DFU_OP_OBJECT_SELECT = 0x06, //!< Select object. + NRF_DFU_OP_MTU_GET = 0x07, //!< Retrieve MTU size. + NRF_DFU_OP_OBJECT_WRITE = 0x08, //!< Write selected object. + NRF_DFU_OP_PING = 0x09, //!< Ping. + NRF_DFU_OP_HARDWARE_VERSION = 0x0A, //!< Retrieve hardware version. + NRF_DFU_OP_FIRMWARE_VERSION = 0x0B, //!< Retrieve firmware version. + NRF_DFU_OP_ABORT = 0x0C, //!< Abort the DFU procedure. + NRF_DFU_OP_RESPONSE = 0x60, //!< Response. + NRF_DFU_OP_INVALID = 0xFF, +} nrf_dfu_op_t; + +/** + * @brief DFU operation result code. + */ +typedef enum +{ + NRF_DFU_RES_CODE_INVALID = 0x00, //!< Invalid opcode. + NRF_DFU_RES_CODE_SUCCESS = 0x01, //!< Operation successful. + NRF_DFU_RES_CODE_OP_CODE_NOT_SUPPORTED = 0x02, //!< Opcode not supported. + NRF_DFU_RES_CODE_INVALID_PARAMETER = 0x03, //!< Missing or invalid parameter value. + NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES = 0x04, //!< Not enough memory for the data object. + NRF_DFU_RES_CODE_INVALID_OBJECT = 0x05, //!< Data object does not match the firmware and hardware requirements, the signature is wrong, or parsing the command failed. + NRF_DFU_RES_CODE_UNSUPPORTED_TYPE = 0x07, //!< Not a valid object type for a Create request. + NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED = 0x08, //!< The state of the DFU process does not allow this operation. + NRF_DFU_RES_CODE_OPERATION_FAILED = 0x0A, //!< Operation failed. + NRF_DFU_RES_CODE_EXT_ERROR = 0x0B, //!< Extended error. The next byte of the response contains the error code of the extended error (see @ref nrf_dfu_ext_error_code_t. +} nrf_dfu_result_t; + +typedef enum +{ + NRF_DFU_FIRMWARE_TYPE_SOFTDEVICE = 0x00, + NRF_DFU_FIRMWARE_TYPE_APPLICATION = 0x01, + NRF_DFU_FIRMWARE_TYPE_BOOTLOADER = 0x02, + NRF_DFU_FIRMWARE_TYPE_UNKNOWN = 0xFF, +} nrf_dfu_firmware_type_t; + +/** + * @brief @ref NRF_DFU_OP_PROTOCOL_VERSION response details. + */ +typedef struct +{ + uint8_t version; //!< Protocol version. +} nrf_dfu_response_protocol_t; + +/** + * @brief @ref NRF_DFU_OP_HARDWARE_VERSION response details. + */ +typedef struct +{ + uint32_t part; //!< Hardware part, from FICR register. + uint32_t variant; //!< Hardware variant, from FICR register. + struct + { + uint32_t rom_size; //!< ROM size, in bytes. + uint32_t ram_size; //!< RAM size, in bytes. + uint32_t rom_page_size; //!< ROM flash page size, in bytes. + } memory; +} nrf_dfu_response_hardware_t; + +/** + * @brief @ref NRF_DFU_OP_FIRMWARE_VERSION response details. + */ +typedef struct +{ + nrf_dfu_firmware_type_t type; //!< Firmware type. + uint32_t version; //!< Firmware version. + uint32_t addr; //!< Firmware address in flash. + uint32_t len; //!< Firmware length in bytes. +} nrf_dfu_response_firmware_t; + +/** + * @brief @ref NRF_DFU_OP_OBJECT_SELECT response details. + */ +typedef struct +{ + uint32_t offset; //!< Current offset. + uint32_t crc; //!< Current CRC. + uint32_t max_size; //!< Maximum size of selected object. +} nrf_dfu_response_select_t; + +/** + * @brief @ref NRF_DFU_OP_OBJECT_CREATE response details. + */ +typedef struct +{ + uint32_t offset; //!< Current offset + uint32_t crc; //!< Current CRC. +} nrf_dfu_response_create_t; + +/** + * @brief @ref NRF_DFU_OP_OBJECT_WRITE response details. + */ +typedef struct +{ + uint32_t offset; //!< Used only when packet receipt notification is used. + uint32_t crc; //!< Used only when packet receipt notification is used. +} nrf_dfu_response_write_t; + +/** + * @brief @ref NRF_DFU_OP_CRC_GET response details. + */ +typedef struct +{ + uint32_t offset; //!< Current offset. + uint32_t crc; //!< Current CRC. +} nrf_dfu_response_crc_t; + +/** + * @brief @ref NRF_DFU_OP_PING response details. + */ +typedef struct +{ + uint8_t id; //!< The received ID which is echoed back. +} nrf_dfu_response_ping_t; + +/** + * @brief @ref NRF_DFU_OP_MTU_GET response details. + */ +typedef struct +{ + uint16_t size; //!< The MTU size as specified by the local transport. +} nrf_dfu_response_mtu_t; + +/** + * @brief DFU response message. + */ +typedef struct +{ + nrf_dfu_op_t request; //!< Requested operation. + nrf_dfu_result_t result; //!< Result of the operation. + union + { + nrf_dfu_response_protocol_t protocol; //!< Protocol version response. + nrf_dfu_response_hardware_t hardware; //!< Hardware version response. + nrf_dfu_response_firmware_t firmware; //!< Firmware version response. + nrf_dfu_response_select_t select; //!< Select object response.. + nrf_dfu_response_create_t create; //!< Create object response.. + nrf_dfu_response_write_t write; //!< Write object response. + nrf_dfu_response_crc_t crc; //!< CRC response. + nrf_dfu_response_ping_t ping; //!< Ping response. + nrf_dfu_response_mtu_t mtu; //!< MTU response. + }; +} nrf_dfu_response_t; + +/** + * @brief @ref NRF_DFU_OP_FIRMWARE_VERSION request details. + */ +typedef struct +{ + uint8_t image_number; //!< Index of the firmware. +} nrf_dfu_request_firmware_t; + +/** + * @brief @ref NRF_DFU_OP_OBJECT_SELECT request details. + */ +typedef struct +{ + uint32_t object_type; //!< Object type. See @ref nrf_dfu_obj_type_t. +} nrf_dfu_request_select_t; + +/** + * @brief @ref NRF_DFU_OP_OBJECT_CREATE request details. + */ +typedef struct +{ + uint32_t object_type; //!< Object type. See @ref nrf_dfu_obj_type_t. + uint32_t object_size; //!< Object size in bytes. +} nrf_dfu_request_create_t; + +/** + * @brief @ref NRF_DFU_OP_OBJECT_WRITE request details. + */ +typedef struct +{ + uint8_t const * p_data; //!< Data. + uint16_t len; //!< Length of data in @ref nrf_dfu_request_write_t::p_data. +} nrf_dfu_request_write_t; + +/** + * @brief @ref NRF_DFU_OP_PING request details. + */ +typedef struct +{ + uint8_t id; //!< Ping ID that will be returned in response. +} nrf_dfu_request_ping_t; + +/** + * @brief @ref NRF_DFU_OP_MTU_GET request details. + */ +typedef struct +{ + uint16_t size; //!< Transport MTU size in bytes. +} nrf_dfu_request_mtu_t; + +/** + * @brief @ref NRF_DFU_OP_RECEIPT_NOTIF_SET request details. + */ +typedef struct +{ + uint32_t target; //!< Target PRN. +} nrf_dfu_request_prn_t; + + +typedef void (*nrf_dfu_response_callback_t)(nrf_dfu_response_t * p_res, void * p_context); + +/** + *@brief DFU request. + */ +typedef struct +{ + nrf_dfu_op_t request; //!< Requested operation. + void * p_context; + struct + { + nrf_dfu_response_callback_t response; //!< Callback to call to send the response. + nrf_dfu_flash_callback_t write; + } callback; + union + { + nrf_dfu_request_firmware_t firmware; //!< Firmware version request. + nrf_dfu_request_select_t select; //!< Select object request. + nrf_dfu_request_create_t create; //!< Create object request. + nrf_dfu_request_write_t write; //!< Write object request. + nrf_dfu_request_ping_t ping; //!< Ping. + nrf_dfu_request_mtu_t mtu; //!< MTU size request. + nrf_dfu_request_prn_t prn; //!< Set receipt notification request. + }; +} nrf_dfu_request_t; + + +/**@brief Function for initializing the request handling module. + * + * @param observer Function for receiving notifications. + * + * @retval NRF_SUCCESS If the operation was successful. + * @retval NRF_ERROR_INTERNAL If the init packet in flash is not valid. + * @retval NRF_ERROR_INVALID_PARAM If observer is not provided. + */ +ret_code_t nrf_dfu_req_handler_init(nrf_dfu_observer_t observer); + + +/**@brief Function for scheduling processing of a DFU request. + * + * Requests are processed asynchronously by the scheduler. + * + * @param[in] p_req Request to be handled. The response callback must be non-null. + * + * @retval NRF_SUCCESS If the command request was executed successfully. + * @retval NRF_ERROR_NO_MEM If the scheduler ran out of memory. + * @retval NRF_ERROR_INVALID_PARAM If the response callback is NULL. + */ +ret_code_t nrf_dfu_req_handler_on_req(nrf_dfu_request_t * p_req); + + +ANON_UNIONS_DISABLE; + +#ifdef __cplusplus +} +#endif + +#endif // NRF_DFU_REQ_HANDLER_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_settings.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_settings.c new file mode 100644 index 0000000..13e89b4 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_settings.c @@ -0,0 +1,241 @@ +/** + * 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 "nrf_dfu_settings.h" +#include <stddef.h> +#include <string.h> +#include "app_error.h" +#include "nrf_dfu_flash.h" +#include "nrf_soc.h" +#include "crc32.h" +#include "nrf_nvmc.h" + +#define DFU_SETTINGS_INIT_COMMAND_OFFSET offsetof(nrf_dfu_settings_t, init_command) //<! Offset in the settings struct where the InitCommand is located. + +#define NRF_LOG_MODULE_NAME nrf_dfu_settings +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + + +/**@brief This variable reserves a page in flash for bootloader settings + * to ensure the linker doesn't place any code or variables at this location. + */ +#if defined (__CC_ARM ) + + uint8_t m_dfu_settings_buffer[BOOTLOADER_SETTINGS_PAGE_SIZE] + __attribute__((at(BOOTLOADER_SETTINGS_ADDRESS))) + __attribute__((used)); + +#elif defined ( __GNUC__ ) || defined ( __SES_ARM ) + + uint8_t m_dfu_settings_buffer[BOOTLOADER_SETTINGS_PAGE_SIZE] + __attribute__((section(".bootloader_settings_page"))) + __attribute__((used)); + +#elif defined ( __ICCARM__ ) + + __no_init __root uint8_t m_dfu_settings_buffer[BOOTLOADER_SETTINGS_PAGE_SIZE] + @ BOOTLOADER_SETTINGS_ADDRESS; + +#else + + #error Not a valid compiler/linker for m_dfu_settings placement. + +#endif // Compiler specific + +#ifndef BL_SETTINGS_ACCESS_ONLY +#if defined(NRF52_SERIES) + +/**@brief This variable reserves a page in flash for MBR parameters + * to ensure the linker doesn't place any code or variables at this location. + */ +#if defined ( __CC_ARM ) + + uint8_t m_mbr_params_page[NRF_MBR_PARAMS_PAGE_SIZE] + __attribute__((at(NRF_MBR_PARAMS_PAGE_ADDRESS))) + __attribute__((used)); + +#elif defined ( __GNUC__ ) || defined ( __SES_ARM ) + + uint8_t m_mbr_params_page[NRF_MBR_PARAMS_PAGE_SIZE] + __attribute__ ((section(".mbr_params_page"))); + +#elif defined ( __ICCARM__ ) + + __no_init uint8_t m_mbr_params_page[NRF_MBR_PARAMS_PAGE_SIZE] + @ NRF_MBR_PARAMS_PAGE_ADDRESS; + +#else + + #error Not a valid compiler/linker for m_mbr_params_page placement. + +#endif // Compiler specific + + +/**@brief This variable has the linker write the MBR parameters page address to the + * UICR register. This value will be written in the HEX file and thus to the + * UICR when the bootloader is flashed into the chip. + */ +#if defined ( __CC_ARM ) + + uint32_t const m_uicr_mbr_params_page_address + __attribute__((at(NRF_UICR_MBR_PARAMS_PAGE_ADDRESS))) = NRF_MBR_PARAMS_PAGE_ADDRESS; + +#elif defined ( __GNUC__ ) || defined ( __SES_ARM ) + + uint32_t const m_uicr_mbr_params_page_address + __attribute__ ((section(".uicr_mbr_params_page"))) + __attribute__ ((used)) = NRF_MBR_PARAMS_PAGE_ADDRESS; + +#elif defined ( __ICCARM__ ) + + __root uint32_t const m_uicr_mbr_params_page_address + @ NRF_UICR_MBR_PARAMS_PAGE_ADDRESS = NRF_MBR_PARAMS_PAGE_ADDRESS; + +#else + + #error Not a valid compiler/linker for m_mbr_params_page placement. + +#endif // Compiler specific +#endif // #if defined( NRF52_SERIES ) +#endif // #ifndef BL_SETTINGS_ACCESS_ONLY + + +nrf_dfu_settings_t s_dfu_settings; + + +static uint32_t nrf_dfu_settings_crc_get(void) +{ + // The crc is calculated from the s_dfu_settings struct, except the crc itself and the init command + return crc32_compute((uint8_t*)&s_dfu_settings + 4, DFU_SETTINGS_INIT_COMMAND_OFFSET - 4, NULL); +} + + +ret_code_t nrf_dfu_settings_init(bool sd_irq_initialized) +{ + NRF_LOG_DEBUG("Calling nrf_dfu_settings_init()..."); + + ret_code_t rc = nrf_dfu_flash_init(sd_irq_initialized); + if (rc != NRF_SUCCESS) + { + NRF_LOG_ERROR("nrf_dfu_flash_init() failed with error: %x", rc); + return NRF_ERROR_INTERNAL; + } + + // Copy the DFU settings out of flash and into a buffer in RAM. + memcpy((void*)&s_dfu_settings, m_dfu_settings_buffer, sizeof(nrf_dfu_settings_t)); + + if (s_dfu_settings.crc != 0xFFFFFFFF) + { + // CRC is set. Content must be valid + uint32_t crc = nrf_dfu_settings_crc_get(); + if (crc == s_dfu_settings.crc) + { + return NRF_SUCCESS; + } + } + + // Reached if the page is erased or CRC is wrong. + NRF_LOG_DEBUG("Resetting bootloader settings."); + + memset(&s_dfu_settings, 0x00, sizeof(nrf_dfu_settings_t)); + s_dfu_settings.settings_version = NRF_DFU_SETTINGS_VERSION; + + rc = nrf_dfu_settings_write(NULL); + if (rc != NRF_SUCCESS) + { + NRF_LOG_ERROR("nrf_dfu_flash_write() failed with error: %x", rc); + return NRF_ERROR_INTERNAL; + } + return NRF_SUCCESS; +} + + +ret_code_t nrf_dfu_settings_write(nrf_dfu_flash_callback_t callback) +{ + ret_code_t err_code; + + if (memcmp(&s_dfu_settings, m_dfu_settings_buffer, sizeof(nrf_dfu_settings_t)) == 0) + { + NRF_LOG_DEBUG("New settings are identical to old, write not needed. Skipping."); + if (callback != NULL) + { + callback(NULL); + } + return NRF_SUCCESS; + } + + NRF_LOG_DEBUG("Writing settings..."); + NRF_LOG_DEBUG("Erasing old settings at: 0x%08x", (uint32_t)m_dfu_settings_buffer); + + // Not setting the callback function because ERASE is required before STORE + // Only report completion on successful STORE. + err_code = nrf_dfu_flash_erase((uint32_t)m_dfu_settings_buffer, 1, NULL); + + if (err_code != NRF_SUCCESS) + { + NRF_LOG_ERROR("Could not erase the settings page!"); + return NRF_ERROR_INTERNAL; + } + + s_dfu_settings.crc = nrf_dfu_settings_crc_get(); + + static nrf_dfu_settings_t temp_dfu_settings; + memcpy(&temp_dfu_settings, &s_dfu_settings, sizeof(nrf_dfu_settings_t)); + + err_code = nrf_dfu_flash_store((uint32_t)m_dfu_settings_buffer, + &temp_dfu_settings, + sizeof(nrf_dfu_settings_t), + callback); + + if (err_code != NRF_SUCCESS) + { + NRF_LOG_ERROR("Could not write the DFU settings page!"); + return NRF_ERROR_INTERNAL; + } + + return NRF_SUCCESS; +} + +__WEAK ret_code_t nrf_dfu_settings_additional_erase(void) +{ + NRF_LOG_WARNING("No additional data erased"); + return NRF_SUCCESS; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_settings.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_settings.h new file mode 100644 index 0000000..9e9dedb --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_settings.h @@ -0,0 +1,173 @@ +/** + * 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. + * + */ +/**@file + * + * @defgroup nrf_dfu_settings DFU settings + * @{ + * @ingroup nrf_dfu + */ + +#ifndef NRF_DFU_SETTINGS_H__ +#define NRF_DFU_SETTINGS_H__ + +#include <stdint.h> +#include "nrf_dfu_types.h" +#include "nrf_dfu_flash.h" +#include "sdk_config.h" +#include "sdk_errors.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/**@brief Global settings. + * + * @note Using this variable is not thread-safe. + * + */ +extern nrf_dfu_settings_t s_dfu_settings; + + +/**@brief Function for writing DFU settings to flash. + * + * @param[in] callback Pointer to a function that is called after completing the write operation. + * + * @retval NRF_SUCCESS If the write process was successfully initiated. + * @retval NRF_ERROR_INTERNAL If a flash error occurred. + */ +ret_code_t nrf_dfu_settings_write(nrf_dfu_flash_callback_t callback); + + +/**@brief Function for initializing the DFU settings module. + * + * @retval NRF_SUCCESS If the initialization was successful. + * @retval NRF_ERROR_INTERNAL If a flash error occurred. + */ +ret_code_t nrf_dfu_settings_init(bool sd_irq_initialized); + + +#if defined(NRF_DFU_TRANSPORT_BLE) && NRF_DFU_TRANSPORT_BLE +/** @brief Function for storing peer data received through an SVCI call in DFU settings. + * + * @note The content of the type can be verified by a CRC value stored inside the struct + * If the CRC value is 0xFFFFFFFF, it means that no data is set. + * + * @note The storage operation is an asynchronous progress. Success will be notified + * through system events raised by the SoftDevice. + * + * @param[in] p_data Peer data to be stored in flash. + * + * @retval NRF_SUCCESS Asynchronous operation was successfully started. + * @retval NRF_ERROR_NULL p_data was NULL. + * @retval Any other error code reported by SoftDevice API calls. + */ +ret_code_t nrf_dfu_settings_peer_data_write(nrf_dfu_peer_data_t * p_data); + + +/** @brief Function for copying peer data from DFU settings to RAM. + * + * @param[in,out] p_data Structure to copy peer data to. + * + * @retval NRF_SUCCESS Peer data was successfully copied. + * @retval NRF_ERROR_NULL p_data was NULL. + */ +ret_code_t nrf_dfu_settings_peer_data_copy(nrf_dfu_peer_data_t * p_data); + + +/** @brief Function for validating peer data in DFU settings. + * + * @retval True if peer data is validated by CRC, false if not. + */ +bool nrf_dfu_settings_peer_data_is_valid(void); + + +/** @brief Function for storing an advertisement name received through an SVCI call in DFU settings. + * + * @note The content of the type is verifyable by a CRC-value stored inside the struct. + * + * @note The storage operation is an asynchronous progress. Success will be notified + * through system events raised by the SoftDevice. + * + * @param[in] p_adv_name Structure holding information about the new advertisement name. + * + * @retval NRF_SUCCESS Asynchronous operation was successfully started. + * @retval NRF_ERROR_NULL p_adv_name was NULL. + * @retval Any other error code reported by SoftDevice API calls. + */ +ret_code_t nrf_dfu_settings_adv_name_write(nrf_dfu_adv_name_t * p_adv_name); + + +/** @brief Function for copying the advertisement name from DFU settings to RAM. + * + * @param[in,out] p_adv_name Structure to copy the new advertisement name to. + * + * @retval NRF_SUCCESS Advertisement name was successfully copied. + * @retval NRF_ERROR_NULL p_adv_name was NULL. + */ +ret_code_t nrf_dfu_settings_adv_name_copy(nrf_dfu_adv_name_t * p_adv_name); + + +/** @brief Function for validating advertisement data in DFU settings. + * + * @retval True if advertisement name is validated by CRC, false if not. + */ +bool nrf_dfu_settings_adv_name_is_valid(void); + +#endif // NRF_DFU_TRANSPORT_BLE + +/** @brief Function for erasing additional data in DFU settings. + * + * @note Erasing additional data in DFU settings is only possible + * if nrf_dfu_flash is initialized to not use SoftDevice calls. + * + * @retval NRF_SUCCESS Additional data was successfully erased. + * @retval Any other error code reported by nrf_dfu_flash + */ +ret_code_t nrf_dfu_settings_additional_erase(void); + + +#ifdef __cplusplus +} +#endif + +#endif // NRF_DFU_SETTINGS_H__ + +/**@} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_settings_svci.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_settings_svci.c new file mode 100644 index 0000000..41deb9e --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_settings_svci.c @@ -0,0 +1,185 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <stddef.h> +#include <string.h> +#include "app_error.h" +#include "sdk_macros.h" +#include "nrf_dfu_settings.h" +#include "nrf_nvmc.h" +#include "crc32.h" + +#define NRF_LOG_MODULE_NAME nrf_dfu_settings_svci +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +#define DFU_SETTINGS_PEER_DATA_OFFSET offsetof(nrf_dfu_settings_t, peer_data) //<! Offset in the settings struct where the additional peer data is located. +#define DFU_SETTINGS_ADV_NAME_OFFSET offsetof(nrf_dfu_settings_t, adv_name) //<! Offset in the settings struct where the additional advertisement name is located. + +extern nrf_dfu_settings_t s_dfu_settings; +extern uint8_t m_dfu_settings_buffer[CODE_PAGE_SIZE]; + +#if defined(NRF_DFU_BLE_REQUIRES_BONDS) && (NRF_DFU_BLE_REQUIRES_BONDS == 1) + +ret_code_t nrf_dfu_settings_peer_data_write(nrf_dfu_peer_data_t * p_data) +{ + uint32_t ret_val; + + uint32_t * p_peer_data_settings = + (uint32_t*) &m_dfu_settings_buffer[DFU_SETTINGS_PEER_DATA_OFFSET]; + + uint32_t crc = (uint32_t)*p_peer_data_settings; + + VERIFY_PARAM_NOT_NULL(p_data); + + if (crc != 0xFFFFFFFF) + { + // Already written to, must be cleared out + // Reset required. + return NRF_ERROR_INVALID_STATE; + } + + // Calculate the CRC for the structure excluding the CRC value itself. + p_data->crc = crc32_compute((uint8_t*)p_data + 4, sizeof(nrf_dfu_peer_data_t) - 4, NULL); + + // Using SoftDevice call since this function cannot use static memory. + ret_val = sd_flash_write(p_peer_data_settings, + (uint32_t*)p_data, + sizeof(nrf_dfu_peer_data_t)/4); + + return ret_val; +} + + +ret_code_t nrf_dfu_settings_peer_data_copy(nrf_dfu_peer_data_t * p_data) +{ + VERIFY_PARAM_NOT_NULL(p_data); + + memcpy(p_data, &m_dfu_settings_buffer[DFU_SETTINGS_PEER_DATA_OFFSET], sizeof(nrf_dfu_peer_data_t)); + + return NRF_SUCCESS; +} + + +bool nrf_dfu_settings_peer_data_is_valid(void) +{ + nrf_dfu_peer_data_t * p_peer_data = + (nrf_dfu_peer_data_t*) &m_dfu_settings_buffer[DFU_SETTINGS_PEER_DATA_OFFSET]; + + // Calculate the CRC for the structure excluding the CRC value itself. + uint32_t crc = crc32_compute((uint8_t*)p_peer_data + 4, sizeof(nrf_dfu_peer_data_t) - 4, NULL); + + return (p_peer_data->crc == crc); +} + +#else // not NRF_DFU_BLE_REQUIRES_BONDS + +ret_code_t nrf_dfu_settings_adv_name_write(nrf_dfu_adv_name_t * p_adv_name) +{ + uint32_t ret_val; + + uint32_t * p_adv_name_settings = + (uint32_t*) &m_dfu_settings_buffer[DFU_SETTINGS_ADV_NAME_OFFSET]; + + uint32_t crc = (uint32_t)*p_adv_name_settings; + + VERIFY_PARAM_NOT_NULL(p_adv_name); + + if (crc != 0xFFFFFFFF) + { + // Already written to, must be cleared out. + // Reset required + return NRF_ERROR_INVALID_STATE; + } + + // Calculate the CRC for the structure excluding the CRC value itself. + p_adv_name->crc = crc32_compute((uint8_t *)p_adv_name + 4, sizeof(nrf_dfu_adv_name_t) - 4, NULL); + + // Using SoftDevice call since this function cannot use static memory. + ret_val = sd_flash_write(p_adv_name_settings, + (uint32_t*) p_adv_name, + sizeof(nrf_dfu_adv_name_t)/4); + return ret_val; +} + + +ret_code_t nrf_dfu_settings_adv_name_copy(nrf_dfu_adv_name_t * p_adv_name) +{ + VERIFY_PARAM_NOT_NULL(p_adv_name); + memcpy(p_adv_name, &m_dfu_settings_buffer[DFU_SETTINGS_ADV_NAME_OFFSET], sizeof(nrf_dfu_adv_name_t)); + + return NRF_SUCCESS; +} + + +bool nrf_dfu_settings_adv_name_is_valid(void) +{ + nrf_dfu_adv_name_t * p_adv_name = + (nrf_dfu_adv_name_t*)&m_dfu_settings_buffer[DFU_SETTINGS_ADV_NAME_OFFSET]; + + // Calculate the CRC for the structure excluding the CRC value itself. + uint32_t crc = crc32_compute((uint8_t*)p_adv_name + 4, sizeof(nrf_dfu_adv_name_t) - 4, NULL); + + return (p_adv_name->crc == crc); +} + +#endif + + +//lint -save -e(14) +ret_code_t nrf_dfu_settings_additional_erase(void) +{ + ret_code_t ret_code = NRF_SUCCESS; + + // Check CRC for both types. + if ( (s_dfu_settings.peer_data.crc != 0xFFFFFFFF) + || (s_dfu_settings.adv_name.crc != 0xFFFFFFFF)) + { + NRF_LOG_DEBUG("Erasing settings page additional data."); + + // Erasing and resetting the settings page without the peer data/adv data + nrf_nvmc_page_erase(BOOTLOADER_SETTINGS_ADDRESS); + nrf_nvmc_write_words(BOOTLOADER_SETTINGS_ADDRESS, (uint32_t const *)&s_dfu_settings, DFU_SETTINGS_PEER_DATA_OFFSET / 4); + } + + return ret_code; +} +//lint -restore + diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_svci.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_svci.c new file mode 100644 index 0000000..ceff394 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_svci.c @@ -0,0 +1,86 @@ +/** + * 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 "nrf_log.h" +#include "nrf_sdm.h" +#include "app_util.h" + +#define APP_START_ADDR CODE_START + + +uint32_t nrf_dfu_svci_vector_table_set(void) +{ + uint32_t err_code; + + if (NRF_UICR->NRFFW[0] != 0xFFFFFFFF) + { + NRF_LOG_INFO("Setting vector table to bootloader: 0x%08x", NRF_UICR->NRFFW[0]); + err_code = sd_softdevice_vector_table_base_set(NRF_UICR->NRFFW[0]); + if (err_code != NRF_SUCCESS) + { + NRF_LOG_ERROR("Failed running sd_softdevice_vector_table_base_set"); + return err_code; + } + + return NRF_SUCCESS; + } + + NRF_LOG_ERROR("No bootloader was found"); + return NRF_ERROR_NO_MEM; +} + + +uint32_t nrf_dfu_svci_vector_table_unset(void) +{ + uint32_t err_code; + + NRF_LOG_INFO("Setting vector table to main app: 0x%08x", APP_START_ADDR); + err_code = sd_softdevice_vector_table_base_set(APP_START_ADDR); + if (err_code != NRF_SUCCESS) + { + NRF_LOG_ERROR("Failed running sd_softdevice_vector_table_base_set"); + return err_code; + } + + return NRF_SUCCESS; +} + diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_svci_handler.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_svci_handler.c new file mode 100644 index 0000000..ce75be7 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_svci_handler.c @@ -0,0 +1,222 @@ +/** + * 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 <string.h> +#include "nrf_svci_async_handler.h" +#include "app_error.h" +#include "nrf_nvmc.h" +#include "nrf_dfu_types.h" +#include "nrf_dfu_ble_svci_bond_sharing.h" +#include "nrf_log.h" +#include "nrf_dfu_settings.h" +#include "sdk_config.h" + + +#if (NRF_DFU_TRANSPORT_BLE && NRF_DFU_BLE_REQUIRES_BONDS) + + +NRF_SVCI_ASYNC_HANDLER_CREATE(NRF_DFU_SVCI_SET_PEER_DATA, + nrf_dfu_set_peer_data, nrf_dfu_peer_data_t, nrf_dfu_peer_data_state_t); + + +static uint32_t nrf_dfu_set_peer_data_handler(nrf_dfu_set_peer_data_svci_async_t * p_async) +{ + VERIFY_PARAM_NOT_NULL(p_async); + + p_async->async_func = nrf_dfu_set_peer_data_on_call; + p_async->sys_evt_handler = nrf_dfu_set_peer_data_on_sys_evt; + p_async->state = DFU_PEER_DATA_STATE_INITIALIZED; + + return NRF_SUCCESS; +} + + +static uint32_t nrf_dfu_set_peer_data_on_call(nrf_dfu_peer_data_t * p_data, + nrf_dfu_peer_data_state_t * p_state) +{ + uint32_t ret_val = NRF_ERROR_BUSY; + + VERIFY_PARAM_NOT_NULL(p_state); + + if (NRF_BL_SETTINGS_PAGE_PROTECT) + { + return NRF_ERROR_FORBIDDEN; + } + + switch (*p_state) + { + case DFU_PEER_DATA_STATE_INVALID: + return NRF_ERROR_INVALID_STATE; + + case DFU_PEER_DATA_STATE_INITIALIZED: + ret_val = nrf_dfu_settings_peer_data_write(p_data); + if (ret_val == NRF_SUCCESS) + { + *p_state = DFU_PEER_DATA_STATE_WRITE_REQUESTED; + } + break; + + case DFU_PEER_DATA_STATE_WRITE_REQUESTED: + return NRF_ERROR_BUSY; + + case DFU_PEER_DATA_STATE_WRITE_FINISHED: + return NRF_ERROR_INVALID_STATE; + + case DFU_PEER_DATA_STATE_WRITE_FAILED: + return NRF_ERROR_INVALID_STATE; + } + + return ret_val; +} + + +static uint32_t nrf_dfu_set_peer_data_on_sys_evt(uint32_t sys_event, nrf_dfu_peer_data_state_t * p_state) +{ + uint32_t ret_val = NRF_ERROR_INVALID_STATE; + + VERIFY_PARAM_NOT_NULL(p_state); + + if (*p_state == DFU_PEER_DATA_STATE_WRITE_REQUESTED) + { + switch (sys_event) + { + case NRF_EVT_FLASH_OPERATION_ERROR: + return NRF_ERROR_BUSY; + + case NRF_EVT_FLASH_OPERATION_SUCCESS: + ret_val = NRF_SUCCESS; + (*p_state) = DFU_PEER_DATA_STATE_WRITE_FINISHED; + break; + + default: + // Event not intended for us + break; + } + } + + return ret_val; +} + +#elif (NRF_DFU_TRANSPORT_BLE && !NRF_DFU_BLE_REQUIRES_BONDS) + + +NRF_SVCI_ASYNC_HANDLER_CREATE(NRF_DFU_SVCI_SET_ADV_NAME, + nrf_dfu_set_adv_name, nrf_dfu_adv_name_t, nrf_dfu_set_adv_name_state_t); + + +static uint32_t nrf_dfu_set_adv_name_handler(nrf_dfu_set_adv_name_svci_async_t * p_async) +{ + VERIFY_PARAM_NOT_NULL(p_async); + + p_async->async_func = nrf_dfu_set_adv_name_on_call; + p_async->sys_evt_handler = nrf_dfu_set_adv_name_on_sys_evt; + p_async->state = DFU_ADV_NAME_STATE_INITIALIZED; + + return NRF_SUCCESS; +} + + +static uint32_t nrf_dfu_set_adv_name_on_call(nrf_dfu_adv_name_t * p_adv_name, + nrf_dfu_set_adv_name_state_t * p_state) +{ + uint32_t ret_val = NRF_ERROR_BUSY; + + VERIFY_PARAM_NOT_NULL(p_state); + + if (NRF_BL_SETTINGS_PAGE_PROTECT) + { + return NRF_ERROR_FORBIDDEN; + } + + switch (*p_state) + { + case DFU_ADV_NAME_STATE_INVALID: + return NRF_ERROR_INVALID_STATE; + + case DFU_ADV_NAME_STATE_INITIALIZED: + ret_val = nrf_dfu_settings_adv_name_write(p_adv_name); + if (ret_val == NRF_SUCCESS) + { + *p_state = DFU_ADV_NAME_STATE_WRITE_REQUESTED; + } + break; + + case DFU_ADV_NAME_STATE_WRITE_REQUESTED: + return NRF_ERROR_BUSY; + + case DFU_ADV_NAME_STATE_WRITE_FINISHED: + return NRF_ERROR_INVALID_STATE; + + case DFU_ADV_NAME_STATE_WRITE_FAILED: + return NRF_ERROR_INVALID_STATE; + } + + return ret_val; +} + + +static uint32_t nrf_dfu_set_adv_name_on_sys_evt(uint32_t sys_event, nrf_dfu_set_adv_name_state_t * p_state) +{ + uint32_t ret_val = NRF_ERROR_INVALID_STATE; + + VERIFY_PARAM_NOT_NULL(p_state); + + if (*p_state == DFU_ADV_NAME_STATE_WRITE_REQUESTED) + { + switch (sys_event) + { + case NRF_EVT_FLASH_OPERATION_ERROR: + return NRF_ERROR_BUSY; + + case NRF_EVT_FLASH_OPERATION_SUCCESS: + ret_val = NRF_SUCCESS; + (*p_state) = DFU_ADV_NAME_STATE_WRITE_FINISHED; + break; + + default: + // Event not intended for us + break; + } + } + + return ret_val; +} + +#endif // NRF_DFU_TRANSPORT_BLE && !NRF_DFU_BLE_REQUIRES_BONDS diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_transport.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_transport.c new file mode 100644 index 0000000..6075538 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_transport.c @@ -0,0 +1,91 @@ +/** + * 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 "nrf_dfu_transport.h" +#include "nrf_log.h" + + +#define DFU_TRANS_SECTION_ITEM_GET(i) NRF_SECTION_ITEM_GET(dfu_trans, nrf_dfu_transport_t, (i)) +#define DFU_TRANS_SECTION_ITEM_COUNT NRF_SECTION_ITEM_COUNT(dfu_trans, nrf_dfu_transport_t) + +NRF_SECTION_DEF(dfu_trans, const nrf_dfu_transport_t); + + +uint32_t nrf_dfu_transports_init(nrf_dfu_observer_t observer) +{ + uint32_t const num_transports = DFU_TRANS_SECTION_ITEM_COUNT; + uint32_t ret_val = NRF_SUCCESS; + + NRF_LOG_DEBUG("Initializing transports (found: %d)", num_transports); + + for (uint32_t i = 0; i < num_transports; i++) + { + nrf_dfu_transport_t * const trans = DFU_TRANS_SECTION_ITEM_GET(i); + ret_val = trans->init_func(observer); + if (ret_val != NRF_SUCCESS) + { + NRF_LOG_DEBUG("Failed to initialize transport %d, error %d", i, ret_val); + break; + } + } + + return ret_val; +} + + +uint32_t nrf_dfu_transports_close(nrf_dfu_transport_t const * p_exception) +{ + uint32_t const num_transports = DFU_TRANS_SECTION_ITEM_COUNT; + uint32_t ret_val = NRF_SUCCESS; + + NRF_LOG_DEBUG("Shutting down transports (found: %d)", num_transports); + + for (uint32_t i = 0; i < num_transports; i++) + { + nrf_dfu_transport_t * const trans = DFU_TRANS_SECTION_ITEM_GET(i); + ret_val = trans->close_func(p_exception); + if (ret_val != NRF_SUCCESS) + { + NRF_LOG_DEBUG("Failed to shutdown transport %d, error %d", i, ret_val); + break; + } + } + + return ret_val; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_transport.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_transport.h new file mode 100644 index 0000000..b8368f0 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_transport.h @@ -0,0 +1,134 @@ +/** + * 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. + * + */ +/**@file + * + * @defgroup sdk_nrf_dfu_transport DFU transport + * @{ + * @ingroup nrf_dfu + * @brief Generic Device Firmware Update (DFU) transport interface. + * + * @details The DFU transport module defines a generic interface that must + * be implemented for each transport layer. + */ + +#ifndef NRF_DFU_TRANSPORT_H__ +#define NRF_DFU_TRANSPORT_H__ + +#include <stdint.h> +#include "nrf_section.h" +#include "nrf_dfu_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Forward declaration of nrf_dfu_transport_t */ +typedef struct nrf_dfu_transport_s nrf_dfu_transport_t; + +/** @brief Function type for initializing a DFU transport. + * + * @details This function initializes a DFU transport. The implementation + * of the function must initialize DFU mode and stay in service + * until either the device is reset or the DFU operation is finalized. + * When the DFU transport receives requests, it should call @ref nrf_dfu_req_handler_on_req for handling the requests. + * + * @param observer Function for receiving DFU transport notifications. + * + * @retval NRF_SUCCESS If initialization was successful for the transport. Any other return code indicates that the DFU transport could not be initialized. + */ +typedef uint32_t (*nrf_dfu_init_fn_t)(nrf_dfu_observer_t observer); + + +/** @brief Function type for closing down a DFU transport. + * + * @details This function closes down a DFU transport in a gentle way. + * + * @param[in] p_exception If exception matches current transport closing should be omitted. + * + * @retval NRF_SUCCESS If closing was successful for the transport. Any other return code indicates that the DFU transport could not be closed closed down. + */ +typedef uint32_t (*nrf_dfu_close_fn_t)(nrf_dfu_transport_t const * p_exception); + + + +/** @brief DFU transport registration. + * + * @details Every DFU transport must provide a registration of the initialization function. + */ +struct nrf_dfu_transport_s +{ + nrf_dfu_init_fn_t init_func; /**< Registration of the init function to run to initialize a DFU transport. */ + nrf_dfu_close_fn_t close_func; /**< Registration of the close function to close down a DFU transport. */ +}; + + +/** @brief Function for initializing all the registered DFU transports. + * + * @retval NRF_SUCCESS If all DFU transport were initialized successfully. + * Any other error code indicates that at least one DFU + * transport could not be initialized. + */ +uint32_t nrf_dfu_transports_init(nrf_dfu_observer_t observer); + +/** @brief Function for closing down all (with optional exception) the registered DFU transports. + * + * @param[in] p_exception Transport which should not be closed. NULL if all transports should be closed. + * @retval NRF_SUCCESS If all DFU transport were closed down successfully. + * Any other error code indicates that at least one DFU + * transport could not be closed down. + */ +uint32_t nrf_dfu_transports_close(nrf_dfu_transport_t const * p_exception); + + +/** @brief Macro for registering a DFU transport by using section variables. + * + * @details This macro places a variable in a section named "dfu_trans", which + * is initialized by @ref nrf_dfu_transports_init. + */ +#define DFU_TRANSPORT_REGISTER(trans_var) NRF_SECTION_ITEM_REGISTER(dfu_trans, trans_var) + + +#ifdef __cplusplus +} +#endif + +#endif // NRF_DFU_TRANSPORT_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_trigger_usb.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_trigger_usb.c new file mode 100644 index 0000000..582d60c --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_trigger_usb.c @@ -0,0 +1,237 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "nrf_dfu_trigger_usb.h" +#include "app_usbd_string_config.h" +#include "app_usbd.h" +#include "app_usbd_nrf_dfu_trigger.h" +#include "nrf_drv_clock.h" +#include "nrf_log_ctrl.h" +#include "nrf_gpio.h" +#include "boards.h" +#include "app_util.h" +#include "app_usbd_serial_num.h" +#define NRF_LOG_MODULE_NAME nrf_dfu_trigger_usb +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +#ifndef BSP_SELF_PINRESET_PIN +#error "This module is intended to be used with boards that have the GP pin shortened with the RESET pin." +#endif + +/** + * @brief Enable power USB detection. + * + * Configure if the example supports USB port connection. + */ +#ifndef USBD_POWER_DETECTION +#define USBD_POWER_DETECTION true +#endif + +#define DFU_FLASH_PAGE_SIZE (NRF_FICR->CODEPAGESIZE) +#define DFU_FLASH_PAGE_COUNT (NRF_FICR->CODESIZE) + +// Semantic versioning string. +#define VERSION_STRING STRINGIFY(APP_VERSION_MAJOR) "." STRINGIFY(APP_VERSION_MINOR) "." STRINGIFY(APP_VERSION_PATCH) APP_VERSION_PRERELEASE APP_VERSION_METADATA + +static uint8_t m_version_string[] = APP_NAME " " VERSION_STRING; ///< Human-readable version string. +static app_usbd_nrf_dfu_trigger_nordic_info_t m_dfu_info; ///< Struct with various information about the current firmware. + +static void dfu_trigger_evt_handler(app_usbd_class_inst_t const * p_inst, + app_usbd_nrf_dfu_trigger_user_event_t event) +{ + UNUSED_PARAMETER(p_inst); + + switch (event) + { + case APP_USBD_NRF_DFU_TRIGGER_USER_EVT_DETACH: + NRF_LOG_INFO("DFU Detach request received. Triggering a pin reset."); + NRF_LOG_FINAL_FLUSH(); + nrf_gpio_cfg_output(BSP_SELF_PINRESET_PIN); + nrf_gpio_pin_clear(BSP_SELF_PINRESET_PIN); + break; + default: + break; + } +} + + +APP_USBD_NRF_DFU_TRIGGER_GLOBAL_DEF(m_app_dfu, + NRF_DFU_TRIGGER_USB_INTERFACE_NUM, + &m_dfu_info, + m_version_string, + dfu_trigger_evt_handler); + + +static void usbd_user_evt_handler(app_usbd_event_type_t event) +{ + switch (event) + { + case APP_USBD_EVT_DRV_SUSPEND: + break; + case APP_USBD_EVT_DRV_RESUME: + break; + case APP_USBD_EVT_STARTED: + break; + case APP_USBD_EVT_STOPPED: + app_usbd_disable(); + break; + case APP_USBD_EVT_POWER_DETECTED: + NRF_LOG_INFO("USB power detected"); + + if (!nrf_drv_usbd_is_enabled()) + { + app_usbd_enable(); + } + break; + case APP_USBD_EVT_POWER_REMOVED: + NRF_LOG_INFO("USB power removed"); + app_usbd_stop(); + break; + case APP_USBD_EVT_POWER_READY: + NRF_LOG_INFO("USB ready"); + app_usbd_start(); + break; + default: + break; + } +} + + +static void serial_number_strings_create(void) +{ + // Remove characters that are not supported in semantic versioning strings. + for (size_t i = strlen(APP_NAME) + 1; i < strlen((char*)m_version_string); i++) + { + if (((m_version_string[i] >= 'a') && (m_version_string[i] <= 'z')) + || ((m_version_string[i] >= 'A') && (m_version_string[i] <= 'Z')) + || ((m_version_string[i] >= '0') && (m_version_string[i] <= '9')) + || (m_version_string[i] == '+') + || (m_version_string[i] == '.') + || (m_version_string[i] == '-')) + { + // Valid semantic versioning character. + } + else + { + m_version_string[i] = '-'; + } + } + +#if !NRF_DFU_TRIGGER_USB_USB_SHARED + app_usbd_serial_num_generate(); +#endif +} + +#if !(APP_USBD_CONFIG_EVENT_QUEUE_ENABLE) +static void usbd_evt_handler(app_usbd_internal_evt_t const * const p_event) +{ + app_usbd_event_execute(p_event); +} +#endif + +ret_code_t nrf_dfu_trigger_usb_init(void) +{ + ret_code_t ret; + static bool initialized = false; + + if (initialized) + { + return NRF_SUCCESS; + } + + m_dfu_info.wAddress = CODE_START; + m_dfu_info.wFirmwareSize = CODE_SIZE; + m_dfu_info.wVersionMajor = APP_VERSION_MAJOR; + m_dfu_info.wVersionMinor = APP_VERSION_MINOR; + m_dfu_info.wFirmwareID = APP_ID; + m_dfu_info.wFlashPageSize = DFU_FLASH_PAGE_SIZE; + m_dfu_info.wFlashSize = m_dfu_info.wFlashPageSize * DFU_FLASH_PAGE_COUNT; + + serial_number_strings_create(); + + if (!NRF_DFU_TRIGGER_USB_USB_SHARED) + { + static const app_usbd_config_t usbd_config = { + +#if !(APP_USBD_CONFIG_EVENT_QUEUE_ENABLE) + .ev_handler = usbd_evt_handler, +#endif + .ev_state_proc = usbd_user_evt_handler + }; + + ret = nrf_drv_clock_init(); + if ((ret != NRF_SUCCESS) && (ret != NRF_ERROR_MODULE_ALREADY_INITIALIZED)) + { + return ret; + } + + ret = app_usbd_init(&usbd_config); + if (ret != NRF_SUCCESS) + { + return ret; + } + } + + app_usbd_class_inst_t const * class_dfu = app_usbd_nrf_dfu_trigger_class_inst_get(&m_app_dfu); + ret = app_usbd_class_append(class_dfu); + + if (!NRF_DFU_TRIGGER_USB_USB_SHARED) + { + if (USBD_POWER_DETECTION) + { + ret = app_usbd_power_events_enable(); + APP_ERROR_CHECK(ret); + } + else + { + NRF_LOG_INFO("No USB power detection enabled\r\nStarting USB now"); + + app_usbd_enable(); + app_usbd_start(); + } + } + + if (ret == NRF_SUCCESS) + { + initialized = true; + } + + return ret; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_trigger_usb.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_trigger_usb.h new file mode 100644 index 0000000..c7ce4d3 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_trigger_usb.h @@ -0,0 +1,74 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef NRF_DFU_TRIGGER_USB_H +#define NRF_DFU_TRIGGER_USB_H + +#include "sdk_errors.h" + +/** + * @defgroup nrf_dfu_trigger_usb USB DFU trigger library + * @ingroup app_common + * + * @brief @tagAPI52840 USB DFU trigger library is used to enter the bootloader and read the firmware version. + * + * @details See @ref lib_dfu_trigger_usb for additional documentation. + * @{ + */ + +/** + * @brief Function for initializing the USB DFU trigger library. + * + * @note If the USB is also used for other purposes, then this function must be called after USB is + * initialized but before it is enabled. In this case, the configuration flag @ref + * NRF_DFU_TRIGGER_USB_USB_SHARED must be set to 1. + * + * @note Calling this again after the first success has no effect and returns @ref NRF_SUCCESS. + * + * @note If @ref APP_USBD_CONFIG_EVENT_QUEUE_ENABLE is on (1), USB events must be handled manually. + * See @ref app_usbd_event_queue_process. + * + * @retval NRF_SUCCESS On successful initialization. + * @return An error code on failure, for example if called at a wrong time. + */ +ret_code_t nrf_dfu_trigger_usb_init(void); + +/** @} */ + +#endif //NRF_DFU_TRIGGER_USB_H diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_types.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_types.h new file mode 100644 index 0000000..5ccd290 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_types.h @@ -0,0 +1,302 @@ +/** + * 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. + * + */ +/**@file + * + * @defgroup sdk_nrf_dfu_types DFU types + * @{ + * @ingroup nrf_dfu + */ + +#ifndef NRF_DFU_TYPES_H__ +#define NRF_DFU_TYPES_H__ + +#include <stdint.h> +#include <stddef.h> + +#include "nrf.h" +#include "nrf_mbr.h" +#include "app_util_platform.h" +#include "sdk_config.h" + +#if defined(NRF_DFU_TRANSPORT_BLE) && NRF_DFU_TRANSPORT_BLE +#include "ble_gap.h" +#define SYSTEM_SERVICE_ATT_SIZE 8 /**< Size of the system service attribute length including CRC-16 at the end. */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +#define INIT_COMMAND_MAX_SIZE 256 /**< Maximum size of the init command stored in dfu_settings. */ + +/** @brief Size of a flash page. This value is used for calculating the size of the reserved + * flash space in the bootloader region. + */ +#if defined(NRF51) + #define CODE_PAGE_SIZE (PAGE_SIZE_IN_WORDS * sizeof(uint32_t)) +#elif defined(NRF52) || defined(NRF52840_XXAA) + #define CODE_PAGE_SIZE (MBR_PAGE_SIZE_IN_WORDS * sizeof(uint32_t)) +#else + #error "Architecture not set." +#endif + +/** @brief Maximum size of a data object.*/ +#if defined(NRF51) + #define DATA_OBJECT_MAX_SIZE (CODE_PAGE_SIZE * 4) +#elif defined(NRF52_SERIES) || defined (__SDK_DOXYGEN__) + #define DATA_OBJECT_MAX_SIZE (CODE_PAGE_SIZE) +#else + #error "Architecture not set." +#endif + +/** @brief Page location of the bootloader settings address. + */ +#if defined (NRF51) + #define BOOTLOADER_SETTINGS_ADDRESS (0x0003FC00UL) +#elif defined( NRF52810_XXAA ) + #define BOOTLOADER_SETTINGS_ADDRESS (0x0002F000UL) +#elif defined( NRF52832_XXAA ) + #define BOOTLOADER_SETTINGS_ADDRESS (0x0007F000UL) +#elif defined(NRF52840_XXAA) + #define BOOTLOADER_SETTINGS_ADDRESS (0x000FF000UL) +#else + #error No valid target set for BOOTLOADER_SETTINGS_ADDRESS. +#endif + +#define BOOTLOADER_SETTINGS_PAGE_SIZE (CODE_PAGE_SIZE) + +/** + * @brief MBR parameters page in UICR. + * + * Register location in UICR where the page address of the MBR parameters page is stored (only used by the nRF52 MBR). + * + * @note If the value at the given location is 0xFFFFFFFF, no MBR parameters page is set. + */ +#define NRF_UICR_MBR_PARAMS_PAGE_ADDRESS (NRF_UICR_BASE + 0x18) +#define NRF_MBR_PARAMS_PAGE_SIZE (CODE_PAGE_SIZE) + +/** @brief Page location of the MBR parameters page address. + */ +#if defined(NRF52840_XXAA) || defined(NRF52840_XXAA_ENGA) + #define NRF_MBR_PARAMS_PAGE_ADDRESS (0x000FE000UL) +#elif defined(NRF52832_XXAA) + #define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0007E000UL) +#elif defined(NRF52810_XXAA) + #define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0002E000UL) +#endif + +/** @brief Size (in bytes) of the flash area reserved for application data. + * + * The area is found at the end of the application area, next to the start of + * the bootloader. This area will not be erased by the bootloader during a + * firmware upgrade. The default value is 3 pages which matches the size used + * in most SDK examples. + */ +#ifndef DFU_APP_DATA_RESERVED +#define DFU_APP_DATA_RESERVED (CODE_PAGE_SIZE * 3) +#endif + +/** @brief Total size of the region between the SoftDevice and the bootloader. + */ +#define DFU_REGION_END(bootloader_start_addr) ((bootloader_start_addr) - (DFU_APP_DATA_RESERVED)) + +#ifdef BLE_STACK_SUPPORT_REQD +#define DFU_REGION_START (nrf_dfu_bank0_start_addr()) +#else +#define DFU_REGION_START (MBR_SIZE) +#endif + +#define DFU_REGION_TOTAL_SIZE ((DFU_REGION_END) - (DFU_REGION_START)) + +#define NRF_DFU_CURRENT_BANK_0 0x00 +#define NRF_DFU_CURRENT_BANK_1 0x01 + +#define NRF_DFU_BANK_LAYOUT_DUAL 0x00 +#define NRF_DFU_BANK_LAYOUT_SINGLE 0x01 + +/** @brief DFU bank state codes. + * + * @details The DFU bank state indicates the content of a bank: + * A valid image of a certain type or an invalid image. + */ + +#define NRF_DFU_BANK_INVALID 0x00 /**< Invalid image. */ +#define NRF_DFU_BANK_VALID_APP 0x01 /**< Valid application. */ +#define NRF_DFU_BANK_VALID_SD 0xA5 /**< Valid SoftDevice. */ +#define NRF_DFU_BANK_VALID_BL 0xAA /**< Valid bootloader. */ +#define NRF_DFU_BANK_VALID_SD_BL 0xAC /**< Valid SoftDevice and bootloader. */ + +/** @brief Description of a single bank. */ +#pragma pack(4) +typedef struct +{ + uint32_t image_size; /**< Size of the image in the bank. */ + uint32_t image_crc; /**< CRC of the image. If set to 0, the CRC is ignored. */ + uint32_t bank_code; /**< Identifier code for the bank. */ +} nrf_dfu_bank_t; + +/**@brief DFU progress. + * + * Be aware of the difference between objects and firmware images. A firmware image consists of multiple objects, each of a maximum size @ref DATA_OBJECT_MAX_SIZE. + * + * @note The union inside this struct is cleared when CREATE_OBJECT of command type is executed, and when there is a valid post-validation. + * In DFU activation (after reset) the @ref dfu_progress_t::update_start_address will be used in case of a SD/SD+BL update. + */ +ANON_UNIONS_ENABLE; +typedef struct +{ + uint32_t command_size; /**< The size of the current init command stored in the DFU settings. */ + uint32_t command_offset; /**< The offset of the currently received init command data. The offset will increase as the init command is received. */ + uint32_t command_crc; /**< The calculated CRC of the init command (calculated after the transfer is completed). */ + uint32_t data_object_size; /**< The size of the last object created. Note that this size is not the size of the whole firmware image.*/ + union + { + struct + { + uint32_t firmware_image_crc; /**< CRC value of the current firmware (continuously calculated as data is received). */ + uint32_t firmware_image_crc_last; /**< The CRC of the last executed object. */ + uint32_t firmware_image_offset; /**< The offset of the current firmware image being transferred. Note that this offset is the offset in the entire firmware image and not only the current object. */ + uint32_t firmware_image_offset_last;/**< The offset of the last executed object from the start of the firmware image. */ + }; + struct + { + uint32_t update_start_address; /**< Value indicating the start address of the new firmware (before copy). It's always used, but it's most important for an SD/SD+BL update where the SD changes size or if the DFU process had a power loss when updating a SD with changed size. */ + }; + }; +} dfu_progress_t; +ANON_UNIONS_DISABLE; + +/** @brief Event types in the bootloader and DFU process. */ +typedef enum +{ + NRF_DFU_EVT_DFU_INITIALIZED, /**< Starting DFU. */ + NRF_DFU_EVT_TRANSPORT_ACTIVATED, /**< Transport activated (e.g. BLE connected, USB plugged in). */ + NRF_DFU_EVT_TRANSPORT_DEACTIVATED, /**< Transport deactivated (e.g. BLE disconnected, USB plugged out). */ + NRF_DFU_EVT_DFU_STARTED, /**< DFU process started. */ + NRF_DFU_EVT_OBJECT_RECEIVED, /**< A DFU data object has been received. */ + NRF_DFU_EVT_DFU_FAILED, /**< DFU process has failed, been interrupted, or hung. */ + NRF_DFU_EVT_DFU_COMPLETED, /**< DFU process completed. */ + NRF_DFU_EVT_DFU_ABORTED, /**< DFU process aborted. */ +} nrf_dfu_evt_type_t; + +/** + * @brief Function for notifying DFU state. + */ +typedef void (*nrf_dfu_observer_t)(nrf_dfu_evt_type_t notification); + + +#if defined(NRF_DFU_TRANSPORT_BLE) && NRF_DFU_TRANSPORT_BLE + +typedef struct +{ + uint32_t crc; /**< CRC of the rest of the parameters in this struct. */ + ble_gap_id_key_t ble_id; /**< BLE GAP identity key of the device that initiated the DFU process. */ + ble_gap_enc_key_t enc_key; /**< Encryption key structure containing encrypted diversifier and LTK for reestablishing the bond. */ + uint8_t sys_serv_attr[SYSTEM_SERVICE_ATT_SIZE]; /**< System service attributes for restoring of Service Changed Indication setting in DFU mode. */ +} nrf_dfu_peer_data_t; + +typedef enum +{ + DFU_PEER_DATA_STATE_INVALID = 0, + DFU_PEER_DATA_STATE_INITIALIZED = 1, + DFU_PEER_DATA_STATE_WRITE_REQUESTED = 2, + DFU_PEER_DATA_STATE_WRITE_FINISHED = 3, + DFU_PEER_DATA_STATE_WRITE_FAILED = 4, +} nrf_dfu_peer_data_state_t; + +typedef struct +{ + uint32_t crc; /**< CRC of the rest of the parameters in this struct. Calculated by the bootloader. */ + uint8_t name[20]; /**< New advertisement name to set. */ + uint32_t len; /**< Length of the advertisement name. */ +} nrf_dfu_adv_name_t; + +typedef enum +{ + DFU_ADV_NAME_STATE_INVALID = 0, + DFU_ADV_NAME_STATE_INITIALIZED = 1, + DFU_ADV_NAME_STATE_WRITE_REQUESTED = 2, + DFU_ADV_NAME_STATE_WRITE_FINISHED = 3, + DFU_ADV_NAME_STATE_WRITE_FAILED = 4, +} nrf_dfu_set_adv_name_state_t; + +#endif // NRF_DFU_TRANSPORT_BLE + + +/**@brief DFU settings for application and bank data. + */ +typedef struct +{ + uint32_t crc; /**< CRC for the stored DFU settings, not including the CRC itself. If 0xFFFFFFF, the CRC has never been calculated. */ + uint32_t settings_version; /**< Version of the current DFU settings struct layout. */ + uint32_t app_version; /**< Version of the last stored application. */ + uint32_t bootloader_version; /**< Version of the last stored bootloader. */ + + uint32_t bank_layout; /**< Bank layout: single bank or dual bank. This value can change. */ + uint32_t bank_current; /**< The bank that is currently used. */ + + nrf_dfu_bank_t bank_0; /**< Bank 0. */ + nrf_dfu_bank_t bank_1; /**< Bank 1. */ + + uint32_t write_offset; /**< Write offset for the current operation. */ + uint32_t sd_size; /**< Size of the SoftDevice. */ + + dfu_progress_t progress; /**< Current DFU progress. */ + + uint32_t enter_buttonless_dfu; + uint8_t init_command[INIT_COMMAND_MAX_SIZE]; /**< Buffer for storing the init command. */ + +#if defined(NRF_DFU_TRANSPORT_BLE) && NRF_DFU_TRANSPORT_BLE + nrf_dfu_peer_data_t peer_data; /**< Not included in calculated CRC. */ + nrf_dfu_adv_name_t adv_name; /**< Not included in calculated CRC. */ +#endif // NRF_DFU_TRANSPORT_BLE + +} nrf_dfu_settings_t; + +#pragma pack() // revert pack settings + +#ifdef __cplusplus +} +#endif + +#endif // NRF_DFU_TYPES_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_utils.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_utils.c new file mode 100644 index 0000000..286eea6 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_utils.c @@ -0,0 +1,259 @@ +/** + * 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 "nrf_dfu_utils.h" + +#include "nrf_dfu_settings.h" +#include "nrf_bootloader_info.h" +#include "crc32.h" +#include "nrf_log.h" + +void nrf_dfu_bank_invalidate(nrf_dfu_bank_t * const p_bank) +{ + // Set the bank-code to invalid, and reset size/CRC + memset(p_bank, 0, sizeof(nrf_dfu_bank_t)); + + // Reset write pointer after completed operation + s_dfu_settings.write_offset = 0; +} + + +#ifndef BLE_STACK_SUPPORT_REQD +void nrf_dfu_softdevice_invalidate(void) +{ + static const uint32_t all_zero = 0UL; + + if (SD_PRESENT) + { + ret_code_t err_code = nrf_dfu_flash_store(SD_MAGIC_NUMBER_ABS_OFFSET_GET(MBR_SIZE), &all_zero, 4, NULL); + if (err_code != NRF_SUCCESS) + { + NRF_LOG_ERROR("Could not invalidate SoftDevice.") + } + else + { + // If there is an app it must be invalidated since its start address can no longer be resolved. + if (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_VALID_APP) + { + s_dfu_settings.bank_0.bank_code = NRF_DFU_BANK_INVALID; + } + // Since the start of bank 0 has now implicitly been moved to the start + // of the invalidated SoftDevice, its image size must be increased by the + // same amount so the start of bank 1 will be correctly calculated. + s_dfu_settings.bank_0.image_size += SD_SIZE_GET(MBR_SIZE) - MBR_SIZE; + } + } +} +#endif + + +uint32_t nrf_dfu_bank0_start_addr(void) +{ + if (SD_PRESENT) + { + return ALIGN_TO_PAGE(SD_SIZE_GET(MBR_SIZE)); + } + else + { + return MBR_SIZE; + } +} + + +uint32_t nrf_dfu_bank1_start_addr(void) +{ + uint32_t bank0_addr = nrf_dfu_bank0_start_addr(); + return ALIGN_TO_PAGE(bank0_addr + s_dfu_settings.bank_0.image_size); +} + + +uint32_t nrf_dfu_app_start_address(void) +{ + return nrf_dfu_bank0_start_addr(); +} + + +uint32_t nrf_dfu_softdevice_start_address(void) +{ + return MBR_SIZE; +} + + +bool nrf_dfu_app_is_valid(bool do_crc) +{ + NRF_LOG_DEBUG("Enter nrf_dfu_app_is_valid"); + if (s_dfu_settings.bank_0.bank_code != NRF_DFU_BANK_VALID_APP) + { + // Bank 0 has no valid app. Nothing to boot + NRF_LOG_DEBUG("Return false in valid app check"); + return false; + } + + // If CRC == 0, the CRC check is skipped. + if (do_crc && (s_dfu_settings.bank_0.image_crc != 0)) + { + uint32_t crc = crc32_compute((uint8_t*) nrf_dfu_app_start_address(), + s_dfu_settings.bank_0.image_size, + NULL); + + if (crc != s_dfu_settings.bank_0.image_crc) + { + // CRC does not match with what is stored. + NRF_LOG_DEBUG("Return false in CRC"); + return false; + } + } + + NRF_LOG_DEBUG("Return true. App was valid"); + return true; +} + + + +uint32_t nrf_dfu_cache_prepare(const uint32_t required_size, bool single_bank, bool keep_app, bool keep_softdevice) +{ + ret_code_t err_code; + bool cache_too_small; + enum + { + INITIAL_DELETE_APP = 0, + APP_DELETED_DELETE_SOFTDEVICE = 1, + SOFTDEVICE_DELETED = 2 + } pass; + + NRF_LOG_DEBUG("Enter nrf_dfu_cache_prepare()"); + NRF_LOG_DEBUG("required_size: 0x%x.", required_size); + NRF_LOG_DEBUG("single_bank: %s.", single_bank ? "true" : "false"); + NRF_LOG_DEBUG("keep_app: %s.", keep_app ? "true" : "false"); + NRF_LOG_DEBUG("keep_softdevice: %s.", keep_softdevice ? "true" : "false"); + NRF_LOG_DEBUG("SD_PRESENT: %s.", SD_PRESENT ? "true" : "false"); + NRF_LOG_DEBUG("Bank contents:"); + NRF_LOG_DEBUG("Bank 0 code: 0x%02x: Size: 0x%x", s_dfu_settings.bank_0.bank_code, s_dfu_settings.bank_0.image_size); + NRF_LOG_DEBUG("Bank 1 code: 0x%02x: Size: 0x%x", s_dfu_settings.bank_1.bank_code, s_dfu_settings.bank_1.image_size); + + // Pass 0 deletes the app if necessary or requested, and if so, proceeds to pass 1. + // Pass 1 deletes the SoftDevice if necessary or requested, and if so, proceeds to pass 2. + // Pass 2 does a last size check. + for (pass = INITIAL_DELETE_APP; pass <= SOFTDEVICE_DELETED; pass++) + { + uint32_t cache_address; + const uint32_t bootloader_start_addr = BOOTLOADER_START_ADDR; // Assign to a variable to prevent warning in Keil 4. + bool keep_firmware = true; + bool delete_more; + + switch (pass) + { + case INITIAL_DELETE_APP: + cache_address = nrf_dfu_bank1_start_addr(); + + // If there is no app, keep_app should be assumed false, so we can free up more space. + keep_firmware = keep_app && (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_VALID_APP); + break; + + case APP_DELETED_DELETE_SOFTDEVICE: + cache_address = nrf_dfu_bank0_start_addr(); + + // If there is no SoftDevice, keep_SoftDevice should be assumed true, because there is + // no point to continuing since the SoftDevice is the last firmware that can be deleted. + keep_firmware = keep_softdevice || !SD_PRESENT; + break; + + case SOFTDEVICE_DELETED: + cache_address = nrf_dfu_softdevice_start_address(); + break; + + default: + ASSERT(false); + cache_address = 0; + break; + } + + ASSERT(cache_address <= DFU_REGION_END(bootloader_start_addr)); + cache_too_small = required_size > (DFU_REGION_END(bootloader_start_addr) - cache_address); + delete_more = cache_too_small || single_bank; // Delete app or SoftDevice only if we need more room, or if single bank is requested. + + NRF_LOG_DEBUG("pass: %d.", pass); + NRF_LOG_DEBUG("cache_address: 0x%x.", cache_address); + NRF_LOG_DEBUG("cache_too_small: %s.", cache_too_small ? "true" : "false"); + NRF_LOG_DEBUG("keep_firmware: %s.", keep_firmware ? "true" : "false"); + NRF_LOG_DEBUG("delete_more: %s.", delete_more ? "true" : "false"); + + if (!delete_more || keep_firmware || (pass >= SOFTDEVICE_DELETED)) + { + // Stop, done. + break; + } + } + + if (cache_too_small) + { + NRF_LOG_WARNING("Aborting. Cannot fit new firmware on device"); + err_code = NRF_ERROR_NO_MEM; + } + else + { + // Room was found. Make the necessary preparations for receiving update. + +#ifndef BLE_STACK_SUPPORT_REQD + if (pass >= SOFTDEVICE_DELETED) + { + NRF_LOG_DEBUG("Invalidating SoftDevice."); + nrf_dfu_softdevice_invalidate(); + } +#endif + if (pass >= APP_DELETED_DELETE_SOFTDEVICE) + { + NRF_LOG_DEBUG("Invalidating app."); + nrf_dfu_bank_invalidate(&s_dfu_settings.bank_0); + } + + s_dfu_settings.bank_layout = NRF_DFU_BANK_LAYOUT_DUAL; + s_dfu_settings.bank_current = NRF_DFU_CURRENT_BANK_1; + + // Prepare bank for new image. + nrf_dfu_bank_invalidate(&s_dfu_settings.bank_1); + + // Store the Firmware size in the bank for continuations + s_dfu_settings.bank_1.image_size = required_size; + + err_code = NRF_SUCCESS; + } + + return err_code; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_utils.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_utils.h new file mode 100644 index 0000000..6369f92 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_utils.h @@ -0,0 +1,167 @@ +/** + * 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. + * + */ +/**@file + * + * @defgroup sdk_nrf_dfu_utils DFU utilities + * @{ + * @ingroup nrf_dfu + */ + +#ifndef NRF_DFU_UTILS_H__ +#define NRF_DFU_UTILS_H__ + +#include <stdint.h> +#include <stdbool.h> +#include "nrf_dfu_types.h" +#include "app_util.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/** + * Round up val to the next page boundary + */ +#define ALIGN_TO_PAGE(val) ALIGN_NUM((CODE_PAGE_SIZE), (val)) + + +/** @brief Function for getting the start address of bank 0. + * + * @note Bank 0 starts after the SoftDevice if a SoftDevice is present. + * + * @return The start address of bank 0. + */ +uint32_t nrf_dfu_bank0_start_addr(void); + + +/** @brief Function for getting the start address of bank 1. + * + * @return The start address of bank 1. + */ +uint32_t nrf_dfu_bank1_start_addr(void); + + +/** @brief Function for getting the start address of the app. + * + * @return The start address of the bootable app. + */ +uint32_t nrf_dfu_app_start_address(void); + + +/** @brief Function for getting the start address of the SoftDevice. + * + * @return The start address of the SoftDevivce. + */ +uint32_t nrf_dfu_softdevice_start_address(void); + + +/** @brief Function for checking if the main application is valid. + * + * @details This function checks if there is a valid application + * located at Bank 0. + * + * @param[in] do_crc Perform CRC check on application. + * + * @retval true If a valid application has been detected. + * @retval false If there is no valid application. + */ +bool nrf_dfu_app_is_valid(bool do_crc); + + +/** @brief Function for finding and preparing a place in flash in which to store a DFU update. + * + * @details This function checks the size requirements and selects a location for + * placing the cache of the DFU images. + * The function tries to find enough space after the existing firmwares. If there is not + * enough space, the present application is deleted. If there is still not enough space, + * the SoftDevice is deleted. + * If @p single_bank is true, the default behavior is to immediately delete the app and + * SoftDevice as necessary to place the new firmware at its intended location. If the + * intended location cannot be made available, or if the update is a bootloader update, + * the update will be a dual bank update, and nothing will be deleted by this function + * except when needed for size. + * If @p keep_app is true, the app is never deleted by this function. Likewise if @p + * keep_softdevice is true, the SoftDevice is never deleted by this function. + * If the new firmware cannot fit within the constraints, nothing is deleted and the + * function fails. + * + * @param[in] required_size Requirements for the size of the new image. + * @param[in] single_bank Whether to put the firmware directly where it's meant to go. + * @p keep_app and @p keep_softdevice take precedence over this. + * @param[in] keep_app True to ensure the app is not deleted by this function. This + * effectively enforces dual bank update. + * @param[out] keep_softdevice True to ensure the SoftDevice is not deleted by this function. + * + * @retval NRF_SUCCESS If a cache location was found for the DFU process. + * @retval NRF_ERROR_NO_MEM If there is not enough space available to receive the update. + * Nothing has been deleted. + */ +uint32_t nrf_dfu_cache_prepare(uint32_t required_size, bool single_bank, bool keep_app, bool keep_softdevice); + + +/**@brief Function for making sure a SoftDevice is not recognized as such anymore. + * + * @details It works by overwriting the magic number of the SoftDevice with 0s. The + * magic number is used throughout the bootloader to detect whether a SoftDevice + * is present. + * + * @warning This function should only be called when both banks are already invalid. + * because the (implicit) position of the banks will shift when the SoftDevice + * is invalidated. + */ +void nrf_dfu_softdevice_invalidate(void); + + +/**@brief Function for making sure a bank is not copied or booted. + * + * @details This also sets the size of the bank to 0. + * + * @param[in] p_bank Pointer to the bank to be invalidated. + */ +void nrf_dfu_bank_invalidate(nrf_dfu_bank_t * const p_bank); + +#ifdef __cplusplus +} +#endif + +#endif // NRF_DFU_UTILS_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_validation.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_validation.c new file mode 100644 index 0000000..566702d --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_validation.c @@ -0,0 +1,745 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <stdbool.h> +#include "nrf_dfu_types.h" +#include "nrf_dfu_settings.h" +#include "nrf_dfu_utils.h" +#include "nrf_dfu_flash.h" +#include "nrf_bootloader_info.h" +#include "pb.h" +#include "pb_common.h" +#include "pb_decode.h" +#include "dfu-cc.pb.h" +#include "crc32.h" +#include "nrf_crypto.h" +#include "nrf_assert.h" +#include "nrf_dfu_validation.h" +#include "nrf_dfu_ver_validation.h" + +#define NRF_LOG_MODULE_NAME nrf_dfu_validation +#include "nrf_log.h" +#include "nrf_log_ctrl.h" +NRF_LOG_MODULE_REGISTER(); + + +#ifndef NRF_DFU_DEBUG +#ifdef NRF_DFU_DEBUG_VERSION +#define NRF_DFU_DEBUG 1 +#else +#define NRF_DFU_DEBUG 0 +#endif +#endif + +#ifndef DFU_REQUIRES_SOFTDEVICE +#ifndef BLE_STACK_SUPPORT_REQD +#define DFU_REQUIRES_SOFTDEVICE 0 +#else +#define DFU_REQUIRES_SOFTDEVICE 1 +#endif +#endif + +#define EXT_ERR(err) (nrf_dfu_result_t)((uint32_t)NRF_DFU_RES_CODE_EXT_ERROR + (uint32_t)err) + +/* Whether a complete init command has been received and prevalidated, but the firmware + * is not yet fully transferred. This value will also be correct after reset. + */ +static bool m_valid_init_cmd_present = false; +static dfu_packet_t m_packet = DFU_PACKET_INIT_DEFAULT; +static uint8_t* m_init_packet_data_ptr = 0; +static uint32_t m_init_packet_data_len = 0; +static pb_istream_t m_pb_stream; + +static nrf_crypto_ecdsa_verify_context_t m_verify_context = {0}; + +static nrf_crypto_hash_context_t m_hash_context = {0}; + + +__ALIGN(4) extern const uint8_t pk[64]; + +/** @brief Value length structure holding the public key. + * + * @details The pk value pointed to is the public key present in dfu_public_key.c + */ +static nrf_crypto_ecc_public_key_t m_public_key; + +/** @brief Structure to hold a signature + */ +static nrf_crypto_ecdsa_secp256r1_signature_t m_signature; + +/** @brief Structure to hold the hash for the init packet + */ +static nrf_crypto_hash_sha256_digest_t m_init_packet_hash; + +/** @brief Structure to hold the hash for the firmware image + */ +static nrf_crypto_hash_sha256_digest_t m_fw_hash; + + +static void pb_decoding_callback(pb_istream_t *str, uint32_t tag, pb_wire_type_t wire_type, void *iter) +{ + pb_field_iter_t* p_iter = (pb_field_iter_t *) iter; + + // match the beginning of the init command + if (p_iter->pos->ptr == &dfu_init_command_fields[0]) + { + uint8_t * ptr = (uint8_t *)str->state; + uint32_t size = str->bytes_left; + + // remove tag byte + ptr++; + size--; + + // store the info in init_packet_data + m_init_packet_data_ptr = ptr; + m_init_packet_data_len = size; + + NRF_LOG_DEBUG("PB: Init packet data len: %d", size); + } +} + +/** @brief Function for decoding byte stream into variable. + * + * @retval true If the stored init command was successfully decoded. + * @retval false If there was no stored init command, or the decoding failed. + */ +static bool stored_init_cmd_decode(void) +{ + m_pb_stream = pb_istream_from_buffer(s_dfu_settings.init_command, + s_dfu_settings.progress.command_size); + + // Attach our callback to follow the field decoding + m_pb_stream.decoding_callback = pb_decoding_callback; + + m_init_packet_data_ptr = NULL; + m_init_packet_data_len = 0; + + if (!pb_decode(&m_pb_stream, dfu_packet_fields, &m_packet)) + { + NRF_LOG_ERROR("Handler: Invalid protocol buffer m_pb_stream"); + return false; + } + + return true; +} + + +void nrf_dfu_validation_init(void) +{ + ret_code_t err_code; + + // If the command is stored to flash, init command was valid. + if ( (s_dfu_settings.progress.command_size != 0) + && stored_init_cmd_decode() + && (s_dfu_settings.bank_1.image_size != 0)) + { + m_valid_init_cmd_present = true; + } + else + { + m_valid_init_cmd_present = false; + } + + err_code = nrf_crypto_init(); + ASSERT(err_code == NRF_SUCCESS); + UNUSED_PARAMETER(err_code); + + + err_code = nrf_crypto_ecc_public_key_from_raw(&g_nrf_crypto_ecc_secp256r1_curve_info, + &m_public_key, + pk, + sizeof(pk)); + ASSERT(err_code == NRF_SUCCESS); + UNUSED_PARAMETER(err_code); +} + + +nrf_dfu_result_t nrf_dfu_validation_init_cmd_create(uint32_t size) +{ + nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS; + if (size == 0) + { + ret_val = NRF_DFU_RES_CODE_INVALID_PARAMETER; + } + else if (size > INIT_COMMAND_MAX_SIZE) + { + ret_val = NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES; + } + else + { + // Set DFU to uninitialized. + m_valid_init_cmd_present = false; + + // Reset all progress. + s_dfu_settings.write_offset = 0; + memset(&s_dfu_settings.progress, 0x00, sizeof(dfu_progress_t)); + + // Set the init command size. + s_dfu_settings.progress.command_size = size; + } + return ret_val; +} + + +nrf_dfu_result_t nrf_dfu_validation_init_cmd_append(uint8_t const * p_data, uint32_t length) +{ + nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS; + if ((length + s_dfu_settings.progress.command_offset) > s_dfu_settings.progress.command_size) + { + NRF_LOG_ERROR("Init command larger than expected."); + ret_val = NRF_DFU_RES_CODE_INVALID_PARAMETER; + } + else + { + // Copy the received data to RAM, update offset and calculate CRC. + memcpy(&s_dfu_settings.init_command[s_dfu_settings.progress.command_offset], + p_data, + length); + + s_dfu_settings.progress.command_offset += length; + s_dfu_settings.progress.command_crc = crc32_compute(p_data, + length, + &s_dfu_settings.progress.command_crc); + } + return ret_val; +} + + +void nrf_dfu_validation_init_cmd_status_get(uint32_t * p_offset, + uint32_t * p_crc, + uint32_t * p_max_size) +{ + *p_offset = s_dfu_settings.progress.command_offset; + *p_crc = s_dfu_settings.progress.command_crc; + *p_max_size = INIT_COMMAND_MAX_SIZE; +} + + +bool nrf_dfu_validation_init_cmd_present(void) +{ + return m_valid_init_cmd_present; +} + + +// Function determines if init command signature is obligatory +static bool signature_required(dfu_fw_type_t fw_type_to_be_updated) +{ + bool result = true; + + if ((!DFU_REQUIRES_SOFTDEVICE && (fw_type_to_be_updated == DFU_FW_TYPE_SOFTDEVICE)) || + (fw_type_to_be_updated == DFU_FW_TYPE_APPLICATION)) + { + result = NRF_DFU_REQUIRE_SIGNED_APP_UPDATE; + } + return result; +} + + +// Function to perform signature check if required. +static nrf_dfu_result_t signature_check(dfu_fw_type_t fw_type, + dfu_signature_type_t signature_type, + dfu_signed_command_signature_t const * p_signature) +{ + ret_code_t err_code; + size_t hash_len = NRF_CRYPTO_HASH_SIZE_SHA256; + + if (!signature_required(fw_type)) + { + return NRF_DFU_RES_CODE_SUCCESS; + } + + NRF_LOG_INFO("Signature required. Checking signature.") + if (p_signature == NULL) + { + NRF_LOG_WARNING("No signature found."); + return EXT_ERR(NRF_DFU_EXT_ERROR_SIGNATURE_MISSING); + } + + if (signature_type != DFU_SIGNATURE_TYPE_ECDSA_P256_SHA256) + { + NRF_LOG_INFO("Invalid signature type"); + return EXT_ERR(NRF_DFU_EXT_ERROR_WRONG_SIGNATURE_TYPE); + } + + NRF_LOG_INFO("Calculating init packet hash (init packet len: %d)", m_init_packet_data_len); + err_code = nrf_crypto_hash_calculate(&m_hash_context, + &g_nrf_crypto_hash_sha256_info, + m_init_packet_data_ptr, + m_init_packet_data_len, + m_init_packet_hash, + &hash_len); + if (err_code != NRF_SUCCESS) + { + return NRF_DFU_RES_CODE_OPERATION_FAILED; + } + + if (sizeof(m_signature) != p_signature->size) + { + return NRF_DFU_RES_CODE_OPERATION_FAILED; + } + + // Prepare the signature received over the air. + memcpy(m_signature, p_signature->bytes, p_signature->size); + + // calculate the signature + NRF_LOG_INFO("Verify signature"); + err_code = nrf_crypto_ecdsa_verify(&m_verify_context, + &m_public_key, + m_init_packet_hash, + hash_len, + m_signature, + sizeof(m_signature)); + if (err_code != NRF_SUCCESS) + { + NRF_LOG_ERROR("Signature failed (err_code: 0x%x)", err_code); + NRF_LOG_DEBUG("Signature:"); + NRF_LOG_HEXDUMP_DEBUG(m_signature, sizeof(m_signature)); + NRF_LOG_DEBUG("Hash:"); + NRF_LOG_HEXDUMP_DEBUG(m_init_packet_hash, hash_len); + NRF_LOG_DEBUG("Public Key:"); + NRF_LOG_HEXDUMP_DEBUG(pk, sizeof(pk)); + NRF_LOG_FLUSH(); + + return NRF_DFU_RES_CODE_INVALID_OBJECT; + } + + NRF_LOG_INFO("Image verified"); + return NRF_DFU_RES_CODE_SUCCESS; +} + + +// Function to calculate the total size of the firmware(s) in the update. +static nrf_dfu_result_t update_data_size_get(dfu_init_command_t const * p_init, uint32_t * p_size) +{ + nrf_dfu_result_t ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID); + uint32_t fw_sz = 0; + + if ((p_init->type == DFU_FW_TYPE_APPLICATION) && (p_init->has_app_size == true)) + { + fw_sz = p_init->app_size; + } + else + { + if ((p_init->type & DFU_FW_TYPE_SOFTDEVICE) && (p_init->has_sd_size == true)) + { + fw_sz = p_init->sd_size; + } + + if ((p_init->type & DFU_FW_TYPE_BOOTLOADER) && (p_init->has_bl_size == true)) + { + if (p_init->bl_size <= BOOTLOADER_SIZE) + { + fw_sz += p_init->bl_size; + } + else + { + NRF_LOG_ERROR("BL size (%d) over limit (%d)", p_init->bl_size, BOOTLOADER_SIZE); + fw_sz = 0; + ret_val = NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES; + } + } + } + + if (fw_sz) + { + *p_size = fw_sz; + ret_val = NRF_DFU_RES_CODE_SUCCESS; + } + else + { + NRF_LOG_ERROR("Init packet does not contain valid firmware size"); + } + + return ret_val; +} + + +/** + * @brief Function to check if single bank update should be used. + * + * @param new_fw_type Firmware type. + */ +static bool use_single_bank(dfu_fw_type_t new_fw_type) +{ + bool result = false; + + if (((new_fw_type == DFU_FW_TYPE_APPLICATION) || (new_fw_type == DFU_FW_TYPE_SOFTDEVICE)) && + NRF_DFU_SINGLE_BANK_APP_UPDATES) + { + result = true; + } + + return result; +} + + +// Function to determine if the new firmware needs a SoftDevice to be present. +static bool update_requires_softdevice(dfu_init_command_t const * p_init) +{ + return ((p_init->sd_req_count > 0) && (p_init->sd_req[0] != SD_REQ_APP_OVERWRITES_SD)); +} + + +// Function to determine if the SoftDevice can be removed during the update or not. +static bool keep_softdevice(dfu_init_command_t const * p_init) +{ + UNUSED_PARAMETER(p_init); // It's unused when DFU_REQUIRES_SOFTDEVICE is true. + return DFU_REQUIRES_SOFTDEVICE || update_requires_softdevice(p_init); +} + + +/**@brief Function to determine where to temporarily store the incoming firmware. + * This also checks whether the update will fit, and deletes existing + * firmware to make room for the new firmware. + * + * @param[in] p_init Init command. + * @param[in] fw_size The size of the incoming firmware. + * @param[out] p_addr The address at which to initially store the firmware. + * + * @retval NRF_DFU_RES_CODE_SUCCESS If the size check passed and + * an address was found. + * @retval NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES If the size check failed. + */ +static nrf_dfu_result_t update_data_addr_get(dfu_init_command_t const * p_init, + uint32_t fw_size, + uint32_t * p_addr) +{ + nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS; + ret_code_t err_code = nrf_dfu_cache_prepare(fw_size, + use_single_bank(p_init->type), + NRF_DFU_FORCE_DUAL_BANK_APP_UPDATES, + keep_softdevice(p_init)); + if (err_code != NRF_SUCCESS) + { + NRF_LOG_ERROR("Can't find room for update"); + ret_val = NRF_DFU_RES_CODE_INSUFFICIENT_RESOURCES; + } + else + { + *p_addr = nrf_dfu_bank1_start_addr(); + NRF_LOG_DEBUG("Write address set to 0x%08x", *p_addr); + } + return ret_val; +} + + +nrf_dfu_result_t nrf_dfu_validation_init_cmd_execute(uint32_t * p_dst_data_addr, + uint32_t * p_data_len) +{ + nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS; + + if (s_dfu_settings.progress.command_offset != s_dfu_settings.progress.command_size) + { + // The object wasn't the right (requested) size + NRF_LOG_ERROR("Execute with faulty offset"); + ret_val = NRF_DFU_RES_CODE_OPERATION_NOT_PERMITTED; + } + else if (m_valid_init_cmd_present) + { + *p_dst_data_addr = nrf_dfu_bank1_start_addr(); + *p_data_len = s_dfu_settings.bank_1.image_size; + ret_val = NRF_DFU_RES_CODE_SUCCESS; + } + else if (stored_init_cmd_decode() && + (m_packet.has_signed_command || m_packet.has_command)) + { + dfu_command_t const * p_command = &m_packet.command; + dfu_signature_type_t signature_type = (dfu_signature_type_t) 0; // Placeholder. + dfu_signed_command_signature_t * p_signature = NULL; + + *p_dst_data_addr = 0; + *p_data_len = 0; + + if (m_packet.has_signed_command) + { + p_command = &m_packet.signed_command.command; + signature_type = m_packet.signed_command.signature_type; + p_signature = &m_packet.signed_command.signature; + } + + // Validate signature. + ret_val = signature_check(p_command->init.type, signature_type, p_signature); + + // Validate versions + if (ret_val == NRF_DFU_RES_CODE_SUCCESS) + { + ret_val = nrf_dfu_ver_validation_check(&p_command->init); + if (ret_val == NRF_DFU_RES_CODE_SUCCESS) + { + m_valid_init_cmd_present = true; + } + } + + // Get size of binary + if (ret_val == NRF_DFU_RES_CODE_SUCCESS) + { + ret_val = update_data_size_get(&p_command->init, p_data_len); + } + + //Get address where to flash the binary + if (ret_val == NRF_DFU_RES_CODE_SUCCESS) + { + ret_val = update_data_addr_get(&p_command->init, *p_data_len, p_dst_data_addr); + } + } + else + { + NRF_LOG_ERROR("Failed to decode init packet"); + ret_val = NRF_DFU_RES_CODE_INVALID_OBJECT; + } + + return ret_val; +} + + +// Function to check the hash received in the init command against the received firmware. +static bool fw_hash_ok(dfu_init_command_t const * p_init, uint32_t fw_start_addr, uint32_t fw_size) +{ + ret_code_t err_code; + bool result = true; + size_t hash_len = NRF_CRYPTO_HASH_SIZE_SHA256; + + ASSERT(p_init != NULL); + + NRF_LOG_DEBUG("Hash verification. Firmware start address: 0x%x, size: 0x%x", fw_start_addr, fw_size); + err_code = nrf_crypto_hash_calculate(&m_hash_context, + &g_nrf_crypto_hash_sha256_info, + (uint8_t*)fw_start_addr, + fw_size, + m_fw_hash, + &hash_len); + + if (err_code != NRF_SUCCESS) + { + NRF_LOG_ERROR("Could not run hash verification (err_code 0x%x).", err_code); + result = false; + } + else if (memcmp(m_fw_hash, p_init->hash.hash.bytes, NRF_CRYPTO_HASH_SIZE_SHA256) != 0) + { + NRF_LOG_WARNING("Hash verification failed."); + NRF_LOG_DEBUG("Expected FW hash:") + NRF_LOG_HEXDUMP_DEBUG(p_init->hash.hash.bytes, NRF_CRYPTO_HASH_SIZE_SHA256); + NRF_LOG_DEBUG("Actual FW hash:") + NRF_LOG_HEXDUMP_DEBUG(m_fw_hash, NRF_CRYPTO_HASH_SIZE_SHA256); + NRF_LOG_FLUSH(); + + result = false; + } + + return result; +} + + +// Function to check if the update contains a SoftDevice and, if so, if it is of a different +// major version than the existing SoftDevice. +static bool is_major_softdevice_update(uint32_t new_sd_addr) +{ + // True if there is no SD right now, but there is a new one coming. This counts as a major update. + bool result = !SD_PRESENT && (SD_MAGIC_NUMBER_GET(new_sd_addr) == SD_MAGIC_NUMBER); + + if (SD_PRESENT && (SD_MAGIC_NUMBER_GET(new_sd_addr) == SD_MAGIC_NUMBER)) + { + // Both SoftDevices are present. + uint32_t current_SD_major = SD_MAJOR_VERSION_EXTRACT(SD_VERSION_GET(MBR_SIZE)); + uint32_t new_SD_major = SD_MAJOR_VERSION_EXTRACT(SD_VERSION_GET(new_sd_addr)); + + result = (current_SD_major != new_SD_major); + + NRF_LOG_INFO("SoftDevice update is a %s version update. Current: %d. New: %d.", + result ? "major" : "minor", + current_SD_major, + new_SD_major); + } + + return result; +} + + +/**@brief Validate the SoftDevice size and magic number in structure found at 0x2000 in received SoftDevice. + * + * @param[in] sd_start_addr Start address of received SoftDevice. + * @param[in] sd_size Size of received SoftDevice in bytes. + */ +static bool softdevice_info_ok(uint32_t sd_start_addr, uint32_t sd_size) +{ + bool result = true; + + if (SD_MAGIC_NUMBER_GET(sd_start_addr) != SD_MAGIC_NUMBER) + { + NRF_LOG_ERROR("The SoftDevice does not contain the magic number identifying it as a SoftDevice."); + result = false; + } + else if (SD_SIZE_GET(sd_start_addr) < ALIGN_TO_PAGE(sd_size + MBR_SIZE)) + { + // The size in the info struct should be rounded up to a page boundary + // and be larger than the actual size + the size of the MBR. + NRF_LOG_ERROR("The SoftDevice size in the info struct is too small compared with the size reported in the init command."); + result = false; + } + + return result; +} + + +static void postvalidate_app(dfu_init_command_t * p_init) +{ + s_dfu_settings.bank_1.bank_code = NRF_DFU_BANK_VALID_APP; + + NRF_LOG_DEBUG("Invalidating old application in bank 0."); + s_dfu_settings.bank_0.bank_code = NRF_DFU_BANK_INVALID; + + if (!DFU_REQUIRES_SOFTDEVICE && !update_requires_softdevice(p_init)) + { + // App does not need SD, so it should be placed where SD is. + nrf_dfu_softdevice_invalidate(); + } + + if (!NRF_DFU_DEBUG || + (NRF_DFU_DEBUG && (p_init->has_is_debug == false || p_init->is_debug == false))) + { + s_dfu_settings.app_version = p_init->fw_version; + } +} + + +// Function to check a received SoftDevice and/or Bootloader firmware +// before it is copied into place. +static bool postvalidate_sd_bl(dfu_init_command_t * p_init, + bool with_sd, + bool with_bl, + uint32_t start_addr) +{ + if (with_sd) + { + if (!softdevice_info_ok(start_addr, p_init->sd_size)) + { + return false; + } + + if (is_major_softdevice_update(start_addr)) + { + NRF_LOG_WARNING("Invalidating app because it is incompatible with the SoftDevice."); + if (DFU_REQUIRES_SOFTDEVICE && !with_bl) + { + NRF_LOG_ERROR("Major SD update but no BL. Abort to avoid incapacitating the BL."); + return false; + } + + // Invalidate app since it may not be compatible with new SD. + nrf_dfu_bank_invalidate(&s_dfu_settings.bank_0); + } + + // Mark the update as valid. + s_dfu_settings.bank_1.bank_code = with_bl ? NRF_DFU_BANK_VALID_SD_BL + : NRF_DFU_BANK_VALID_SD; + + s_dfu_settings.sd_size = p_init->sd_size; + } + else + { + s_dfu_settings.bank_1.bank_code = NRF_DFU_BANK_VALID_BL; + } + + + if (with_bl && + (!NRF_DFU_DEBUG || + (NRF_DFU_DEBUG && (p_init->has_is_debug == false || p_init->is_debug == false)))) + { + // If the update contains a bootloader, update the version. + // Unless the update is a debug packet. + s_dfu_settings.bootloader_version = p_init->fw_version; + } + + return true; +} + + +nrf_dfu_result_t nrf_dfu_validation_post_data_execute(uint32_t src_addr, uint32_t data_len) +{ + nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS; + dfu_init_command_t * p_init = m_packet.has_signed_command ? &m_packet.signed_command.command.init + : &m_packet.command.init; + + if (!fw_hash_ok(p_init, src_addr, data_len)) + { + ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_VERIFICATION_FAILED); + } + else + { + if (p_init->type == DFU_FW_TYPE_APPLICATION) + { + postvalidate_app(p_init); + } + else + { + bool with_sd = p_init->type & DFU_FW_TYPE_SOFTDEVICE; + bool with_bl = p_init->type & DFU_FW_TYPE_BOOTLOADER; + + if (!postvalidate_sd_bl(p_init, with_sd, with_bl, src_addr)) + { + ret_val = NRF_DFU_RES_CODE_INVALID_OBJECT; + if (with_sd && !DFU_REQUIRES_SOFTDEVICE && + (src_addr == nrf_dfu_softdevice_start_address())) + { + nrf_dfu_softdevice_invalidate(); + } + } + } + } + + if (ret_val == NRF_DFU_RES_CODE_SUCCESS) + { + // Store CRC32 for image + s_dfu_settings.bank_1.image_crc = s_dfu_settings.progress.firmware_image_crc; + s_dfu_settings.bank_1.image_size = data_len; + } + else + { + nrf_dfu_bank_invalidate(&s_dfu_settings.bank_1); + } + + // Set the progress to zero and remove the last command + memset(&s_dfu_settings.progress, 0, sizeof(dfu_progress_t)); + memset(s_dfu_settings.init_command, 0xFF, DFU_SIGNED_COMMAND_SIZE); + + s_dfu_settings.write_offset = 0; + s_dfu_settings.progress.update_start_address = src_addr; + + return ret_val; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_validation.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_validation.h new file mode 100644 index 0000000..d0de004 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_validation.h @@ -0,0 +1,127 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/**@file + * + * @defgroup sdk_nrf_dfu_validation Validation + * @{ + * @ingroup nrf_dfu + */ + +#ifndef __NRF_DFU_VALIDATION_H +#define __NRF_DFU_VALIDATION_H + +#include "stdint.h" +#include "sdk_errors.h" +#include "nrf_dfu_handling_error.h" + +/** + * @brief Function for module initialization. + * + * Function checks if there is a valid init packet in DFU settings written in flash. + */ +void nrf_dfu_validation_init(void); + +/** + * @brief Function called on reception of init command creation request. + * + * @param[in] size Size of incoming init packet. + * + * @return Operation result. See @ref nrf_dfu_result_t + */ +nrf_dfu_result_t nrf_dfu_validation_init_cmd_create(uint32_t size); + +/** + * @brief Function called on reception of fragment of init command. + * + * @param[in] p_data Init command fragment. + * @param[in] length Init command fragment size. + * + * @return Operation result. See @ref nrf_dfu_result_t + */ +nrf_dfu_result_t nrf_dfu_validation_init_cmd_append(uint8_t const * p_data, uint32_t length); + +/** + * @brief Function for getting init command status. + * + * @param[out] p_offset Current offset. + * @param[out] p_crc Current CRC. + * @param[out] p_max_size Maximum size of init command. + */ +void nrf_dfu_validation_init_cmd_status_get(uint32_t * p_offset, + uint32_t * p_crc, + uint32_t * p_max_size); + +/** + * @brief Function for inquiring whether a valid init command has been received. + * + * @return true if there is a valid init command. This can be true at boot time + * if the device was reset during a DFU operation. + */ +bool nrf_dfu_validation_init_cmd_present(void); + +/** + * @brief Function for validating init command. + * + * If init command is successfully validated Bank 1 details are written to out parameters. + * + * Until @ref nrf_dfu_validation_init_cmd_create is called, this function can be called + * again after the first time without side effects to retrieve address and length. + * + * @param[out] p_dst_data_addr Bank 1 start address if validation is successful. + * @param[out] p_data_len Bank 1 length if validation is successful. + * + * @return Operation result. See @ref nrf_dfu_result_t + */ +nrf_dfu_result_t nrf_dfu_validation_init_cmd_execute(uint32_t * p_dst_data_addr, + uint32_t * p_data_len); + +/** + * @brief Function for postvalidating the update. Function is called once all data is received. + * + * @param[in] dst_data_addr Bank 1 start address. + * @param[in] data_len Bank 1 length. + * + * @return Operation result. See @ref nrf_dfu_result_t + */ +nrf_dfu_result_t nrf_dfu_validation_post_data_execute(uint32_t dst_data_addr, uint32_t data_len); + +#endif //__NRF_DFU_VALIDATION_H + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_ver_validation.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_ver_validation.c new file mode 100644 index 0000000..4958dd3 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_ver_validation.c @@ -0,0 +1,241 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include <stdbool.h> +#include "nrf_dfu_types.h" +#include "nrf_dfu_settings.h" +#include "nrf_dfu_utils.h" +#include "nrf_bootloader_info.h" +#include "nrf_crypto.h" +#include "nrf_assert.h" +#include "dfu-cc.pb.h" +#include "nrf_dfu_ver_validation.h" + +#define NRF_LOG_MODULE_NAME nrf_dfu_ver_validation +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + + +#ifndef NRF_DFU_DEBUG +#ifdef NRF_DFU_DEBUG_VERSION +#define NRF_DFU_DEBUG 1 +#else +#define NRF_DFU_DEBUG 0 +#endif +#endif + +/** @brief Macro for reading the Firmware ID of a SoftDevice at a given base address. + */ +#ifndef _SD_FWID_GET +#define _SD_FWID_GET(baseaddr) SD_OFFSET_GET_UINT16(baseaddr, 0x0C) +#endif + +#define EXT_ERR(err) (nrf_dfu_result_t)((uint32_t)NRF_DFU_RES_CODE_EXT_ERROR + (uint32_t)err) + +static bool sd_req_check(uint32_t const * p_sd_req, uint8_t sd_req_cnt) +{ + bool result = false; + for (uint8_t i = 0; i < sd_req_cnt; i++) + { + if (p_sd_req[i] == _SD_FWID_GET(MBR_SIZE)) + { + // Found a matching sd_req field. sd_req is ok. + result = true; + break; + } + } + return result; +} + +static bool sd_req_ok(dfu_init_command_t const * p_init) +{ + ASSERT(p_init != NULL); + bool result; +#ifdef BLE_STACK_SUPPORT_REQD + // The bootloader needs the SoftDevice, so disabling NRF_DFU_APP_DOWNGRADE_PREVENTION + // should not be applied to SoftDevice updates. + const bool prevent_downgrade = NRF_DFU_APP_DOWNGRADE_PREVENTION || (p_init->type == DFU_FW_TYPE_SOFTDEVICE); +#else + const bool prevent_downgrade = NRF_DFU_APP_DOWNGRADE_PREVENTION; +#endif + + if (SD_PRESENT) + { + if (p_init->sd_req_count && (p_init->sd_req[0] != SD_REQ_APP_OVERWRITES_SD)) + { + result = sd_req_check(p_init->sd_req, p_init->sd_req_count); + } + else if (p_init->type == DFU_FW_TYPE_APPLICATION) + { + // The application wants to overwrite the SoftDevice. + if (prevent_downgrade && (p_init->sd_req_count > 1) && (p_init->sd_req[0] == SD_REQ_APP_OVERWRITES_SD)) + { + // The application can overwrite the SD if sd_req[0] == 0 and table has the fwid of the current SD. + result = sd_req_check(p_init->sd_req, p_init->sd_req_count); + } + else + { + result = true; + } + } + else + { + // Don't allow SoftDevice updates which assume no SD is present already. + result = !prevent_downgrade || (p_init->type != DFU_FW_TYPE_SOFTDEVICE); + } + } + else + { + if (p_init->sd_req_count && (p_init->sd_req[0] != SD_REQ_APP_OVERWRITES_SD)) + { + // Fail if there is no SD and the update requires SD. + result = false; + } + else + { + // If there is no SD and update has SD it is accepted only if it has a fw_version. + result = !prevent_downgrade || p_init->has_fw_version; + } + } + return result; +} + +static bool fw_hash_type_ok(dfu_init_command_t const * p_init) +{ + ASSERT(p_init != NULL); + + return (p_init->hash.hash_type == DFU_HASH_TYPE_SHA256); +} + +static bool fw_version_required(dfu_fw_type_t new_fw_type) +{ + bool result = true; + + if (new_fw_type == DFU_FW_TYPE_SOFTDEVICE) + { + result = false; // fw_version is optional in SoftDevice updates. If present, it will be checked against the app version. + } + else if (new_fw_type == DFU_FW_TYPE_APPLICATION) + { + result = NRF_DFU_APP_DOWNGRADE_PREVENTION; // fw_version is configurable in app updates. + } + + return result; +} + + +static bool fw_type_ok(dfu_init_command_t const * p_init) +{ + ASSERT(p_init != NULL); + + return ((p_init->has_type) + && ( (p_init->type == DFU_FW_TYPE_APPLICATION) + || (p_init->type == DFU_FW_TYPE_SOFTDEVICE) + || (p_init->type == DFU_FW_TYPE_BOOTLOADER) + || (p_init->type == DFU_FW_TYPE_SOFTDEVICE_BOOTLOADER))); +} + + +// This function assumes p_init->has_fw_version. +static bool fw_version_ok(dfu_init_command_t const * p_init) +{ + ASSERT(p_init != NULL); + ASSERT(p_init->has_fw_version); + + if ( (p_init->type == DFU_FW_TYPE_APPLICATION) + || (p_init->type == DFU_FW_TYPE_SOFTDEVICE)) + { + return ((p_init->fw_version >= s_dfu_settings.app_version) || !NRF_DFU_APP_DOWNGRADE_PREVENTION); + } + else + { + return (p_init->fw_version > s_dfu_settings.bootloader_version); + } +} + +nrf_dfu_result_t nrf_dfu_ver_validation_check(dfu_init_command_t const * p_init) +{ + nrf_dfu_result_t ret_val = NRF_DFU_RES_CODE_SUCCESS; + if (!fw_type_ok(p_init)) + { + NRF_LOG_ERROR("Invalid firmware type."); + ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID); + } + else if (!fw_hash_type_ok(p_init)) + { + NRF_LOG_ERROR("Invalid hash type."); + ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_WRONG_HASH_TYPE); + } + else if (!NRF_DFU_DEBUG || + (NRF_DFU_DEBUG && ((p_init->has_is_debug == false) || (p_init->is_debug == false)))) + { + if (p_init->has_hw_version == false) + { + NRF_LOG_ERROR("No HW version."); + ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID); + } + else if (p_init->hw_version != NRF_DFU_HW_VERSION) + { + NRF_LOG_WARNING("Faulty HW version."); + ret_val = EXT_ERR( NRF_DFU_EXT_ERROR_HW_VERSION_FAILURE); + } + else if (!sd_req_ok(p_init)) + { + NRF_LOG_WARNING("SD req not met."); + ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_SD_VERSION_FAILURE); + } + else if (p_init->has_fw_version) + { + if (!fw_version_ok(p_init)) + { + NRF_LOG_WARNING("FW version too low."); + ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_FW_VERSION_FAILURE); + } + } + else + { + if (fw_version_required(p_init->type)) + { + NRF_LOG_ERROR("FW version missing."); + ret_val = EXT_ERR(NRF_DFU_EXT_ERROR_INIT_COMMAND_INVALID); + } + } + } + return ret_val; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_ver_validation.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_ver_validation.h new file mode 100644 index 0000000..5014b15 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/dfu/nrf_dfu_ver_validation.h @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __NRF_DFU_VER_VALIDATION_H +#define __NRF_DFU_VER_VALIDATION_H + +#include "stdint.h" +#include "sdk_errors.h" +#include "nrf_dfu_handling_error.h" +#include "dfu-cc.pb.h" + +/** @brief SD_REQ field value which indicates that Softdevice can be overwritten by the application. */ +#define SD_REQ_APP_OVERWRITES_SD 0 + +/** + * @brief Function for validating version of new firmware. + * + * @return NRF_DFU_RES_CODE_SUCCESS if successful or error code otherwise + */ +nrf_dfu_result_t nrf_dfu_ver_validation_check(dfu_init_command_t const * p_init); + +#endif //__NRF_DFU_VER_VALIDATION_H diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader.c new file mode 100644 index 0000000..3e62e47 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader.c @@ -0,0 +1,394 @@ +/** + * 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 "nrf_bootloader.h" + +#include "compiler_abstraction.h" +#include "nrf.h" +#include "boards.h" +#include "sdk_config.h" +#include "nrf_power.h" +#include "nrf_delay.h" +#include "nrf_log.h" +#include "nrf_log_ctrl.h" +#include "nrf_dfu.h" +#include "nrf_error.h" +#include "nrf_dfu_settings.h" +#include "nrf_dfu_utils.h" +#include "nrf_bootloader_wdt.h" +#include "nrf_bootloader_info.h" +#include "nrf_bootloader_app_start.h" +#include "nrf_bootloader_fw_activation.h" +#include "nrf_bootloader_dfu_timers.h" +#include "app_scheduler.h" +#include "app_timer.h" + +static nrf_dfu_observer_t m_user_observer; //<! Observer callback set by the user. + +#define SCHED_QUEUE_SIZE 32 /**< Maximum number of events in the scheduler queue. */ +#define SCHED_EVENT_DATA_SIZE MAX(NRF_DFU_SCHED_EVENT_DATA_SIZE, APP_TIMER_SCHED_EVENT_DATA_SIZE) /**< Maximum app_scheduler event size. */ + +#if !(defined(NRF_BL_DFU_ENTER_METHOD_BUTTON) && \ + defined(NRF_BL_DFU_ENTER_METHOD_PINRESET) && \ + defined(NRF_BL_DFU_ENTER_METHOD_GPREGRET) && \ + defined(NRF_BL_DFU_ENTER_METHOD_BUTTONLESS)) + #error Configuration file is missing flags. Update sdk_config.h. +#endif + +STATIC_ASSERT((NRF_BL_DFU_INACTIVITY_TIMEOUT_MS >= 100) || (NRF_BL_DFU_INACTIVITY_TIMEOUT_MS == 0), + "NRF_BL_DFU_INACTIVITY_TIMEOUT_MS must be 100 ms or more, or 0 to indicate that it is disabled."); + +#if defined(NRF_LOG_BACKEND_FLASH_START_PAGE) +STATIC_ASSERT(NRF_LOG_BACKEND_FLASH_START_PAGE != 0, + "If nrf_log flash backend is used it cannot use space after code because it would collide with settings page."); +#endif + +/**@brief Weak implemenation of nrf_dfu_init + * + * @note This function will be overridden if nrf_dfu.c is + * compiled and linked with the project + */ + #if (__LINT__ != 1) +__WEAK uint32_t nrf_dfu_init(nrf_dfu_observer_t observer) +{ + NRF_LOG_DEBUG("in weak nrf_dfu_init"); + return NRF_SUCCESS; +} +#endif + + +/**@brief Weak implementation of nrf_dfu_init + * + * @note This function must be overridden in application if + * user-specific initialization is needed. + */ +__WEAK uint32_t nrf_dfu_init_user(void) +{ + NRF_LOG_DEBUG("in weak nrf_dfu_init_user"); + return NRF_SUCCESS; +} + + +static void bootloader_reset(void) +{ + NRF_LOG_DEBUG("Resetting bootloader."); + + NRF_LOG_FINAL_FLUSH(); + +#if NRF_MODULE_ENABLED(NRF_LOG_BACKEND_RTT) + // To allow the buffer to be flushed by the host. + nrf_delay_ms(100); +#endif + + NVIC_SystemReset(); +} + + +static void inactivity_timeout(void) +{ + NRF_LOG_INFO("Inactivity timeout."); + bootloader_reset(); +} + + +/**@brief Function for handling DFU events. + */ +static void dfu_observer(nrf_dfu_evt_type_t evt_type) +{ + switch (evt_type) + { + case NRF_DFU_EVT_DFU_STARTED: + case NRF_DFU_EVT_OBJECT_RECEIVED: + nrf_bootloader_dfu_inactivity_timer_restart(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS, inactivity_timeout); + break; + case NRF_DFU_EVT_DFU_COMPLETED: + case NRF_DFU_EVT_DFU_ABORTED: + bootloader_reset(); + break; + default: + break; + } + + if (m_user_observer) + { + m_user_observer(evt_type); + } +} + + +/**@brief Function for initializing the event scheduler. + */ +static void scheduler_init(void) +{ + APP_SCHED_INIT(SCHED_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE); +} + + +/**@brief Suspend the CPU until an interrupt occurs. + */ +static void wait_for_event(void) +{ +#ifdef BLE_STACK_SUPPORT_REQD + (void)sd_app_evt_wait(); +#else + // Wait for an event. + __WFE(); + // Clear the internal event register. + __SEV(); + __WFE(); +#endif +} + + +/**@brief Continually sleep and process tasks whenever woken. + */ +static void loop_forever(void) +{ + while (true) + { + //feed the watchdog if enabled. + nrf_bootloader_wdt_feed(); + + app_sched_execute(); + + if (!NRF_LOG_PROCESS()) + { + wait_for_event(); + } + } +} + +/**@brief Function for initializing button used to enter DFU mode. + */ +static void dfu_enter_button_init(void) +{ + nrf_gpio_cfg_sense_input(NRF_BL_DFU_ENTER_METHOD_BUTTON_PIN, + BUTTON_PULL, + NRF_GPIO_PIN_SENSE_LOW); +} + + +static bool crc_on_valid_app_required(void) +{ + bool ret = true; + if (NRF_BL_APP_CRC_CHECK_SKIPPED_ON_SYSTEMOFF_RESET && + (nrf_power_resetreas_get() & NRF_POWER_RESETREAS_OFF_MASK)) + { + nrf_power_resetreas_clear(NRF_POWER_RESETREAS_OFF_MASK); + ret = false; + } + else if (NRF_BL_APP_CRC_CHECK_SKIPPED_ON_GPREGRET2 && + (nrf_power_gpregret2_get() & BOOTLOADER_DFU_SKIP_CRC)) + { + nrf_power_gpregret2_set(nrf_power_gpregret2_get() & ~BOOTLOADER_DFU_SKIP_CRC); + ret = false; + } + else + { + } + + return ret; +} + + +/**@brief Function for clearing all DFU enter flags that + * preserve state during reset. + * + * @details This is used to make sure that each of these flags + * is checked only once after reset. + */ +static void dfu_enter_flags_clear(void) +{ + if (NRF_BL_DFU_ENTER_METHOD_PINRESET && + (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk)) + { + // Clear RESETPIN flag. + NRF_POWER->RESETREAS |= POWER_RESETREAS_RESETPIN_Msk; + } + + if (NRF_BL_DFU_ENTER_METHOD_GPREGRET && + (nrf_power_gpregret_get() & BOOTLOADER_DFU_START)) + { + // Clear DFU mark in GPREGRET register. + nrf_power_gpregret_set(nrf_power_gpregret_get() & ~BOOTLOADER_DFU_START); + } + + if (NRF_BL_DFU_ENTER_METHOD_BUTTONLESS && + (s_dfu_settings.enter_buttonless_dfu == 1)) + { + // Clear DFU flag in flash settings. + s_dfu_settings.enter_buttonless_dfu = 0; + APP_ERROR_CHECK(nrf_dfu_settings_write(NULL)); + } +} + + +/**@brief Function for checking whether to enter DFU mode or not. + */ +static bool dfu_enter_check(void) +{ + if (!nrf_dfu_app_is_valid(crc_on_valid_app_required())) + { + NRF_LOG_DEBUG("DFU mode because app is not valid."); + return true; + } + + if (NRF_BL_DFU_ENTER_METHOD_BUTTON && + (nrf_gpio_pin_read(NRF_BL_DFU_ENTER_METHOD_BUTTON_PIN) == 0)) + { + NRF_LOG_DEBUG("DFU mode requested via button."); + return true; + } + + if (NRF_BL_DFU_ENTER_METHOD_PINRESET && + (NRF_POWER->RESETREAS & POWER_RESETREAS_RESETPIN_Msk)) + { + NRF_LOG_DEBUG("DFU mode requested via pin-reset."); + return true; + } + + if (NRF_BL_DFU_ENTER_METHOD_GPREGRET && + (nrf_power_gpregret_get() & BOOTLOADER_DFU_START)) + { + NRF_LOG_DEBUG("DFU mode requested via GPREGRET."); + return true; + } + + if (NRF_BL_DFU_ENTER_METHOD_BUTTONLESS && + (s_dfu_settings.enter_buttonless_dfu == 1)) + { + NRF_LOG_DEBUG("DFU mode requested via bootloader settings."); + return true; + } + + return false; +} + + +ret_code_t nrf_bootloader_init(nrf_dfu_observer_t observer) +{ + NRF_LOG_DEBUG("In nrf_bootloader_init"); + + uint32_t ret_val; + nrf_bootloader_fw_activation_result_t activation_result; + uint32_t initial_timeout; + bool dfu_enter = false; + + m_user_observer = observer; + + if (NRF_BL_DFU_ENTER_METHOD_BUTTON) + { + dfu_enter_button_init(); + } + + ret_val = nrf_dfu_settings_init(false); + if (ret_val != NRF_SUCCESS) + { + return NRF_ERROR_INTERNAL; + } + + // Check if an update needs to be activated and activate it. + activation_result = nrf_bootloader_fw_activate(); + + switch (activation_result) + { + case ACTIVATION_NONE: + initial_timeout = NRF_BL_DFU_INACTIVITY_TIMEOUT_MS; + dfu_enter = dfu_enter_check(); + break; + + case ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE: + initial_timeout = NRF_BL_DFU_CONTINUATION_TIMEOUT_MS; + dfu_enter = true; + break; + + case ACTIVATION_SUCCESS: + bootloader_reset(); + NRF_LOG_ERROR("Should never come here: After bootloader_reset()"); + return NRF_ERROR_INTERNAL; // Should not reach this. + + case ACTIVATION_ERROR: + default: + return NRF_ERROR_INTERNAL; + } + + if (dfu_enter) + { + nrf_bootloader_wdt_init(); + + scheduler_init(); + + // Clear all DFU stop flags. + dfu_enter_flags_clear(); + + // Call user-defined init function if implemented + ret_val = nrf_dfu_init_user(); + if (ret_val != NRF_SUCCESS) + { + return NRF_ERROR_INTERNAL; + } + + nrf_bootloader_dfu_inactivity_timer_restart(initial_timeout, inactivity_timeout); + + ret_val = nrf_dfu_init(dfu_observer); + if (ret_val != NRF_SUCCESS) + { + return NRF_ERROR_INTERNAL; + } + + NRF_LOG_DEBUG("Enter main loop"); + loop_forever(); // This function will never return. + NRF_LOG_ERROR("Should never come here: After looping forever."); + } + else + { + // Erase additional data like peer data or advertisement name + ret_val = nrf_dfu_settings_additional_erase(); + if (ret_val != NRF_SUCCESS) + { + return NRF_ERROR_INTERNAL; + } + + nrf_bootloader_app_start(); + NRF_LOG_ERROR("Should never come here: After nrf_bootloader_app_start()"); + } + + // Should not be reached. + return NRF_ERROR_INTERNAL; +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader.h new file mode 100644 index 0000000..d588b02 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader.h @@ -0,0 +1,79 @@ +/** + * 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. + * + */ +/**@file + * + * + * @defgroup nrf_bootloader Bootloader modules + * @{ + * @ingroup app_common + * @brief Bootloader and DFU modules + * + * The bootloader module can be used to implement a basic bootloader that + * can be extended with, for example, Device Firmware Update (DFU) support + * or custom functionality. + */ + +#ifndef NRF_BOOTLOADER_H__ +#define NRF_BOOTLOADER_H__ + +#include <stdint.h> +#include "nrf_dfu.h" +#ifdef __cplusplus +extern "C" { +#endif + +/** @brief Function for initializing the bootloader. + * + * @details This function is the entry point of all bootloader operations. + * If DFU functionality is compiled in, the DFU process is initialized + * when running this function. + * + * @note This function does not return unless an error occurred. + * + * @retval NRF_ERROR_INTERNAL Something went wrong. + */ +ret_code_t nrf_bootloader_init(nrf_dfu_observer_t observer); + +#ifdef __cplusplus +} +#endif + +#endif // NRF_BOOTLOADER_H__ +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_app_start.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_app_start.c new file mode 100644 index 0000000..b12cda0 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_app_start.c @@ -0,0 +1,77 @@ +/** + * 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 "nrf.h" +#include "nrf_bootloader_app_start.h" +#include "nrf_bootloader_info.h" +#include "nrf_log.h" +#include "nrf_dfu_mbr.h" +#include "nrf_log_ctrl.h" +#include "nrf_bootloader_info.h" + +// Do the final stages of app_start. Protect flash and run app. See nrf_bootloader_app_start_final.c +void nrf_bootloader_app_start_final(uint32_t start_addr); + +void nrf_bootloader_app_start(void) +{ + uint32_t start_addr = MBR_SIZE; // Always boot from end of MBR. If a SoftDevice is present, it will boot the app. + NRF_LOG_DEBUG("Running nrf_bootloader_app_start with address: 0x%08x", start_addr); + uint32_t err_code; + + // Disable and clear interrupts + // Notice that this disables only 'external' interrupts (positive IRQn). + NRF_LOG_DEBUG("Disabling interrupts. NVIC->ICER[0]: 0x%x", NVIC->ICER[0]); + + NVIC->ICER[0]=0xFFFFFFFF; + NVIC->ICPR[0]=0xFFFFFFFF; +#if defined(__NRF_NVIC_ISER_COUNT) && __NRF_NVIC_ISER_COUNT == 2 + NVIC->ICER[1]=0xFFFFFFFF; + NVIC->ICPR[1]=0xFFFFFFFF; +#endif + + err_code = nrf_dfu_mbr_irq_forward_address_set(); + if (err_code != NRF_SUCCESS) + { + NRF_LOG_ERROR("Failed running nrf_dfu_mbr_irq_forward_address_set()"); + } + + NRF_LOG_FLUSH(); + nrf_bootloader_app_start_final(start_addr); +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_app_start.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_app_start.h new file mode 100644 index 0000000..0bce18d --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_app_start.h @@ -0,0 +1,92 @@ +/** + * 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. + * + */ +/**@file + * + * @defgroup nrf_bootloader_app Application start + * @{ + * @ingroup nrf_bootloader + */ + +#ifndef NRF_BOOTLOADER_APP_START_H__ +#define NRF_BOOTLOADER_APP_START_H__ + +#include <stdint.h> +#include <stdbool.h> +#include "sdk_errors.h" + + +/**@brief Function for using hardware to protect flash from writing and reading. + * + * @details This function will apply write/erase protection to a specific area. Read + * protection is optional, decided by \p read_protect. This function uses + * the BPROT or ACL peripheral, depending on which is available. + * + * @param[in] address The start address of the area to protect. Must be a flash page + * boundary. + * @param[in] size The size of the area to protect, in bytes. Must be a multiple + * of flash page size. + * @param[in] read_protect Whether to protect the area from reading/executing as well. + * This is not available on chips with the BPROT peripheral + * (e.g. nrf52832, nrf52810). + * + * @retval NRF_SUCCESS Flash protection applied successfully. + * @retval NRF_ERROR_NO_MEM No more ACL instances to use for flash protection. + * @retval NRF_ERROR_INVALID_PARAM Address was out of range or size was not a multiple + * of flash page size. + */ +ret_code_t nrf_bootloader_flash_protect(uint32_t address, uint32_t size, bool read_protect); + +/**@brief Function for starting another application (and aborting the current one). + * + * @details This function uses the provided address to swap the stack pointer and then load + * the address of the reset handler to be executed. It checks the current system mode + * (thread/handler). If in thread mode, it resets into the other application. + * If in handler mode, isr_abort is executed to ensure that handler mode is left correctly. + * It then jumps into the reset handler of the other application. + * + * @note This function assumes the SoftDevice has not previously been initialized. + * + * @note This function will never return, but issues a reset into the provided application. + */ +void nrf_bootloader_app_start(void); + +#endif // NRF_BOOTLOADER_APP_START_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_app_start_final.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_app_start_final.c new file mode 100644 index 0000000..a818322 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_app_start_final.c @@ -0,0 +1,256 @@ +/** + * 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 "sdk_config.h" +#include "nrf_bootloader_app_start.h" +#include <stdint.h> +#include "nrf.h" +#include "nrf_peripherals.h" +#include "nrf_bootloader_info.h" +#include "nrf_dfu_types.h" +#include "nrf_assert.h" +#include "nrf_log.h" +#include "sdk_config.h" + + +// Enabling the NRF_BOOTLOADER_READ_PROTECT define is untested. +// Read-protecting the bootloader requires certain functions to run from RAM. +// In GCC and SES this is done automatically when the define is enabled. You will +// get warnings which can be ignored. +// In Keil you must change project settings to run the entire file from RAM. +#ifndef NRF_BOOTLOADER_READ_PROTECT +#define NRF_BOOTLOADER_READ_PROTECT 0 +#endif + + +#define HANDLER_MODE_EXIT 0xFFFFFFF9 // When this is jumped to, the CPU will exit interrupt context + // (handler mode), and pop values from the stack into registers. + // See ARM's documentation for "Exception entry and return". +#define EXCEPTION_STACK_WORD_COUNT 8 // The number of words popped from the stack when + // HANDLER_MODE_EXIT is branched to. + + +/**@brief Function that sets the stack pointer and link register, and starts executing a particular address. + * + * @param[in] new_msp The new value to set in the main stack pointer. + * @param[in] new_lr The new value to set in the link register. + * @param[in] addr The address to execute. + */ +#if defined ( __CC_ARM ) +__ASM __STATIC_INLINE void jump_to_addr(uint32_t new_msp, uint32_t new_lr, uint32_t addr) +{ + MSR MSP, R0; + MOV LR, R1; + BX R2; +} +#else +__STATIC_INLINE void jump_to_addr(uint32_t new_msp, uint32_t new_lr, uint32_t addr) +{ + __ASM volatile ("MSR MSP, %[arg]" : : [arg] "r" (new_msp)); + __ASM volatile ("MOV LR, %[arg]" : : [arg] "r" (new_lr) : "lr"); + __ASM volatile ("BX %[arg]" : : [arg] "r" (addr)); +} +#endif + + +/**@brief Function for booting an app as if the chip was reset. + * + * @param[in] vector_table_addr The address of the app's vector table. + */ +__STATIC_INLINE void app_start(uint32_t vector_table_addr) +{ + const uint32_t current_isr_num = (__get_IPSR() & IPSR_ISR_Msk); + const uint32_t new_msp = *((uint32_t *)(vector_table_addr)); // The app's Stack Pointer is found as the first word of the vector table. + const uint32_t reset_handler = *((uint32_t *)(vector_table_addr + sizeof(uint32_t))); // The app's Reset Handler is found as the second word of the vector table. + const uint32_t new_lr = 0xFFFFFFFF; + + __set_CONTROL(0x00000000); // Set CONTROL to its reset value 0. + __set_PRIMASK(0x00000000); // Set PRIMASK to its reset value 0. + __set_BASEPRI(0x00000000); // Set BASEPRI to its reset value 0. + __set_FAULTMASK(0x00000000); // Set FAULTMASK to its reset value 0. + + if (current_isr_num == 0) + { + // The CPU is in Thread mode (main context). + jump_to_addr(new_msp, new_lr, reset_handler); // Jump directly to the App's Reset Handler. + } + else + { + // The CPU is in Handler mode (interrupt context). + + const uint32_t exception_stack[EXCEPTION_STACK_WORD_COUNT] = // To be copied onto the stack. + { + 0x00000000, // New value of R0. Cleared by setting to 0. + 0x00000000, // New value of R1. Cleared by setting to 0. + 0x00000000, // New value of R2. Cleared by setting to 0. + 0x00000000, // New value of R3. Cleared by setting to 0. + 0x00000000, // New value of R12. Cleared by setting to 0. + 0xFFFFFFFF, // New value of LR. Cleared by setting to all 1s. + reset_handler, // New value of PC. The CPU will continue by executing the App's Reset Handler. + xPSR_T_Msk, // New value of xPSR (Thumb mode set). + }; + const uint32_t exception_sp = new_msp - sizeof(exception_stack); + + memcpy((uint32_t *)exception_sp, exception_stack, sizeof(exception_stack)); // 'Push' exception_stack onto the App's stack. + + jump_to_addr(exception_sp, new_lr, HANDLER_MODE_EXIT); // 'Jump' to the special value to exit handler mode. new_lr is superfluous here. + // exception_stack will be popped from the stack, so the resulting SP will be the new_msp. + // Execution will continue from the App's Reset Handler. + } +} + +#if NRF_BOOTLOADER_READ_PROTECT +#ifdef __ICCARM__ +__ramfunc +#elif defined ( __GNUC__ ) || defined ( __SES_ARM ) +__attribute__((noinline, long_call, section(".data"))) +#elif defined ( __CC_ARM ) +#warning "Keil requires changes to project settings to run this file from RAM. Ignore this warning if configuration has been made." +#endif +#endif +ret_code_t nrf_bootloader_flash_protect(uint32_t address, uint32_t size, bool read_protect) +{ + if ((size & (CODE_PAGE_SIZE - 1)) || (address > BOOTLOADER_SETTINGS_ADDRESS)) + { + return NRF_ERROR_INVALID_PARAM; + } + +#if defined(ACL_PRESENT) + + // Protect using ACL. + static uint32_t acl_instance = 0; + + uint32_t const wmask = (ACL_ACL_PERM_WRITE_Disable << ACL_ACL_PERM_WRITE_Pos); + uint32_t const rwmask = wmask | (ACL_ACL_PERM_READ_Disable << ACL_ACL_PERM_READ_Pos); + uint32_t const mask = read_protect ? rwmask: wmask; + + do + { + if (acl_instance >= ACL_REGIONS_COUNT) + { + return NRF_ERROR_NO_MEM; + } + + NRF_ACL->ACL[acl_instance].ADDR = address; + NRF_ACL->ACL[acl_instance].SIZE = size; + NRF_ACL->ACL[acl_instance].PERM = mask; + + acl_instance++; + + } while (NRF_ACL->ACL[acl_instance - 1].ADDR != address + || NRF_ACL->ACL[acl_instance - 1].SIZE != size + || NRF_ACL->ACL[acl_instance - 1].PERM != mask); // Check whether the acl_instance has been used before. + +#elif defined (BPROT_PRESENT) + + // Protect using BPROT. BPROT does not support read protection. + uint32_t pagenum_start = address / CODE_PAGE_SIZE; + uint32_t pagenum_end = pagenum_start + ((size - 1) / CODE_PAGE_SIZE); + + for (uint32_t i = pagenum_start; i <= pagenum_end; i++) + { + uint32_t config_index = i / 32; + uint32_t mask = (1 << (i - config_index * 32)); + + switch (config_index) + { + case 0: + NRF_BPROT->CONFIG0 = mask; + break; + case 1: + NRF_BPROT->CONFIG1 = mask; + break; + case 2: + NRF_BPROT->CONFIG2 = mask; + break; + case 3: + NRF_BPROT->CONFIG3 = mask; + break; + } + } + +#endif + + return NRF_SUCCESS; +} + + +#if NRF_BOOTLOADER_READ_PROTECT +#ifdef __ICCARM__ +__ramfunc +#elif defined ( __GNUC__ ) || defined ( __SES_ARM ) +__attribute__((noinline, long_call, section(".data"))) +#elif defined ( __CC_ARM ) +#warning "Keil requires changes to project settings to run this file from RAM. Ignore this warning if configuration has been made." +#endif +#endif +void nrf_bootloader_app_start_final(uint32_t vector_table_addr) +{ + ret_code_t ret_val; + + // Protect MBR & bootloader code and params pages. + if (NRF_BOOTLOADER_READ_PROTECT) + { + ret_val = nrf_bootloader_flash_protect(0, MBR_SIZE, NRF_BOOTLOADER_READ_PROTECT); + } + + // Size of the flash area to protect. + uint32_t area_size; + + if (!NRF_BL_SETTINGS_PAGE_PROTECT) + { + area_size = BOOTLOADER_SIZE + NRF_MBR_PARAMS_PAGE_SIZE; + } + else + { + area_size = BOOTLOADER_SIZE + NRF_MBR_PARAMS_PAGE_SIZE + BOOTLOADER_SETTINGS_PAGE_SIZE; + } + + ret_val = nrf_bootloader_flash_protect(BOOTLOADER_START_ADDR, + area_size, + NRF_BOOTLOADER_READ_PROTECT); + + if (!NRF_BOOTLOADER_READ_PROTECT && (ret_val != NRF_SUCCESS)) + { + NRF_LOG_ERROR("Could not protect bootloader and settings pages, 0x%x.", ret_val); + } + + // Run application + app_start(vector_table_addr); +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_dfu_timers.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_dfu_timers.c new file mode 100644 index 0000000..a6b056e --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_dfu_timers.c @@ -0,0 +1,126 @@ +/** + * Copyright (c) 2018 - 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 "nrf_bootloader_dfu_timers.h" + +#include "app_timer.h" +#include "nrf_clock.h" + +APP_TIMER_DEF(m_dfu_inactivity_timer); //!< Timer for aborting DFU if no update happens. +APP_TIMER_DEF(m_wdt_feed_timer); //!< Timer for feeding the application's watchdog (WDT) while the bootloader is running. + +static bool m_app_timer_initialized; + +/** @brief Function for handling the timeouts by calling the callback in the context. + */ +static void timeout_handler(void * p_context) +{ + if (p_context) + { + //lint -save -e611 "Suspicious cast" + ((nrf_bootloader_dfu_timeout_callback_t)p_context)(); + //lint -restore + } +} + + +/**@brief Initialization of app_timer. Function ensures that initialization happens only once. + */ +static void timer_init(void) +{ + if (!m_app_timer_initialized) + { + if (!nrf_clock_lf_is_running()) + { + nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART); + + // Wait for the clock to be ready. + while (!nrf_clock_lf_is_running()) {;} + } + + uint32_t err_code = app_timer_init(); + APP_ERROR_CHECK(err_code); + + // Start a single shot timer that will reset the DFU on timeout. + err_code = app_timer_create(&m_dfu_inactivity_timer, + APP_TIMER_MODE_SINGLE_SHOT, + timeout_handler); + ASSERT(err_code == NRF_SUCCESS); + + err_code = app_timer_create(&m_wdt_feed_timer, + APP_TIMER_MODE_REPEATED, + timeout_handler); + ASSERT(err_code == NRF_SUCCESS); + + m_app_timer_initialized = true; + } +} + + +/**@brief Function for initializing app_timer if necessary, and (re)starting a timer. + */ +static void timer_start(app_timer_t * p_timer, uint32_t timeout_ms, nrf_bootloader_dfu_timeout_callback_t callback) +{ + ret_code_t err_code; + + timer_init(); + + err_code = app_timer_stop(p_timer); + ASSERT(err_code == NRF_SUCCESS); + + if (timeout_ms != 0) + { + //lint -save -e611 "Suspicious cast" + err_code = app_timer_start(p_timer, APP_TIMER_TICKS(timeout_ms), (void *)callback); + //lint -restore + ASSERT(err_code == NRF_SUCCESS); + } +} + + +void nrf_bootloader_dfu_inactivity_timer_restart(uint32_t timeout_ms, nrf_bootloader_dfu_timeout_callback_t callback) +{ + timer_start(m_dfu_inactivity_timer, timeout_ms, callback); +} + + +void nrf_bootloader_wdt_feed_timer_start(uint32_t timeout_ms, nrf_bootloader_dfu_timeout_callback_t callback) +{ + timer_start(m_wdt_feed_timer, timeout_ms, callback); +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_dfu_timers.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_dfu_timers.h new file mode 100644 index 0000000..5104dfd --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_dfu_timers.h @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2018 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/**@file + * + * @defgroup nrf_bootloader_dfu_timers Timers for DFU in the bootloader + * @{ + * @ingroup nrf_bootloader + */ + +#ifndef NRF_BOOTLOADER_DFU_TIMERS_H__ +#define NRF_BOOTLOADER_DFU_TIMERS_H__ + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +/**@brief Handler called on timeout of a timer requested by the watchdog. + */ +typedef void (*nrf_bootloader_dfu_timeout_callback_t)(void); + + +/**@brief Function for restarting the inactivity timer. + * + * @note Calling this function cancels any previous calls to this function. + * + * @param[in] timeout_ms The number of milliseconds until reset if not restarted. + * If 0 is passed, the timer will be stopped and not restarted. + * @param[in] callback Function to be called on timeout. + */ +void nrf_bootloader_dfu_inactivity_timer_restart(uint32_t timeout_ms, nrf_bootloader_dfu_timeout_callback_t callback); + + +/**@brief Function for initializing and starting a repeated timer for feeding the watchdog. + * + * @param[in] timeout_ms Timer period. + * @param[in] callback Function called on every timeout. + */ +void nrf_bootloader_wdt_feed_timer_start(uint32_t timeout_ms, nrf_bootloader_dfu_timeout_callback_t callback); + + +#ifdef __cplusplus +} +#endif + +#endif // NRF_BOOTLOADER_DFU_TIMERS_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_fw_activation.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_fw_activation.c new file mode 100644 index 0000000..40e4870 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_fw_activation.c @@ -0,0 +1,436 @@ +/** + * 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 "nrf_bootloader_fw_activation.h" +#include "nrf_dfu_settings.h" +#include "nrf_dfu_mbr.h" +#include "nrf_bootloader_info.h" +#include "crc32.h" +#include "nrf_log.h" +#include "nrf_log_ctrl.h" +#include "nrf_dfu_utils.h" +#include "nrf_bootloader_wdt.h" + + +static volatile bool m_flash_write_done; + + +/** + * @brief Function for copying image. Image is copied in chunks. Frequency of storing progress + * in flash is configured by input parameter. + * + * @param[in] dst_addr Destination address. Must be page aligned. + * @param[in] src_addr Source address. Must be higher value than dst_addr. + * @param[in] size Image size. + * @param[in] progress_update_step Number of copied pages that triggers saving progress to non-volatile memory. + * Note that step can be decreased if there is a risk of corruption caused by source + * and destination overlapping. + * + * @return NRF_SUCCESS or error code in case of failure. + */ +static uint32_t image_copy(uint32_t dst_addr, + uint32_t src_addr, + uint32_t size, + uint32_t progress_update_step) +{ + if (src_addr == dst_addr) + { + NRF_LOG_DEBUG("No copy needed src_addr: 0x%x, dst_addr: 0x%x", src_addr, dst_addr); + return NRF_SUCCESS; + } + + ASSERT(src_addr >= dst_addr); + ASSERT(progress_update_step > 0); + ASSERT((dst_addr % CODE_PAGE_SIZE) == 0); + + uint32_t max_safe_progress_upd_step = (src_addr - dst_addr)/CODE_PAGE_SIZE; + ASSERT(max_safe_progress_upd_step > 0); + + uint32_t ret_val = NRF_SUCCESS; + uint32_t pages_left = CEIL_DIV(size, CODE_PAGE_SIZE); + + //Firmware copying is time consuming operation thus watchdog handling is started + nrf_bootloader_wdt_init(); + + progress_update_step = MIN(progress_update_step, max_safe_progress_upd_step); + + while (size > 0) + { + uint32_t pages; + uint32_t bytes; + if (pages_left <= progress_update_step) + { + pages = pages_left; + bytes = size; + } + else + { + pages = progress_update_step; + bytes = progress_update_step * CODE_PAGE_SIZE; + } + // Erase the target pages + ret_val = nrf_dfu_flash_erase(dst_addr, pages, NULL); + if (ret_val != NRF_SUCCESS) + { + return ret_val; + } + + // Flash one page + NRF_LOG_DEBUG("Copying 0x%x to 0x%x, size: 0x%x", src_addr, dst_addr, bytes); + ret_val = nrf_dfu_flash_store(dst_addr, + (uint32_t *)src_addr, + ALIGN_NUM(sizeof(uint32_t), bytes), + NULL); + if (ret_val != NRF_SUCCESS) + { + return ret_val; + } + + pages_left -= pages; + size -= bytes; + dst_addr += bytes; + src_addr += bytes; + s_dfu_settings.write_offset += bytes; + + //store progress in flash on every successful chunk write + ret_val = nrf_dfu_settings_write(NULL); + if (ret_val != NRF_SUCCESS) + { + NRF_LOG_ERROR("Failed to write image copying progress to settings page."); + return ret_val; + } + } + + return ret_val; +} + +/** @brief Function to continue application update. + * + * @details This function will be called after reset if there is a valid application in Bank1 + * required to be copied down to Bank 0. + * + * @return NRF_SUCCESS if continuation was successful, NRF_ERROR_INTERNAL if new firmware does not + * contain softdevice or other error coming from modules used by this function. + */ +static uint32_t app_activate(void) +{ + // This function is only in use when new app is present in Bank 1 + uint32_t const image_size = s_dfu_settings.bank_1.image_size; + + uint32_t src_addr = s_dfu_settings.progress.update_start_address; + uint32_t ret_val = NRF_SUCCESS; + uint32_t target_addr = nrf_dfu_bank0_start_addr() + s_dfu_settings.write_offset; + uint32_t length_left = (image_size - s_dfu_settings.write_offset); + uint32_t crc; + + NRF_LOG_DEBUG("Enter nrf_dfu_app_continue"); + + src_addr += s_dfu_settings.write_offset; + + if (src_addr == target_addr) + { + length_left = 0; + } + + ret_val = image_copy(target_addr, src_addr, length_left, NRF_BL_FW_COPY_PROGRESS_STORE_STEP); + if (ret_val != NRF_SUCCESS) + { + NRF_LOG_ERROR("Failed to copy firmware."); + return ret_val; + } + + // Check the CRC of the copied data. Enable if so. + crc = crc32_compute((uint8_t*)nrf_dfu_bank0_start_addr(), image_size, NULL); + + if (crc == s_dfu_settings.bank_1.image_crc) + { + NRF_LOG_DEBUG("Setting app as valid"); + s_dfu_settings.bank_0.bank_code = NRF_DFU_BANK_VALID_APP; + s_dfu_settings.bank_0.image_crc = crc; + s_dfu_settings.bank_0.image_size = image_size; + } + else + { + NRF_LOG_ERROR("CRC computation failed for copied app: " + "src crc: 0x%08x, res crc: 0x%08x", + s_dfu_settings.bank_1.image_crc, + crc); + } + + return ret_val; +} + + +/** @brief Function to execute the continuation of a SoftDevice update. + * + * @return NRF_SUCCESS if continuation was successful, NRF_ERROR_INTERNAL if new firmware does not + * contain softdevice or other error coming from modules used by this function. + */ +static uint32_t sd_activate(void) +{ + uint32_t ret_val = NRF_SUCCESS; + uint32_t target_addr = nrf_dfu_softdevice_start_address() + s_dfu_settings.write_offset; + uint32_t src_addr = s_dfu_settings.progress.update_start_address; + uint32_t sd_size = s_dfu_settings.sd_size; + uint32_t length_left = ALIGN_TO_PAGE(sd_size - s_dfu_settings.write_offset); + + NRF_LOG_DEBUG("Enter nrf_bootloader_dfu_sd_continue"); + + if (SD_MAGIC_NUMBER_GET(src_addr) != SD_MAGIC_NUMBER) + { + NRF_LOG_ERROR("Source address does not contain a valid SoftDevice.") + return NRF_ERROR_INTERNAL; + } + + // This can be a continuation due to a power failure + src_addr += s_dfu_settings.write_offset; + + if (s_dfu_settings.write_offset == sd_size) + { + NRF_LOG_DEBUG("SD already copied"); + return NRF_SUCCESS; + } + + if (s_dfu_settings.write_offset == 0) + { + NRF_LOG_DEBUG("Updating SD. Old SD ver: %d, New ver: %d", + SD_VERSION_GET(MBR_SIZE) / 1000000, SD_VERSION_GET(src_addr) / 1000000); + } + + ret_val = image_copy(target_addr, src_addr, length_left, NRF_BL_FW_COPY_PROGRESS_STORE_STEP); + if (ret_val != NRF_SUCCESS) + { + NRF_LOG_ERROR("Failed to copy firmware."); + return ret_val; + } + + ret_val = nrf_dfu_settings_write(NULL); + + return ret_val; +} + + +/** @brief Function to continue bootloader update. + * + * @details This function will be called after reset if there is a valid bootloader in Bank 0 or Bank 1 + * required to be relocated and activated through MBR commands. + * + * @return This function will not return if the bootloader is copied successfully. + * After the copy is verified, the device will reset and start the new bootloader. + * + * @retval NRF_SUCCESS Continuation was successful. + * @retval NRF_ERROR_INVALID_LENGTH Invalid length of flash operation. + * @retval NRF_ERROR_NO_MEM If no parameter page is provided (see sds for more info). + * @retval NRF_ERROR_INVALID_PARAM If an invalid command is given. + * @retval NRF_ERROR_INTERNAL Internal error that should not happen. + * @retval NRF_ERROR_FORBIDDEN If NRF_UICR->BOOTADDR is not set. + */ +static uint32_t bl_activate(void) +{ + uint32_t ret_val = NRF_ERROR_INVALID_DATA; + nrf_dfu_bank_t * p_bank = &s_dfu_settings.bank_1; + uint32_t len = p_bank->image_size; + uint32_t src_addr = s_dfu_settings.progress.update_start_address; + + if (p_bank->bank_code == NRF_DFU_BANK_VALID_SD_BL) + { + src_addr += s_dfu_settings.sd_size; + len -= s_dfu_settings.sd_size; + } + + NRF_LOG_DEBUG("Verifying BL: Addr: 0x%08x, Src: 0x%08x, Len: 0x%08x", BOOTLOADER_START_ADDR, src_addr, len); + + // This code is a configurable workaround for updating SD+BL from SDK 12.x.y - 14.1.0 + // SoftDevice size increase would lead to unaligned source address when comparing new BL in SD+BL updates. + // This workaround is not required once BL is successfully installed with a version that is compiled SDK 14.1.0 +#if defined(NRF52832_XXAA) && defined(BLE_STACK_SUPPORT_REQD) + if ((p_bank->bank_code == NRF_DFU_BANK_VALID_SD_BL) && + (memcmp((void *)BOOTLOADER_START_ADDR, (void *)(src_addr - 0x4000), len) == 0)) + { + ret_val = NRF_SUCCESS; + } +#endif // defined(NRF52832_XXAA) + + // Check if the BL has already been copied. + if ((ret_val != NRF_SUCCESS) && + (memcmp((void *)BOOTLOADER_START_ADDR, (void *)src_addr, len) == 0)) + { + ret_val = NRF_SUCCESS; + } + + // If the bootloader is the same as the banked version, the copy is finished + if (ret_val == NRF_SUCCESS) + { + NRF_LOG_DEBUG("No bootloader copy needed, bootloader update complete."); + } + else + { + NRF_LOG_DEBUG("Copying bootloader: Src: 0x%08x, Len: 0x%08x", src_addr, len); + NRF_LOG_FLUSH(); + + nrf_bootloader_wdt_feed(); + + // Bootloader is different than the banked version. Continue copy + // Note that if the SD and BL was combined, then the split point between them is in s_dfu_settings.sd_size + // On success this function won't return. + ret_val = nrf_dfu_mbr_copy_bl((uint32_t*)src_addr, len); + if (ret_val != NRF_SUCCESS) + { + NRF_LOG_ERROR("Request to copy BL failed"); + } + } + + return ret_val; +} + + +/** @brief Function to continue combined bootloader and SoftDevice update. + * + * @details This function will be called after reset if there is a valid bootloader and SoftDevice in Bank 0 or Bank 1 + * required to be relocated and activated through MBR commands. + * + * @retval NRF_SUCCESS Continuation was successful. + * @retval NRF_ERROR_INVALID_LENGTH Invalid length. + * @retval NRF_ERROR_NO_MEM If UICR.NRFFW[1] is not set (i.e. is 0xFFFFFFFF). + * @retval NRF_ERROR_INVALID_PARAM If an invalid command is given. + * @retval NRF_ERROR_INTERNAL Indicates that the contents of the memory blocks where not verified correctly after copying. + * @retval NRF_ERROR_NULL If the content of the memory blocks differs after copying. + * @retval NRF_ERROR_FORBIDDEN If NRF_UICR->BOOTADDR is not set. + */ +static uint32_t sd_bl_activate() +{ + uint32_t ret_val = NRF_SUCCESS; + + NRF_LOG_DEBUG("Enter nrf_dfu_sd_bl_continue"); + + ret_val = sd_activate(); + if (ret_val != NRF_SUCCESS) + { + NRF_LOG_ERROR("SD+BL: SD copy failed"); + return ret_val; + } + + ret_val = bl_activate(); + if (ret_val != NRF_SUCCESS) + { + NRF_LOG_ERROR("SD+BL: BL copy failed"); + return ret_val; + } + + return ret_val; +} + + +static void flash_write_callback(void * p_context) +{ + UNUSED_PARAMETER(p_context); + m_flash_write_done = true; +} + + +nrf_bootloader_fw_activation_result_t nrf_bootloader_fw_activate(void) +{ + nrf_bootloader_fw_activation_result_t result; + uint32_t ret_val = NRF_SUCCESS; + nrf_dfu_bank_t * p_bank = &s_dfu_settings.bank_1; + bool sd_update = false; + + + NRF_LOG_DEBUG("Enter nrf_bootloader_fw_activate"); + + switch (p_bank->bank_code) + { + case NRF_DFU_BANK_VALID_APP: + NRF_LOG_DEBUG("Valid App"); + ret_val = app_activate(); + break; + case NRF_DFU_BANK_VALID_SD: + NRF_LOG_DEBUG("Valid SD"); + ret_val = sd_activate(); + sd_update = true; + break; + case NRF_DFU_BANK_VALID_BL: + NRF_LOG_DEBUG("Valid BL"); + ret_val = bl_activate(); + break; + case NRF_DFU_BANK_VALID_SD_BL: + NRF_LOG_DEBUG("Valid SD + BL"); + ret_val = sd_bl_activate(); + sd_update = true; + break; + case NRF_DFU_BANK_INVALID: + default: + NRF_LOG_INFO("No firmware to activate."); + return ACTIVATION_NONE; + } + + if (ret_val != NRF_SUCCESS) + { + NRF_LOG_ERROR("Activation failed with error %d (bank code: 0x%x)", ret_val, p_bank->bank_code); + result = ACTIVATION_ERROR; + } + + // Invalidate bank, marking completion. + nrf_dfu_bank_invalidate(p_bank); + + m_flash_write_done = false; + ret_val = nrf_dfu_settings_write(flash_write_callback); + ASSERT(m_flash_write_done); + + /* At this point flash module is performing blocking operation. It is expected that operation is already performed. */ + if (ret_val == NRF_SUCCESS) + { + result = ACTIVATION_SUCCESS; + if (sd_update && nrf_dfu_app_is_valid(true)) + { + //If SD was updated and application is valid we want to stay in DFU to receive application. + NRF_LOG_DEBUG("A SoftDevice has just been activated. It's likely that an application will come immediately"); + result = ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE; + } + } + else + { + NRF_LOG_ERROR("Could not write settings."); + result = ACTIVATION_ERROR; + } + + return result; +} + diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_fw_activation.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_fw_activation.h new file mode 100644 index 0000000..312491d --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_fw_activation.h @@ -0,0 +1,96 @@ +/** + * Copyright (c) 2018 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/**@file + * + * @defgroup nrf_bootloader_fw_activation Firmware activation + * @{ + * @ingroup nrf_bootloader + */ + +#ifndef NRF_BOOTLOADER_FW_ACTIVATION_H__ +#define NRF_BOOTLOADER_FW_ACTIVATION_H__ + +#include <stdint.h> +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef enum +{ + ACTIVATION_NONE, //!< No new update was found. + ACTIVATION_SUCCESS, //!< Update was successfully activated. + ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE, //!< Update was successfully activated, but there might be additional update(s) to be transferred. + ACTIVATION_ERROR, //!< Activation of an update failed. +} nrf_bootloader_fw_activation_result_t; + +/** @brief Function for activating a firmware received during DFU. + * + * @details This function initiates or continues the DFU copy-back + * routines. These routines are fail-safe operations to activate + * either a new SoftDevice, bootloader, combination of SoftDevice and + * bootloader, or a new application. + * + * @details This function relies on accessing MBR commands through supervisor calls. + * It does not rely on the SoftDevice for flash operations. + * + * @note When updating the bootloader or both bootloader and SoftDevice in combination, + * this function does not return, but rather initiates a reboot to activate + * the new bootloader. + * + * @retval ACTIVATION_NONE If no update was found. + * @retval ACTIVATION_SUCCESS If the firmware update was successfully activated. + * @retval ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE If the firmware update was successfully activated, + * but there are likely more updates to be transferred. + * @retval ACTIVATION_ERROR If the firmware update could not be activated. + */ +nrf_bootloader_fw_activation_result_t nrf_bootloader_fw_activate(void); + + + +#ifdef __cplusplus +} +#endif + +#endif // NRF_BOOTLOADER_FW_ACTIVATION_H__ + +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_info.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_info.c new file mode 100644 index 0000000..77a8ad1 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_info.c @@ -0,0 +1,59 @@ +/** + * 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 "nrf_bootloader_info.h" + + +/** @brief This variable ensures that the linker script will write the bootloader start address + * to the UICR register. This value will be written in the HEX file and thus written to + * UICR when the bootloader is flashed into the chip. + */ +#if defined (__CC_ARM ) + #pragma push + #pragma diag_suppress 1296 + uint32_t m_uicr_bootloader_start_address __attribute__((at(NRF_UICR_BOOTLOADER_START_ADDRESS))) + = BOOTLOADER_START_ADDR; + #pragma pop +#elif defined ( __GNUC__ ) || defined ( __SES_ARM ) + volatile uint32_t m_uicr_bootloader_start_address __attribute__ ((section(".uicr_bootloader_start_address"))) + = BOOTLOADER_START_ADDR; +#elif defined ( __ICCARM__ ) + __root const uint32_t m_uicr_bootloader_start_address @ NRF_UICR_BOOTLOADER_START_ADDRESS + = BOOTLOADER_START_ADDR; +#endif diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_info.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_info.h new file mode 100644 index 0000000..812cddb --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_info.h @@ -0,0 +1,188 @@ +/** + * 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. + * + */ +/**@file + * + * @defgroup nrf_bootloader_info Bootloader Information + * @{ + * @ingroup nrf_bootloader + */ + +#ifndef NRF_BOOTLOADER_INFO_H__ +#define NRF_BOOTLOADER_INFO_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "app_util.h" +#include "nrf.h" +#include "nrf_mbr.h" + +/** @brief Macro for getting the start address of the bootloader image. + * + * The macro is not a compile time symbol. It cannot be used as a + * constant expression, for example, inside a static assert or linker script + * at-placement. + */ +#ifndef BOOTLOADER_START_ADDR +#if (__LINT__ == 1) + #define BOOTLOADER_START_ADDR (0x3AC00) +#elif defined(CODE_START) + #define BOOTLOADER_START_ADDR (CODE_START) +#else + #error Not a valid compiler/linker for BOOTLOADER_START_ADDR. +#endif +#endif + + +/** @brief Macro for getting the size of the bootloader image. + */ +#ifndef BOOTLOADER_SIZE +#if defined ( NRF51 ) + #define BOOTLOADER_SIZE (BOOTLOADER_SETTINGS_ADDRESS - BOOTLOADER_START_ADDR) +#elif defined( NRF52_SERIES ) + #define BOOTLOADER_SIZE (NRF_MBR_PARAMS_PAGE_ADDRESS - BOOTLOADER_START_ADDR) +#elif (__LINT__ == 1) + #define BOOTLOADER_SIZE (0x6000) +#endif +#endif + + +/** + * @brief Bootloader start address in UICR. + * + * Register location in UICR where the bootloader start address is stored. + * + * @note If the value at the given location is 0xFFFFFFFF, the bootloader address is not set. + */ +#define NRF_UICR_BOOTLOADER_START_ADDRESS (NRF_UICR_BASE + 0x14) + + +// The following macros are for accessing the SoftDevice information structure, +// which is found inside the SoftDevice binary. + +/** @brief Macro for converting an offset inside the SoftDevice information struct to an absolute address. + */ +#define SD_INFO_ABS_OFFSET_GET(baseaddr, offset) ((baseaddr) + (SOFTDEVICE_INFO_STRUCT_OFFSET) + (offset)) + +/** @brief Macros for reading a byte or a word at a particular offset inside a SoftDevice information struct. + * Use MBR_SIZE as baseaddr when the SoftDevice is installed just above the MBR (the usual case). + */ +#define SD_OFFSET_GET_UINT32(baseaddr, offset) (*((uint32_t *) SD_INFO_ABS_OFFSET_GET(baseaddr, offset))) +#define SD_OFFSET_GET_UINT16(baseaddr, offset) (*((uint16_t *) SD_INFO_ABS_OFFSET_GET(baseaddr, offset))) +#define SD_OFFSET_GET_UINT8(baseaddr, offset) (*((uint8_t *) SD_INFO_ABS_OFFSET_GET(baseaddr, offset))) + + +#ifdef BLE_STACK_SUPPORT_REQD +#include "nrf_sdm.h" +#else +/** @brief The offset inside the SoftDevice at which the information struct is placed. + * To see the layout of the information struct, see the SoftDevice specification. + */ +#define SOFTDEVICE_INFO_STRUCT_OFFSET (0x2000) + +#define SD_INFO_STRUCT_SIZE(baseaddr) SD_OFFSET_GET_UINT8(baseaddr, 0x00) + +/** @brief Macro for reading the size of a SoftDevice at a given base address. + */ +#ifndef SD_SIZE_GET +#define SD_SIZE_GET(baseaddr) SD_OFFSET_GET_UINT32(baseaddr, 0x08) +#endif + +/** @brief Macro for reading the version of a SoftDevice at a given base address. + * This expression checks the length of the information struct to see if the version is present. + * The version number is constructed like this: + * major_version * 1000000 + minor_version * 1000 + bugfix_version + */ +#ifndef SD_VERSION_GET +#define SD_VERSION_GET(baseaddr) ((SD_INFO_STRUCT_SIZE(baseaddr) > (0x14)) \ + ? SD_OFFSET_GET_UINT32(baseaddr, 0x14) \ + : 0) +#endif +#endif + + +/** @brief Macro for reading the magic number of a SoftDevice at a given base address. + */ +#ifndef SD_MAGIC_NUMBER_GET +#define SD_MAGIC_NUMBER_GET(baseaddr) SD_OFFSET_GET_UINT32(baseaddr, 0x04) +#endif + +/** @brief Macro for getting the absolute address of the magic number. + */ +#define SD_MAGIC_NUMBER_ABS_OFFSET_GET(baseaddr) SD_INFO_ABS_OFFSET_GET(baseaddr, 0x04) + +/** @brief The number present at a specific location in all SoftDevices. + */ +#define SD_MAGIC_NUMBER ((uint32_t)0x51B1E5DB) + +/** @brief Whether a SoftDevice is at its regular location. + */ +#ifndef SD_PRESENT +#define SD_PRESENT ((SD_MAGIC_NUMBER_GET(MBR_SIZE)) == (SD_MAGIC_NUMBER)) +#endif + +/** @brief The multiplier for the major version of the SoftDevice. See \ref SD_VERSION_GET + */ +#define SD_MAJOR_VERSION_MULTIPLIER (1000000) + +/** @brief Read the major version of the SoftDevice from the raw version number. See \ref SD_VERSION_GET. + */ +#define SD_MAJOR_VERSION_EXTRACT(raw_version) ((raw_version)/SD_MAJOR_VERSION_MULTIPLIER) + + +#define BOOTLOADER_DFU_GPREGRET_MASK (0xB0) /**< Magic pattern written to GPREGRET register to signal between main app and DFU. The 3 lower bits are assumed to be used for signalling purposes.*/ +#define BOOTLOADER_DFU_START_BIT_MASK (0x01) /**< Bit mask to signal from main application to enter DFU mode using a buttonless service. */ + +#define BOOTLOADER_DFU_GPREGRET2_MASK (0xA8) /**< Magic pattern written to GPREGRET2 register to signal between main app and DFU. The 3 lower bits are assumed to be used for signalling purposes.*/ +#define BOOTLOADER_DFU_SKIP_CRC_BIT_MASK (0x01) /**< Bit mask to signal from main application that CRC-check is not needed for image verification. */ + + +#define BOOTLOADER_DFU_START (BOOTLOADER_DFU_GPREGRET_MASK | BOOTLOADER_DFU_START_BIT_MASK) /**< Magic number to signal that bootloader should enter DFU mode because of signal from Buttonless DFU in main app.*/ +#define BOOTLOADER_DFU_SKIP_CRC (BOOTLOADER_DFU_GPREGRET2_MASK | BOOTLOADER_DFU_SKIP_CRC_BIT_MASK) /**< Magic number to signal that CRC can be skipped due to low power modes.*/ + + + +#ifdef __cplusplus +} +#endif + +#endif // #ifndef NRF_BOOTLOADER_INFO_H__ +/** @} */ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_wdt.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_wdt.c new file mode 100644 index 0000000..b75d6ef --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_wdt.c @@ -0,0 +1,134 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include "nrf_bootloader_wdt.h" +#include "nrf_wdt.h" +#include "nrf_bootloader_dfu_timers.h" +#include "nrf_log_ctrl.h" + +#define NRF_LOG_MODULE_NAME nrf_bootloader_wdt +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +//Flag used to determine if internal feeding should stay active. +static bool m_wdt_keep_internal_feed; + +static void wdt_feed(void) +{ + if (nrf_wdt_started()) + { + for (nrf_wdt_rr_register_t i = NRF_WDT_RR0; i < NRF_WDT_RR7; i++) + { + if (nrf_wdt_reload_request_is_enabled(i)) + { + nrf_wdt_reload_request_set(i); + } + } + } +} + + +static void wdt_feed_timer_handler(void) +{ + if (m_wdt_keep_internal_feed) + { + NRF_LOG_INFO("Internal feed"); + wdt_feed(); + } +} + + +void WDT_IRQHandler(void) +{ + nrf_wdt_event_clear(NRF_WDT_EVENT_TIMEOUT); + NRF_LOG_FINAL_FLUSH(); +} + +void nrf_bootloader_wdt_init(void) +{ + static bool initialized = false; + + if (initialized) + { + return; + } + + if (nrf_wdt_started()) + { + uint32_t approx_wdt_ms = nrf_wdt_reload_value_get() / 32; + + NRF_LOG_INFO("WDT enabled CRV:%d ms", approx_wdt_ms); + + //wdt_ticks must be reduced (0.75) to feed the watchdog before the timeout. + uint32_t reduced_timeout_ms = (approx_wdt_ms * 3)/4; + + /* Ideally, watchdog should be fed by the bootloader from the main context but if bootloader latency + * (mainly driven by signature check) is big enough there is a risk that watchdog will not be fed + * on time. In that case watchdog will be fed from timer context. */ + m_wdt_keep_internal_feed = + (reduced_timeout_ms < NRF_BL_WDT_MAX_SCHEDULER_LATENCY_MS); + + /* initial watchdog feed */ + wdt_feed(); + + /* If internal feed is needed or WDT is active in sleep module must provide regular wakeup interrupt.*/ + bool wdt_start_timer = m_wdt_keep_internal_feed || (NRF_WDT->CONFIG & WDT_CONFIG_SLEEP_Msk); + if (wdt_start_timer) + { + NRF_LOG_INFO("Starting a timer (%d ms) for feeding watchdog.", reduced_timeout_ms); + nrf_bootloader_wdt_feed_timer_start(reduced_timeout_ms, wdt_feed_timer_handler); + } + + NVIC_EnableIRQ(WDT_IRQn); + } + else + { + NRF_LOG_INFO("WDT is not enabled"); + } + + initialized = true; +} + +void nrf_bootloader_wdt_feed(void) +{ + if (nrf_wdt_started()) + { + wdt_feed(); + } +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_wdt.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_wdt.h new file mode 100644 index 0000000..0a6cb9b --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/nrf_bootloader_wdt.h @@ -0,0 +1,79 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef NRF_BOOTLOADER_WDT_H +#define NRF_BOOTLOADER_WDT_H + +/**@file + * + * @defgroup nrf_bootloader_wdt Automated feeding of the watchdog + * @{ + * @ingroup nrf_bootloader + * @brief Module that keeps the WDT from timing out if the WDT has been started in the application. + */ + +#include "sdk_errors.h" + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @brief Function for checking whether the WDT peripheral is started and for getting its configuration. + * + * The module uses app_timer to start regular feeding of the watchdog. Timer interval + * is chosen based on watchdog settings. When @ref nrf_bootloader_wdt_feed is called, internal + * feeding is stopped assuming that the application takes responsibity of watchdog feeding. + * However, if @ref NRF_BL_WDT_MAX_SCHEDULER_LATENCY_MS or the watchdog is configured to + * run during sleep, then internal feeding (from app_timer handler context) is kept active. + */ +void nrf_bootloader_wdt_init(void); + + +/** + * @brief Function for feeding the watchdog (if active). + */ +void nrf_bootloader_wdt_feed(void); + +#ifdef __cplusplus +} +#endif + +/** @} */ + +#endif //NRF_BOOTLOADER_WDT_H diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/serial_dfu/nrf_dfu_serial.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/serial_dfu/nrf_dfu_serial.c new file mode 100644 index 0000000..8e14b05 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/serial_dfu/nrf_dfu_serial.c @@ -0,0 +1,265 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "nrf_dfu_serial.h" +#include "nrf_dfu_req_handler.h" +#include "nrf_dfu_handling_error.h" + +#define NRF_LOG_MODULE_NAME nrf_dfu_serial +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +#define NRF_SERIAL_OPCODE_SIZE (sizeof(uint8_t)) + + + +static uint32_t response_ext_err_payload_add(uint8_t * p_buffer, uint32_t buf_offset) +{ + p_buffer[buf_offset] = ext_error_get(); + (void) ext_error_set(NRF_DFU_EXT_ERROR_NO_ERROR); + + return 1; +} + + +static void response_send(nrf_dfu_serial_t * p_transport, + nrf_dfu_response_t const * p_response) +{ + uint8_t index = 0; + uint8_t * p_serialized_rsp = p_transport->p_rsp_buf; + + NRF_LOG_DEBUG("Sending Response: [0x%01x, 0x%01x]", p_response->request, p_response->result); + + p_serialized_rsp[index++] = NRF_DFU_OP_RESPONSE; + p_serialized_rsp[index++] = p_response->request; + p_serialized_rsp[index++] = (uint8_t)(p_response->result); + + if (p_response->result == NRF_DFU_RES_CODE_SUCCESS) + { + switch (p_response->request) + { + case NRF_DFU_OP_PROTOCOL_VERSION: + { + p_serialized_rsp[index] = p_response->protocol.version; + index += sizeof(uint8_t); + } break; + + case NRF_DFU_OP_HARDWARE_VERSION: + { + index += uint32_encode(p_response->hardware.part, &p_serialized_rsp[index]); + index += uint32_encode(p_response->hardware.variant, &p_serialized_rsp[index]); + index += uint32_encode(p_response->hardware.memory.rom_size, &p_serialized_rsp[index]); + index += uint32_encode(p_response->hardware.memory.ram_size, &p_serialized_rsp[index]); + index += uint32_encode(p_response->hardware.memory.rom_page_size, &p_serialized_rsp[index]); + } break; + + case NRF_DFU_OP_FIRMWARE_VERSION: + { + p_serialized_rsp[index++] = p_response->firmware.type; + index += uint32_encode(p_response->firmware.version, &p_serialized_rsp[index]); + index += uint32_encode(p_response->firmware.addr, &p_serialized_rsp[index]); + index += uint32_encode(p_response->firmware.len, &p_serialized_rsp[index]); + } break; + + case NRF_DFU_OP_CRC_GET: + index += uint32_encode(p_response->crc.offset, &p_serialized_rsp[index]); + index += uint32_encode(p_response->crc.crc, &p_serialized_rsp[index]); + break; + + case NRF_DFU_OP_OBJECT_SELECT: + index += uint32_encode(p_response->select.max_size, &p_serialized_rsp[index]); + index += uint32_encode(p_response->select.offset, &p_serialized_rsp[index]); + index += uint32_encode(p_response->select.crc, &p_serialized_rsp[index]); + break; + + case NRF_DFU_OP_MTU_GET: + index += uint16_encode(p_response->mtu.size, &p_serialized_rsp[index]); + break; + + case NRF_DFU_OP_PING: + p_serialized_rsp[index] = p_response->ping.id; + index += sizeof(uint8_t); + break; + + default: + // no implementation + break; + } + } + else if (p_response->result == NRF_DFU_RES_CODE_EXT_ERROR) + { + index += response_ext_err_payload_add(p_serialized_rsp, index); + } + + if (index > NRF_SERIAL_MAX_RESPONSE_SIZE) + { + NRF_LOG_ERROR("Message is larger than expected."); + } + + // Send response. + if (p_transport->rsp_func((uint8_t const *)(p_serialized_rsp), index) != NRF_SUCCESS) + { + NRF_LOG_ERROR("Failed to send data over serial interface!"); + } +} + + +void dfu_req_handler_rsp_clbk(nrf_dfu_response_t * p_res, void * p_context) +{ + nrf_dfu_serial_t * p_transport = (nrf_dfu_serial_t *)(p_context); + + if (p_res->result != NRF_DFU_RES_CODE_SUCCESS) + { + NRF_LOG_WARNING("DFU request completed with result: 0x%x", p_res->result); + } + + switch (p_res->request) + { + default: + /* Reply normally. + * Make sure to reply to NRF_DFU_OP_OBJECT_CREATE when running DFU over serial, + * otherwise the transfer might run very slow, without an apparent reason. + */ + break; + + case NRF_DFU_OP_OBJECT_WRITE: + { + p_transport->pkt_notif_target_count--; + + if ( (p_transport->pkt_notif_target == 0) + || (p_transport->pkt_notif_target_count != 0)) + { + /* Do not reply to _OBJECT_WRITE messages. */ + return; + } + + /* Reply with a CRC message and reset the packet counter. */ + p_transport->pkt_notif_target_count = p_transport->pkt_notif_target; + + p_res->request = NRF_DFU_OP_CRC_GET; + p_res->crc.offset = p_res->write.offset; + p_res->crc.crc = p_res->write.crc; + } break; + } + + response_send(p_transport, p_res); +} + + +void nrf_dfu_serial_on_packet_received(nrf_dfu_serial_t * p_transport, + uint8_t const * p_data, + uint32_t length) +{ + uint8_t const * p_payload = &p_data[NRF_SERIAL_OPCODE_SIZE]; + uint16_t const payload_len = (length - NRF_SERIAL_OPCODE_SIZE); + + nrf_dfu_request_t request = + { + .request = (nrf_dfu_op_t)(p_data[0]), + .callback.response = dfu_req_handler_rsp_clbk, + .p_context = p_transport + }; + + bool buf_free = true; + + switch (request.request) + { + case NRF_DFU_OP_FIRMWARE_VERSION: + { + request.firmware.image_number = p_payload[0]; + } break; + + case NRF_DFU_OP_RECEIPT_NOTIF_SET: + { + NRF_LOG_DEBUG("Set receipt notif target: %d", p_transport->pkt_notif_target); + + p_transport->pkt_notif_target = uint16_decode(&p_payload[0]); + p_transport->pkt_notif_target_count = p_transport->pkt_notif_target; + } break; + + case NRF_DFU_OP_OBJECT_SELECT: + { + request.select.object_type = p_payload[0]; + } break; + + case NRF_DFU_OP_OBJECT_CREATE: + { + // Reset the packet receipt notification on create object + p_transport->pkt_notif_target_count = p_transport->pkt_notif_target; + + request.create.object_type = p_payload[0]; + request.create.object_size = uint32_decode(&p_payload[1]); + } break; + + case NRF_DFU_OP_OBJECT_WRITE: + { + // Buffer will be freed asynchronously + buf_free = false; + + request.write.p_data = p_payload; + request.write.len = payload_len; + request.callback.write = p_transport->payload_free_func; + } break; + + case NRF_DFU_OP_MTU_GET: + { + NRF_LOG_DEBUG("Received serial mtu"); + request.mtu.size = p_transport->mtu; + } break; + + case NRF_DFU_OP_PING: + { + NRF_LOG_DEBUG("Received ping %d", p_payload[0]); + request.ping.id = p_payload[0]; + } break; + + default: + /* Do nothing. */ + break; + } + + if (buf_free) + { + p_transport->payload_free_func((void *)(p_payload)); + } + + ret_code_t ret_code = nrf_dfu_req_handler_on_req(&request); + ASSERT(ret_code == NRF_SUCCESS); +} diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/serial_dfu/nrf_dfu_serial.h b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/serial_dfu/nrf_dfu_serial.h new file mode 100644 index 0000000..c14ee40 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/serial_dfu/nrf_dfu_serial.h @@ -0,0 +1,109 @@ +/** + * Copyright (c) 2017 - 2018, Nordic Semiconductor ASA + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form, except as embedded into a Nordic + * Semiconductor ASA integrated circuit in a product or a software update for + * such product, must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of Nordic Semiconductor ASA nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * 4. This software, with or without modification, must only be used with a + * Nordic Semiconductor ASA integrated circuit. + * + * 5. Any software provided in binary form under this license must not be reverse + * engineered, decompiled, modified and/or disassembled. + * + * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef NRF_DFU_SERIAL_H__ +#define NRF_DFU_SERIAL_H__ + +#include <stdint.h> +#include "sdk_errors.h" +#include "nrf_dfu_req_handler.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/**@file + * + * @defgroup nrf_dfu_serial DFU Serial transports shared part + * @{ + * @ingroup nrf_dfu + * @brief Shared part of Device Firmware Update (DFU) transport layers using serial interface (UART, USB CDC ACM). + * + * @defgroup nrf_dfu_serial_uart DFU Serial UART transport + * @ingroup nrf_dfu_serial + * @brief Configuration for Device Firmware Update (DFU) transport layer using UART. + * + * @defgroup nrf_dfu_serial_usb DFU Serial USB CDC ACM transport + * @ingroup nrf_dfu_serial + * @brief Configuration for Device Firmware Update (DFU) transport layer using USB CDC ACM. + * + */ + +#define NRF_SERIAL_MAX_RESPONSE_SIZE (sizeof(nrf_dfu_response_t)) + +/** + * Prototype for function for sending response over serial DFU transport. + */ +typedef ret_code_t (*nrf_serial_rsp_func_t)(uint8_t const * p_data, uint32_t length); + +/** + * Prototype for function for freeing RX buffer. + * + * Function is called when input data is processed. + */ +typedef void (*nrf_serial_rx_buf_free_func_t)(void * p_buf); + + +/**@brief DFU serial transport layer state. + * + * @details This structure contains status information related to the serial transport layer type. + */ +typedef struct +{ + uint16_t pkt_notif_target; + uint16_t pkt_notif_target_count; + nrf_serial_rsp_func_t rsp_func; + nrf_serial_rx_buf_free_func_t payload_free_func; + uint32_t mtu; + uint8_t * p_rsp_buf; +} nrf_dfu_serial_t; + +void nrf_dfu_serial_on_packet_received(nrf_dfu_serial_t * p_transport, + uint8_t const * p_data, + uint32_t length); + +/** @} */ + +#ifdef __cplusplus +} +#endif + +#endif // NRF_DFU_SERIAL_H__ diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/serial_dfu/nrf_dfu_serial_uart.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/serial_dfu/nrf_dfu_serial_uart.c new file mode 100644 index 0000000..3d0b783 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/serial_dfu/nrf_dfu_serial_uart.c @@ -0,0 +1,235 @@ +/** + * 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 "nrf_dfu_serial.h" + +#include <string.h> +#include "boards.h" +#include "app_util_platform.h" +#include "nrf_dfu_transport.h" +#include "nrf_dfu_req_handler.h" +#include "slip.h" +#include "nrf_balloc.h" +#include "nrf_drv_uart.h" + +#define NRF_LOG_MODULE_NAME nrf_dfu_serial_uart +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +/**@file + * + * @defgroup nrf_dfu_serial_uart DFU Serial UART transport + * @ingroup nrf_dfu + * @brief Device Firmware Update (DFU) transport layer using UART. + */ + +#define NRF_SERIAL_OPCODE_SIZE (sizeof(uint8_t)) +#define NRF_UART_MAX_RESPONSE_SIZE_SLIP (2 * NRF_SERIAL_MAX_RESPONSE_SIZE + 1) +#define RX_BUF_SIZE (64) //to get 64bytes payload +#define OPCODE_OFFSET (sizeof(uint32_t) - NRF_SERIAL_OPCODE_SIZE) +#define DATA_OFFSET (OPCODE_OFFSET + NRF_SERIAL_OPCODE_SIZE) +#define UART_SLIP_MTU (2 * (RX_BUF_SIZE + 1) + 1) +#define BALLOC_BUF_SIZE ((CEIL_DIV((RX_BUF_SIZE+OPCODE_SIZE),sizeof(uint32_t))*sizeof(uint32_t))) + +NRF_BALLOC_DEF(m_payload_pool, (UART_SLIP_MTU + 1), NRF_DFU_SERIAL_UART_RX_BUFFERS); + +static nrf_drv_uart_t m_uart = NRF_DRV_UART_INSTANCE(0); +static uint8_t m_rx_byte; + +static nrf_dfu_serial_t m_serial; +static slip_t m_slip; +static uint8_t m_rsp_buf[NRF_UART_MAX_RESPONSE_SIZE_SLIP]; +static bool m_active; + +static nrf_dfu_observer_t m_observer; + +static uint32_t uart_dfu_transport_init(nrf_dfu_observer_t observer); +static uint32_t uart_dfu_transport_close(nrf_dfu_transport_t const * p_exception); + +DFU_TRANSPORT_REGISTER(nrf_dfu_transport_t const uart_dfu_transport) = +{ + .init_func = uart_dfu_transport_init, + .close_func = uart_dfu_transport_close, +}; + +static void payload_free(void * p_buf) +{ + uint8_t * p_buf_root = (uint8_t *)p_buf - DATA_OFFSET; //pointer is shifted to point to data + nrf_balloc_free(&m_payload_pool, p_buf_root); +} + +static ret_code_t rsp_send(uint8_t const * p_data, uint32_t length) +{ + uint32_t slip_len; + (void) slip_encode(m_rsp_buf, (uint8_t *)p_data, length, &slip_len); + + return nrf_drv_uart_tx(&m_uart, m_rsp_buf, slip_len); +} + +static __INLINE void on_rx_complete(nrf_dfu_serial_t * p_transport, uint8_t * p_data, uint8_t len) +{ + ret_code_t ret_code; + + ret_code = slip_decode_add_byte(&m_slip, p_data[0]); + (void) nrf_drv_uart_rx(&m_uart, &m_rx_byte, 1); + + if (ret_code == NRF_SUCCESS) + { + // Activity detected on current transport, close all except active one. + UNUSED_RETURN_VALUE(nrf_dfu_transports_close(&uart_dfu_transport)); + + nrf_dfu_serial_on_packet_received(p_transport, + (uint8_t const *)m_slip.p_buffer, + m_slip.current_index); + + uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool); + if (p_rx_buf == NULL) + { + NRF_LOG_ERROR("Failed to allocate buffer"); + return; + } + NRF_LOG_INFO("Allocated buffer %x", p_rx_buf); + // reset the slip decoding + m_slip.p_buffer = &p_rx_buf[OPCODE_OFFSET]; + m_slip.current_index = 0; + m_slip.state = SLIP_STATE_DECODING; + } + +} + +static void uart_event_handler(nrf_drv_uart_event_t * p_event, void * p_context) +{ + switch (p_event->type) + { + case NRF_DRV_UART_EVT_RX_DONE: + on_rx_complete((nrf_dfu_serial_t*)p_context, + p_event->data.rxtx.p_data, + p_event->data.rxtx.bytes); + break; + + case NRF_DRV_UART_EVT_ERROR: + APP_ERROR_HANDLER(p_event->data.error.error_mask); + break; + + default: + // No action. + break; + } +} + +static uint32_t uart_dfu_transport_init(nrf_dfu_observer_t observer) +{ + uint32_t err_code = NRF_SUCCESS; + + if (m_active) + { + return err_code; + } + + NRF_LOG_DEBUG("serial_dfu_transport_init()"); + + m_observer = observer; + + err_code = nrf_balloc_init(&m_payload_pool); + if (err_code != NRF_SUCCESS) + { + return err_code; + } + + uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool); + + m_slip.p_buffer = &p_rx_buf[OPCODE_OFFSET]; + m_slip.current_index = 0; + m_slip.buffer_len = UART_SLIP_MTU; + m_slip.state = SLIP_STATE_DECODING; + + m_serial.rsp_func = rsp_send; + m_serial.payload_free_func = payload_free; + m_serial.mtu = UART_SLIP_MTU; + m_serial.p_rsp_buf = &m_rsp_buf[NRF_UART_MAX_RESPONSE_SIZE_SLIP - + NRF_SERIAL_MAX_RESPONSE_SIZE]; + + nrf_drv_uart_config_t uart_config = NRF_DRV_UART_DEFAULT_CONFIG; + + uart_config.pseltxd = TX_PIN_NUMBER; + uart_config.pselrxd = RX_PIN_NUMBER; + uart_config.pselcts = CTS_PIN_NUMBER; + uart_config.pselrts = RTS_PIN_NUMBER; + uart_config.hwfc = NRF_DFU_SERIAL_UART_USES_HWFC ? + NRF_UART_HWFC_ENABLED : NRF_UART_HWFC_DISABLED; + uart_config.p_context = &m_serial; + + err_code = nrf_drv_uart_init(&m_uart, &uart_config, uart_event_handler); + if (err_code != NRF_SUCCESS) + { + NRF_LOG_ERROR("Failed initializing uart"); + return err_code; + } + + err_code = nrf_drv_uart_rx(&m_uart, &m_rx_byte, 1); + if (err_code != NRF_SUCCESS) + { + NRF_LOG_ERROR("Failed initializing rx"); + } + + NRF_LOG_DEBUG("serial_dfu_transport_init() completed"); + + m_active = true; + + if (m_observer) + { + m_observer(NRF_DFU_EVT_TRANSPORT_ACTIVATED); + } + + return err_code; +} + + +static uint32_t uart_dfu_transport_close(nrf_dfu_transport_t const * p_exception) +{ + if ((m_active == true) && (p_exception != &uart_dfu_transport)) + { + nrf_drv_uart_uninit(&m_uart); + m_active = false; + } + + return NRF_SUCCESS; +} + diff --git a/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/serial_dfu/nrf_dfu_serial_usb.c b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/serial_dfu/nrf_dfu_serial_usb.c new file mode 100644 index 0000000..2b45643 --- /dev/null +++ b/thirdparty/nRF5_SDK_15.0.0_a53641a/components/libraries/bootloader/serial_dfu/nrf_dfu_serial_usb.c @@ -0,0 +1,370 @@ +/** + * 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 <string.h> +#include "nrf_dfu_req_handler.h" +#include "nrf_dfu_transport.h" +#include "slip.h" +#include "nrf_balloc.h" +#include "nrf_drv_power.h" +#include "nrf_drv_clock.h" +#include "nrf_drv_usbd.h" +#include "nrf_dfu_serial.h" +#include "app_scheduler.h" +#include "app_usbd.h" +#include "app_usbd_cdc_acm.h" +#include "app_usbd_core.h" +#include "app_usbd_string_desc.h" +#include "app_util_platform.h" +#include "app_usbd_serial_num.h" + +#define NRF_LOG_MODULE_NAME nrf_dfu_serial_usb +#include "nrf_log.h" +NRF_LOG_MODULE_REGISTER(); + +/**@file + * + * @defgroup nrf_dfu_serial_usb DFU Serial USB CDC ACM transport + * @ingroup nrf_dfu + * @brief Device Firmware Update (DFU) transport layer using USB CDC ACM. + */ + +#define NRF_SERIAL_OPCODE_SIZE (sizeof(uint8_t)) + +#define NRF_USB_MAX_RESPONSE_SIZE_SLIP (2 * NRF_SERIAL_MAX_RESPONSE_SIZE + 1) + +#define RX_BUF_SIZE (1024) +#define SLIP_MTU (2 * (RX_BUF_SIZE + 1) + 1) +#define OPCODE_OFFSET (sizeof(uint32_t) - NRF_SERIAL_OPCODE_SIZE) +#define DATA_OFFSET (OPCODE_OFFSET + NRF_SERIAL_OPCODE_SIZE) + +#define CDC_ACM_COMM_INTERFACE 0 +#define CDC_ACM_COMM_EPIN NRF_DRV_USBD_EPIN2 +#define CDC_ACM_DATA_INTERFACE 1 +#define CDC_ACM_DATA_EPIN NRF_DRV_USBD_EPIN1 +#define CDC_ACM_DATA_EPOUT NRF_DRV_USBD_EPOUT1 + +/** + * @brief Enable power USB detection + * + * Configure if example supports USB port connection + */ +#ifndef USBD_POWER_DETECTION +#define USBD_POWER_DETECTION true +#endif + +/** + * @brief Interfaces list passed to @ref APP_USBD_CDC_ACM_GLOBAL_DEF + * */ +#define CDC_ACM_INTERFACES_CONFIG() \ + APP_USBD_CDC_ACM_CONFIG(CDC_ACM_COMM_INTERFACE, \ + CDC_ACM_COMM_EPIN, \ + CDC_ACM_DATA_INTERFACE, \ + CDC_ACM_DATA_EPIN, \ + CDC_ACM_DATA_EPOUT) + +/*lint -save -e26 -e64 -e505 -e651 */ +static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst, + app_usbd_cdc_acm_user_event_t event); + +/**@brief CDC_ACM class instance. */ +APP_USBD_CDC_ACM_GLOBAL_DEF(m_app_cdc_acm, + cdc_acm_user_ev_handler, + CDC_ACM_COMM_INTERFACE, + CDC_ACM_DATA_INTERFACE, + CDC_ACM_COMM_EPIN, + CDC_ACM_DATA_EPIN, + CDC_ACM_DATA_EPOUT, + APP_USBD_CDC_COMM_PROTOCOL_NONE); +/*lint -restore */ + +NRF_BALLOC_DEF(m_payload_pool, (SLIP_MTU+1), NRF_DFU_SERIAL_USB_RX_BUFFERS); + +static nrf_dfu_serial_t m_serial; +static slip_t m_slip; +static uint8_t m_rsp_buf[NRF_USB_MAX_RESPONSE_SIZE_SLIP]; +static uint8_t m_rx_buf[NRF_DRV_USBD_EPSIZE]; + +static nrf_dfu_observer_t m_observer; + +static uint32_t usb_dfu_transport_init(nrf_dfu_observer_t observer); +static uint32_t usb_dfu_transport_close(nrf_dfu_transport_t const * p_exception); + + +DFU_TRANSPORT_REGISTER(nrf_dfu_transport_t const usb_dfu_transport) = +{ + .init_func = usb_dfu_transport_init, + .close_func = usb_dfu_transport_close, +}; + + +static void payload_free(void * p_buf) +{ + uint8_t * p_buf_root = ((uint8_t *)(p_buf)) - DATA_OFFSET; //pointer is shifted to point to data + nrf_balloc_free(&m_payload_pool, p_buf_root); +} + + +static ret_code_t rsp_send(uint8_t const * p_data, uint32_t length) +{ + ASSERT(p_data); + ASSERT(length != 0); + + uint32_t slip_len; + + // Cannot fail if inputs are non-NULL. + (void) slip_encode(m_rsp_buf, (uint8_t *)(p_data), length, &slip_len); + + return app_usbd_cdc_acm_write(&m_app_cdc_acm, m_rsp_buf, slip_len); +} + + +static void on_rx_complete(nrf_dfu_serial_t * p_transport, uint8_t * p_data, uint8_t len) +{ + ret_code_t ret_code; + + for (uint32_t i = 0; i < len; i++) + { + ret_code = slip_decode_add_byte(&m_slip, p_data[i]); + if (ret_code != NRF_SUCCESS) + { + continue; + } + + // Activity detected on current transport, close all except active one. + (void) nrf_dfu_transports_close(&usb_dfu_transport); + + nrf_dfu_serial_on_packet_received(p_transport, + (uint8_t const *)(m_slip.p_buffer), + m_slip.current_index); + + uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool); + if (p_rx_buf == NULL) + { + NRF_LOG_ERROR("Failed to allocate buffer!"); + return; + } + + NRF_LOG_DEBUG("Allocated buffer %x", p_rx_buf); + // reset the slip decoding + m_slip.p_buffer = &p_rx_buf[OPCODE_OFFSET]; + m_slip.current_index = 0; + m_slip.state = SLIP_STATE_DECODING; + } +} + +/** + * @brief User event handler @ref app_usbd_cdc_acm_user_ev_handler_t (headphones) + * */ +static void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst, + app_usbd_cdc_acm_user_event_t event) +{ + ret_code_t ret_code; + + switch (event) + { + case APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN: + { + ret_code = app_usbd_cdc_acm_read(&m_app_cdc_acm, m_rx_buf, 1); + NRF_LOG_WARNING("Could not read from CDC. Error: 0x%x.", ret_code); + } break; + + case APP_USBD_CDC_ACM_USER_EVT_RX_DONE: + { + do + { + on_rx_complete(&m_serial, m_rx_buf, 1); + ret_code = app_usbd_cdc_acm_read(&m_app_cdc_acm, m_rx_buf, 1); + } while (ret_code == NRF_SUCCESS); + } break; + + default: + break; + } +} + + +static void usbd_dfu_transport_ev_handler(app_usbd_event_type_t event) +{ + switch (event) + { + case APP_USBD_EVT_STOPPED: + app_usbd_disable(); + break; + + case APP_USBD_EVT_POWER_DETECTED: + NRF_LOG_INFO("USB power detected"); + if (!nrf_drv_usbd_is_enabled()) + { + app_usbd_enable(); + } + + if (m_observer) + { + m_observer(NRF_DFU_EVT_TRANSPORT_ACTIVATED); + } + break; + + case APP_USBD_EVT_POWER_REMOVED: + NRF_LOG_INFO("USB power removed"); + app_usbd_stop(); + if (m_observer) + { + m_observer(NRF_DFU_EVT_TRANSPORT_DEACTIVATED); + } + break; + + case APP_USBD_EVT_POWER_READY: + NRF_LOG_INFO("USB ready"); + app_usbd_start(); + break; + + default: + break; + } +} + + +static void usbd_sched_event_handler(void * p_event_data, uint16_t event_size) +{ + app_usbd_event_execute(p_event_data); +} + + +static void usbd_event_handler(app_usbd_internal_evt_t const * const p_event) +{ + ret_code_t ret_code; + if (p_event->type == APP_USBD_EVT_DRV_SOF) + { + app_usbd_event_execute(p_event); + } + else + { + ret_code = app_sched_event_put(p_event, + sizeof(app_usbd_internal_evt_t), + usbd_sched_event_handler); + + if (ret_code != NRF_SUCCESS) + { + NRF_LOG_ERROR("Could not schedule USB event!"); + } + } +} + + +static uint32_t usb_dfu_transport_init(nrf_dfu_observer_t observer) +{ + uint32_t err_code; + + /* Execute event directly in interrupt handler */ + static const app_usbd_config_t usbd_config = + { + .ev_handler = usbd_event_handler, + .ev_state_proc = usbd_dfu_transport_ev_handler + }; + + (void) nrf_balloc_init(&m_payload_pool); //Result is checked by checking result of _alloc(). + + m_observer = observer; + + uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool); + if (p_rx_buf == NULL) + { + NRF_LOG_ERROR("Could not allocate payload pool."); + return NRF_ERROR_INTERNAL; + } + + m_slip.p_buffer = &p_rx_buf[OPCODE_OFFSET]; + m_slip.current_index = 0; + m_slip.buffer_len = SLIP_MTU; + m_slip.state = SLIP_STATE_DECODING; + + m_serial.rsp_func = rsp_send; + m_serial.payload_free_func = payload_free; + m_serial.mtu = SLIP_MTU; + m_serial.p_rsp_buf = &m_rsp_buf[NRF_USB_MAX_RESPONSE_SIZE_SLIP - + NRF_SERIAL_MAX_RESPONSE_SIZE]; + + + NRF_LOG_DEBUG("Initializing drivers."); + + err_code = nrf_drv_clock_init(); + if (err_code != NRF_ERROR_MODULE_ALREADY_INITIALIZED) + { + VERIFY_SUCCESS(err_code); + } + + err_code = nrf_drv_power_init(NULL); + VERIFY_SUCCESS(err_code); + + app_usbd_serial_num_generate(); + + err_code = app_usbd_init(&usbd_config); + VERIFY_SUCCESS(err_code); + + app_usbd_class_inst_t const * class_cdc_acm = app_usbd_cdc_acm_class_inst_get(&m_app_cdc_acm); + err_code = app_usbd_class_append(class_cdc_acm); + VERIFY_SUCCESS(err_code); + + NRF_LOG_DEBUG("Starting USB"); + + if (USBD_POWER_DETECTION) + { + err_code = app_usbd_power_events_enable(); + VERIFY_SUCCESS(err_code); + } + else + { + NRF_LOG_DEBUG("No USB power detection enabled, starting USB now"); + + app_usbd_enable(); + app_usbd_start(); + } + + NRF_LOG_DEBUG("USB Transport initialized"); + + return err_code; +} + + +static uint32_t usb_dfu_transport_close(nrf_dfu_transport_t const * p_exception) +{ + return NRF_SUCCESS; +} |