初始版本

This commit is contained in:
xiaozhengsheng
2025-08-19 09:49:41 +08:00
parent 10f1ddf1c1
commit 6df0f7d96e
2974 changed files with 1712873 additions and 54 deletions

View File

@@ -0,0 +1,772 @@
/**
* This software is subject to the ANT+ Shared Source License
* www.thisisant.com/swlicenses
* Copyright (c) Garmin Canada Inc. 2018
* 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 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 Garmin nor the names of its
* contributors may be used to endorse or promote products
* derived from this software without specific prior
* written permission.
*
* The following actions are prohibited:
*
* 1) Redistribution of source code containing the ANT+ Network
* Key. The ANT+ Network Key is available to ANT+ Adopters.
* Please refer to http://thisisant.com to become an ANT+
* Adopter and access the key.
*
* 2) Reverse engineering, decompilation, and/or disassembly of
* software provided in binary form under this license.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE HEREBY
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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; DAMAGE TO ANY DEVICE, 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. SOME STATES DO NOT ALLOW
* THE EXCLUSION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THE
* ABOVE LIMITATIONS MAY NOT APPLY TO YOU.
*
*/
#include <stdbool.h>
#include <stdint.h>
#include "sdk_common.h"
#include "ant_channel_config.h"
#include "ant_interface.h"
#include "ant_parameters.h"
#include "nrf_assert.h"
#include "nrf_balloc.h"
#include "nrf_bootloader_info.h"
#include "nrf_dfu_handling_error.h"
#include "nrf_dfu_req_handler.h"
#include "nrf_dfu_transport.h"
#include "nrf_dfu_mbr.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ant.h"
#include "nrf_soc.h"
#define NRF_LOG_MODULE_NAME nrf_dfu_ant
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
/**@file
*
* @defgroup nrf_dfu_ant ANT transport for reference DFU.
* @ingroup nrf_dfu
* @brief Device Firmware Update (DFU) transport layer using ANT.
*
* Transport documentation:
*
* The ANT transport uses all of the same opcodes and payload formats as the
* UART serial transport. The only differences are the packet header format and
* some extra details to deal with retransmissions.
*
* The device receiving the update is the ANT master. The format of the
* broadcast buffer is as follows;
* Byte 0: Current Slave -> Master sequence number.
* Byte 1: Current Master -> Slave sequence number.
* Bytes 2-7: Reserved, set to 0.
*
* The sequence numbers are used to detect retransmissions, any messages sent
* with a sequence number equivalent to the current sequence will be ignored.
*
* When the slave first connects to the master it should inspect the broadcast
* data in order to synchronize its sequence counters.
*
* All commands/responses are padded out to the nearest 8-byte boundary after
* framing, and then sent using either a burst or acknowledged data depending on
* length (ack data is used for 8-byte messages). The message transmission is
* retried until an EVENT_TRANSFER_TX_COMPLETE event is received.
* All messages are framed using the following format:
* Bytes 0-1: Message length before padding, little endian, includes header.
* Byte 2: Sequence number. Increment for every new message.
* Byte 3: Op code. Always 0x60 for responses.
* Bytes 4-N: Command/Response payload. This follows the same format as the
* UART serial transport, without any SLIP encoding.
*
* As a final note, the MTU for this protocol is the maximum size of a burst
* that can be received.
*/
/** Packet header is always 2 byte length + seq num + op code */
#define PKT_HEADER_SIZE 4
/** Maximum size of the payload in a write command. */
#define MAX_WRITE_PAYLOAD (NRF_DFU_ANT_MTU - PKT_HEADER_SIZE)
/** Bursts are always a multiple of the standard data size. */
STATIC_ASSERT_MSG(
ALIGN_NUM(ANT_STANDARD_DATA_PAYLOAD_SIZE, NRF_DFU_ANT_MTU) == NRF_DFU_ANT_MTU,
"ANT MTU must be a multiple of " STRINGIFY(ANT_STANDARD_DATA_PAYLOAD_SIZE));
/** Number of buffers to reserve space for with balloc. */
#if (NRF_DFU_ANT_BUFFERS_OVERRIDE)
#define NUM_BUFFERS NRF_DFU_ANT_BUFFERS
#else
#define NUM_BUFFERS CEIL_DIV(CODE_PAGE_SIZE, MAX_WRITE_PAYLOAD)
#endif
static uint32_t ant_dfu_init(nrf_dfu_observer_t observer);
static uint32_t ant_dfu_close(nrf_dfu_transport_t const * p_exception);
static ant_channel_config_t m_channel_config = {
.channel_number = 0,
.channel_type = CHANNEL_TYPE_MASTER,
.rf_freq = NRF_DFU_ANT_RF_FREQ,
.transmission_type = 1, // Non-shared, no global pages.
.device_type = NRF_DFU_ANT_DEV_TYPE,
.channel_period = NRF_DFU_ANT_CHANNEL_PERIOD,
};
static nrf_dfu_observer_t m_observer;
/** Has transport been initialized by DFU core */
static bool m_initialized = false;
/** Has the channel started broadcasting */
static bool m_started = false;
/** Has some data been received on the transport. */
static bool m_active = false;
/** State tracking for rx transfers. */
static struct
{
/** Buffer for holding the command. */
uint8_t * buff;
/** Amount of data written */
size_t offset;
/** Sequence of last processed command. */
uint8_t seq;
} m_rx;
/** State tracking for tx transfers. */
static struct
{
/** Raw data to send. */
uint8_t resp[ALIGN_NUM(ANT_STANDARD_DATA_PAYLOAD_SIZE,
PKT_HEADER_SIZE + sizeof(nrf_dfu_response_t))];
/** Length of data to send. 0 Indicates no response queued. */
size_t len;
/** Sequence number of last queued response. */
uint8_t seq;
/**
* Used as burst flag for softdevice, allows to busy loop until all data is
* accepted by softdevice.
*/
volatile bool buffering;
/**
* Indicate that a new response was generated before the last one was
* confirmed.
*/
bool response_overwritten;
/** Data buffer used for broadcast messages. */
uint8_t bcast_data[ANT_STANDARD_DATA_PAYLOAD_SIZE];
} m_tx;
/** State tracking for progress notifications. */
static struct
{
/** Requested PRN */
uint16_t limit;
/** How many more write commands until a CRC should be sent back. */
uint16_t remaining;
} m_pkt_notify;
DFU_TRANSPORT_REGISTER(nrf_dfu_transport_t const ant_dfu_transport) = {
.init_func = ant_dfu_init,
.close_func = ant_dfu_close,
};
NRF_BALLOC_DEF(m_buffer_pool, NRF_DFU_ANT_MTU, NUM_BUFFERS);
static void release_rx_buff(void)
{
if (m_rx.buff != NULL)
{
nrf_balloc_free(&m_buffer_pool, m_rx.buff);
m_rx.buff = NULL;
}
}
static void transmit_response(void)
{
uint32_t err_code = NRF_SUCCESS;
size_t full_len = ALIGN_NUM(ANT_STANDARD_DATA_PAYLOAD_SIZE, m_tx.len);
// Pad out with 0's.
memset(&m_tx.resp[m_tx.len], 0, full_len - m_tx.len);
if (full_len > ANT_STANDARD_DATA_PAYLOAD_SIZE)
{
err_code = sd_ant_burst_handler_request(
m_channel_config.channel_number,
full_len, m_tx.resp,
BURST_SEGMENT_START | BURST_SEGMENT_END);
} else
{
err_code = sd_ant_acknowledge_message_tx(
m_channel_config.channel_number,
full_len, m_tx.resp);
}
// Wait for buffer to be consumed.
// TODO: wait flag management needs to be improved if this will coexist with
// other channels.
while (err_code == NRF_SUCCESS && m_tx.buffering)
{
err_code = sd_app_evt_wait();
}
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Sending response failed with error %d", err_code);
}
}
static void update_bcast_data(void)
{
memset(m_tx.bcast_data, 0, sizeof(m_tx.bcast_data));
m_tx.bcast_data[0] = m_rx.seq;
m_tx.bcast_data[1] = m_tx.seq;
if (NRF_SUCCESS != sd_ant_broadcast_message_tx(
m_channel_config.channel_number,
sizeof(m_tx.bcast_data), m_tx.bcast_data))
{
NRF_LOG_WARNING("Unable to update broadcast data.");
}
}
static void handle_write_complete(void * p_buf)
{
nrf_balloc_free(&m_buffer_pool, p_buf);
}
static void prepare_response(nrf_dfu_response_t * p_res)
{
if (m_tx.len)
{
NRF_LOG_WARNING("Overwriting previous response.");
m_tx.response_overwritten = true;
}
// reserve first 2 bytes for length.
m_tx.len = 2;
m_tx.resp[m_tx.len++] = ++(m_tx.seq);
m_tx.resp[m_tx.len++] = NRF_DFU_OP_RESPONSE;
m_tx.resp[m_tx.len++] = p_res->request;
m_tx.resp[m_tx.len++] = p_res->result;
if (p_res->result == NRF_DFU_RES_CODE_SUCCESS)
{
switch(p_res->request)
{
case NRF_DFU_OP_PROTOCOL_VERSION:
{
m_tx.resp[m_tx.len++] = p_res->protocol.version;
} break;
case NRF_DFU_OP_CRC_GET:
{
m_tx.len += uint32_encode(
p_res->crc.offset, &m_tx.resp[m_tx.len]);
m_tx.len += uint32_encode(
p_res->crc.crc, &m_tx.resp[m_tx.len]);
} break;
case NRF_DFU_OP_OBJECT_SELECT:
{
m_tx.len += uint32_encode(
p_res->select.max_size, &m_tx.resp[m_tx.len]);
m_tx.len += uint32_encode(
p_res->select.offset, &m_tx.resp[m_tx.len]);
m_tx.len += uint32_encode(
p_res->select.crc, &m_tx.resp[m_tx.len]);
} break;
case NRF_DFU_OP_MTU_GET:
{
m_tx.len += uint16_encode(
p_res->mtu.size, &m_tx.resp[m_tx.len]);
} break;
case NRF_DFU_OP_PING:
{
m_tx.resp[m_tx.len++] = p_res->ping.id;
} break;
case NRF_DFU_OP_HARDWARE_VERSION:
{
m_tx.len += uint32_encode(
p_res->hardware.part, &m_tx.resp[m_tx.len]);
m_tx.len += uint32_encode(
p_res->hardware.variant, &m_tx.resp[m_tx.len]);
m_tx.len += uint32_encode(
p_res->hardware.memory.rom_size, &m_tx.resp[m_tx.len]);
m_tx.len += uint32_encode(
p_res->hardware.memory.rom_page_size, &m_tx.resp[m_tx.len]);
m_tx.len += uint32_encode(
p_res->hardware.memory.ram_size, &m_tx.resp[m_tx.len]);
} break;
case NRF_DFU_OP_FIRMWARE_VERSION:
{
m_tx.resp[m_tx.len++] = p_res->firmware.type;
m_tx.len += uint32_encode(
p_res->firmware.version, &m_tx.resp[m_tx.len]);
m_tx.len += uint32_encode(
p_res->firmware.addr, &m_tx.resp[m_tx.len]);
m_tx.len += uint32_encode(
p_res->firmware.len, &m_tx.resp[m_tx.len]);
} break;
default:
break;
}
}
else if (p_res->result == NRF_DFU_RES_CODE_EXT_ERROR)
{
m_tx.resp[m_tx.len++] = ext_error_get();
UNUSED_RETURN_VALUE(ext_error_set(NRF_DFU_EXT_ERROR_NO_ERROR));
}
// Finally fill in the length.
UNUSED_RETURN_VALUE(uint16_encode(m_tx.len, m_tx.resp));
// Safety check buffer overflow.
ASSERT(m_tx.len <= sizeof(m_tx.resp));
if (!m_tx.response_overwritten)
{
// Can send out the response immediately if there wasn't a previous one
// queued.
transmit_response();
}
}
static void handle_response(nrf_dfu_response_t * p_res, void * p_context)
{
UNUSED_PARAMETER(p_context);
if (p_res->result != NRF_DFU_RES_CODE_SUCCESS)
{
NRF_LOG_WARNING("Operation %d had result %d",
p_res->request, p_res->result);
}
if (p_res->request == NRF_DFU_OP_OBJECT_WRITE)
{
if (m_pkt_notify.limit == 0 ||
--m_pkt_notify.remaining != 0)
{
// No packet notification needed, filter out response.
return;
}
// Packet Notification time, send a CRC response.
m_pkt_notify.remaining = m_pkt_notify.limit;
p_res->request = NRF_DFU_OP_CRC_GET;
uint32_t offset = p_res->write.offset;
uint32_t crc = p_res->write.crc;
p_res->crc.offset = offset;
p_res->crc.crc = crc;
}
prepare_response(p_res);
}
static uint32_t handle_request(void)
{
uint16_t len = uint16_decode(m_rx.buff);
uint16_t offset = sizeof(uint16_t);
if (len < PKT_HEADER_SIZE || len > m_rx.offset)
{
NRF_LOG_WARNING("Ignoring command with invalid length.");
return NRF_ERROR_DATA_SIZE;
}
uint8_t seq = m_rx.buff[offset++];
if (!m_active)
{
m_active = true;
// Close all other transports.
UNUSED_RETURN_VALUE(nrf_dfu_transports_close(&ant_dfu_transport));
}
else if (seq == m_rx.seq)
{
NRF_LOG_DEBUG("Ignoring repeated command");
return NRF_SUCCESS;
}
m_rx.seq = seq;
nrf_dfu_request_t request = {
.request = (nrf_dfu_op_t)m_rx.buff[offset++],
.callback.response = handle_response,
};
switch(request.request)
{
case NRF_DFU_OP_OBJECT_CREATE:
{
request.create.object_type = m_rx.buff[offset++];
request.create.object_size = uint32_decode(&m_rx.buff[offset]);
offset += sizeof(uint32_t);
} break;
case NRF_DFU_OP_RECEIPT_NOTIF_SET:
{
request.prn.target = uint16_decode(&m_rx.buff[offset]);
offset += sizeof(uint16_t);
} break;
case NRF_DFU_OP_OBJECT_SELECT:
{
request.select.object_type = m_rx.buff[offset++];
} break;
case NRF_DFU_OP_OBJECT_WRITE:
{
request.write.p_data = &m_rx.buff[offset];
request.write.len = len - offset;
offset = len;
} break;
case NRF_DFU_OP_PING:
{
request.ping.id = m_rx.buff[offset++];
} break;
case NRF_DFU_OP_FIRMWARE_VERSION:
{
request.firmware.image_number = m_rx.buff[offset++];
} break;
case NRF_DFU_OP_MTU_GET:
{
NRF_LOG_DEBUG("ANT DFU: Responding to MTU request with %d",
NRF_DFU_ANT_MTU);
request.mtu.size = NRF_DFU_ANT_MTU;
} break;
default:
// Do nothing.
break;
}
if (offset > len)
{
NRF_LOG_WARNING("Ignoring command with invalid length");
return NRF_ERROR_DATA_SIZE;
}
// Some processing that is only safe to do if accepting the command.
switch (request.request)
{
case NRF_DFU_OP_RECEIPT_NOTIF_SET:
{
m_pkt_notify.limit = request.prn.target;
m_pkt_notify.remaining = m_pkt_notify.limit;
} break;
case NRF_DFU_OP_OBJECT_CREATE:
case NRF_DFU_OP_OBJECT_SELECT:
{
m_pkt_notify.remaining = m_pkt_notify.limit;
} break;
case NRF_DFU_OP_OBJECT_WRITE:
{
// Ownership of buffer is transferred to the write command.
request.callback.write = handle_write_complete;
m_rx.buff = NULL;
} break;
default:
break;
}
return nrf_dfu_req_handler_on_req(&request);
}
static void handle_tx_transfer_complete(bool success)
{
if (m_tx.response_overwritten)
{
// By treating the result as a failure the retransmission will send out
// the new response.
success = false;
m_tx.response_overwritten = false;
}
if (success)
{
m_tx.len = 0;
update_bcast_data();
}
else
{
transmit_response();
}
}
static void handle_rx_transfer_start()
{
if (m_rx.buff == NULL)
{
m_rx.buff = nrf_balloc_alloc(&m_buffer_pool);
if (m_rx.buff != NULL)
{
NRF_LOG_INFO("Allocated buffer %x", m_rx.buff);
}
else
{
NRF_LOG_ERROR("Unable to allocate buffer for incoming packet.");
return;
}
}
NRF_LOG_DEBUG("Resetting rx pointer.");
m_rx.offset = 0;
}
static void handle_rx_transfer_complete(bool success)
{
if (success)
{
uint32_t err_code = handle_request();
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Error %d handling request.", err_code);
}
}
release_rx_buff();
}
static void handle_rx_transfer_data(uint8_t * data, size_t len)
{
if (m_rx.buff == NULL)
{
NRF_LOG_DEBUG("Ignoring transfer data.");
return;
}
if (m_rx.offset + len > NRF_DFU_ANT_MTU)
{
NRF_LOG_ERROR("Received packet overflows MTU.");
handle_rx_transfer_complete(false);
return;
}
memcpy(&m_rx.buff[m_rx.offset], data, len);
m_rx.offset += len;
}
static void handle_data_mesg(ANT_MESSAGE * p_msg)
{
bool is_first = false;
bool is_last = false;
uint8_t len = ANT_STANDARD_DATA_PAYLOAD_SIZE;
switch(p_msg->ANT_MESSAGE_ucMesgID)
{
case MESG_BROADCAST_DATA_ID:
{
// Broadcast data is ignored.
len = 0;
} break;
case MESG_ACKNOWLEDGED_DATA_ID:
{
is_first = true;
is_last = true;
} break;
case MESG_ADV_BURST_DATA_ID:
{
len = p_msg->ANT_MESSAGE_ucSize - MESG_CHANNEL_NUM_SIZE;
} // FALL-THROUGH : both burst types act the same other than len.
case MESG_BURST_DATA_ID:
{
uint8_t seq = p_msg->ANT_MESSAGE_ucChannel & SEQUENCE_NUMBER_MASK;
is_first = seq == SEQUENCE_FIRST_MESSAGE;
is_last = !!(seq & SEQUENCE_LAST_MESSAGE);
} break;
}
if (len != 0)
{
if (is_first)
{
handle_rx_transfer_start();
}
handle_rx_transfer_data(p_msg->ANT_MESSAGE_aucPayload, len);
if (is_last)
{
handle_rx_transfer_complete(true);
}
}
}
static void ant_dfu_evt_handler(ant_evt_t * p_ant_evt, void * p_context)
{
// Ignore messages meant for other channels.
if (p_ant_evt->channel != m_channel_config.channel_number)
{
return;
}
switch(p_ant_evt->event)
{
case EVENT_TX:
{
if (!m_started)
{
m_started = true;
m_observer(NRF_DFU_EVT_TRANSPORT_ACTIVATED);
}
} break;
case EVENT_TRANSFER_TX_COMPLETED:
handle_tx_transfer_complete(true);
break;
case EVENT_TRANSFER_TX_FAILED:
handle_tx_transfer_complete(false);
break;
case EVENT_RX:
handle_data_mesg(&p_ant_evt->message);
break;
case EVENT_TRANSFER_RX_FAILED:
handle_rx_transfer_complete(false);
break;
}
}
static uint32_t ant_dfu_init(nrf_dfu_observer_t observer)
{
uint32_t err_code = NRF_SUCCESS;
if (m_initialized)
{
return err_code;
}
NRF_SDH_ANT_OBSERVER(ant_dfu_observer, NRF_DFU_ANT_EVT_HANDLER_PRIO,
ant_dfu_evt_handler, NULL);
m_observer = observer;
m_tx.seq = m_rx.seq = 0;
m_active = false;
m_started = false;
NRF_LOG_DEBUG("Initializing ANT DFU transport");
err_code = nrf_balloc_init(&m_buffer_pool);
VERIFY_SUCCESS(err_code);
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);
err_code = nrf_sdh_ant_enable();
VERIFY_SUCCESS(err_code);
static uint8_t adv_burst_conf[] = {
ADV_BURST_MODE_ENABLE,
ADV_BURST_MODES_SIZE_24_BYTES,
0, // No required modes.
0, 0, // Reserved
ADV_BURST_MODES_FREQ_HOP, // Optional Modes
0, 0, // Reserved
// No optional configs.
};
err_code = sd_ant_adv_burst_config_set(adv_burst_conf, sizeof(adv_burst_conf));
VERIFY_SUCCESS(err_code);
m_channel_config.device_number = NRF_FICR->DEVICEID[0];
m_channel_config.transmission_type |= (NRF_FICR->DEVICEID[1] & 0xF) << 4;
err_code = ant_channel_init(&m_channel_config);
VERIFY_SUCCESS(err_code);
update_bcast_data();
err_code = sd_ant_channel_open(m_channel_config.channel_number);
VERIFY_SUCCESS(err_code);
NRF_LOG_DEBUG("ANT transport intialized");
m_initialized = true;
return err_code;
}
static uint32_t ant_dfu_close(nrf_dfu_transport_t const * p_exception)
{
uint32_t err_code = NRF_SUCCESS;
if (p_exception != &ant_dfu_transport && m_initialized)
{
NRF_LOG_DEBUG("Shutting down ANT DFU transport");
m_initialized = false;
err_code = sd_ant_channel_close(m_channel_config.channel_number);
VERIFY_SUCCESS(err_code);
uint8_t status;
do
{
// The initial wait is safe because the close command above would
// have generated at least 1 app event.
err_code = sd_app_evt_wait();
VERIFY_SUCCESS(err_code);
err_code = sd_ant_channel_status_get(
m_channel_config.channel_number, &status);
VERIFY_SUCCESS(err_code);
} while ((status & STATUS_CHANNEL_STATE_MASK) != STATUS_ASSIGNED_CHANNEL);
err_code = nrf_sdh_disable_request();
VERIFY_SUCCESS(err_code);
NRF_LOG_DEBUG("ANT transport disabled.");
}
return err_code;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,121 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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;
/**@brief Function for initializing the BLE transport.
*
* @param[in] observer Callback function for receiving notifications from the BLE transport.
*
* @retval NRF_SUCCESS If successful.
* @return Error code from sub-call on error.
*/
uint32_t ble_dfu_transport_init(nrf_dfu_observer_t observer);
/**@brief Function for closing the BLE transport.
*
* This function disconnects and disables the SoftDevice.
*
* @param[in] p_exception Optional exception. If the exception refers to this transport,
* this function will do nothing. Can be NULL to signify no exception.
*
* @retval NRF_SUCCESS If successful.
* @return Error code from sub-call on error.
*/
uint32_t ble_dfu_transport_close(nrf_dfu_transport_t const * p_exception);
/**@brief Function for disconnecting from the BLE peer and starting advertising.
*
* @retval NRF_SUCCESS If successful.
* @return Error code from sub-call on error.
*/
uint32_t ble_dfu_transport_disconnect(void);
#ifdef __cplusplus
}
#endif
#endif // NRF_DFU_BLE_H__
/** @} */

View File

@@ -0,0 +1,95 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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__
/** @} */

View File

@@ -0,0 +1,5 @@
dfu.Hash.hash max_size:32
dfu.SignedCommand.signature max_size:64
dfu.InitCommand.sd_req max_count:16
dfu.InitCommand.boot_validation max_count:3
dfu.BootValidation.bytes max_size:64

View File

@@ -0,0 +1,123 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/* Automatically generated nanopb constant definitions */
/* Generated by nanopb-0.3.6-dev at Tue Sep 11 14:37:18 2018. */
#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_boot_validation_fields[3] = {
PB_FIELD( 1, UENUM , REQUIRED, STATIC , FIRST, dfu_boot_validation_t, type, type, 0),
PB_FIELD( 2, BYTES , REQUIRED, STATIC , OTHER, dfu_boot_validation_t, bytes, type, 0),
PB_LAST_FIELD
};
const pb_field_t dfu_init_command_fields[11] = {
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_FIELD( 10, MESSAGE , REPEATED, STATIC , OTHER, dfu_init_command_t, boot_validation, is_debug, &dfu_boot_validation_fields),
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_init_command_t, boot_validation[0]) < 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_boot_validation_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_init_command_t, boot_validation[0]) < 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_boot_validation_dfu_init_command_dfu_command_dfu_signed_command_dfu_packet)
#endif
/* @@protoc_insertion_point(eof) */

View File

@@ -0,0 +1,241 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/* Automatically generated nanopb header */
/* Generated by nanopb-0.3.6-dev at Tue Sep 11 14:37:18 2018. */
#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_EXTERNAL_APPLICATION = 4
} dfu_fw_type_t;
#define DFU_FW_TYPE_MIN DFU_FW_TYPE_APPLICATION
#define DFU_FW_TYPE_MAX DFU_FW_TYPE_EXTERNAL_APPLICATION
#define DFU_FW_TYPE_ARRAYSIZE ((dfu_fw_type_t)(DFU_FW_TYPE_EXTERNAL_APPLICATION+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_OP_CODE_INIT = 1
} dfu_op_code_t;
#define DFU_OP_CODE_MIN DFU_OP_CODE_INIT
#define DFU_OP_CODE_MAX DFU_OP_CODE_INIT
#define DFU_OP_CODE_ARRAYSIZE ((dfu_op_code_t)(DFU_OP_CODE_INIT+1))
typedef enum
{
DFU_VALIDATION_TYPE_NO_VALIDATION = 0,
DFU_VALIDATION_TYPE_VALIDATE_GENERATED_CRC = 1,
DFU_VALIDATION_TYPE_VALIDATE_SHA256 = 2,
DFU_VALIDATION_TYPE_VALIDATE_ECDSA_P256_SHA256 = 3
} dfu_validation_type_t;
#define DFU_VALIDATION_TYPE_MIN DFU_VALIDATION_TYPE_NO_VALIDATION
#define DFU_VALIDATION_TYPE_MAX DFU_VALIDATION_TYPE_VALIDATE_ECDSA_P256_SHA256
#define DFU_VALIDATION_TYPE_ARRAYSIZE ((dfu_validation_type_t)(DFU_VALIDATION_TYPE_VALIDATE_ECDSA_P256_SHA256+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))
/* Struct definitions */
typedef PB_BYTES_ARRAY_T(64) dfu_boot_validation_bytes_t;
typedef struct {
dfu_validation_type_t type;
dfu_boot_validation_bytes_t bytes;
/* @@protoc_insertion_point(struct:dfu_boot_validation_t) */
} dfu_boot_validation_t;
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;
pb_size_t boot_validation_count;
dfu_boot_validation_t boot_validation[3];
/* @@protoc_insertion_point(struct:dfu_init_command_t) */
} dfu_init_command_t;
typedef struct {
bool has_op_code;
dfu_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_BOOT_VALIDATION_INIT_DEFAULT {(dfu_validation_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, 0, {DFU_BOOT_VALIDATION_INIT_DEFAULT, DFU_BOOT_VALIDATION_INIT_DEFAULT, DFU_BOOT_VALIDATION_INIT_DEFAULT}}
#define DFU_COMMAND_INIT_DEFAULT {false, (dfu_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_BOOT_VALIDATION_INIT_ZERO {(dfu_validation_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, 0, {DFU_BOOT_VALIDATION_INIT_ZERO, DFU_BOOT_VALIDATION_INIT_ZERO, DFU_BOOT_VALIDATION_INIT_ZERO}}
#define DFU_COMMAND_INIT_ZERO {false, (dfu_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_BOOT_VALIDATION_TYPE_TAG 1
#define DFU_BOOT_VALIDATION_BYTES_TAG 2
#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_INIT_COMMAND_BOOT_VALIDATION_TAG 10
#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_boot_validation_fields[3];
extern const pb_field_t dfu_init_command_fields[11];
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_BOOT_VALIDATION_SIZE 68
#define DFU_INIT_COMMAND_SIZE 378
#define DFU_COMMAND_SIZE 383
#define DFU_SIGNED_COMMAND_SIZE 454
#define DFU_PACKET_SIZE 843
/* 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

View File

@@ -0,0 +1,82 @@
package dfu;
// Version 0.1
enum FwType {
APPLICATION = 0;
SOFTDEVICE = 1;
BOOTLOADER = 2;
SOFTDEVICE_BOOTLOADER = 3;
EXTERNAL_APPLICATION = 4;
}
enum HashType {
NO_HASH = 0;
CRC = 1;
SHA128 = 2;
SHA256 = 3;
SHA512 = 4;
}
enum OpCode {
INIT = 1;
}
enum ValidationType {
NO_VALIDATION = 0;
VALIDATE_GENERATED_CRC = 1;
VALIDATE_SHA256 = 2;
VALIDATE_ECDSA_P256_SHA256 = 3;
}
message Hash {
required HashType hash_type = 1;
required bytes hash = 2;
}
message BootValidation {
required ValidationType type = 1;
required bytes bytes = 2;
}
// Commands data
message InitCommand {
optional uint32 fw_version = 1;
optional uint32 hw_version = 2;
repeated uint32 sd_req = 3 [packed = true];
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];
repeated BootValidation boot_validation = 10;
}
// Command type
message Command {
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;
}

View File

@@ -0,0 +1,98 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_dfu.h"
#include "nrf_dfu_utils.h"
#include "nrf_dfu_transport.h"
#include "nrf_dfu_req_handler.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:
case NRF_DFU_EVT_DFU_ABORTED:
#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;
}

View File

@@ -0,0 +1,85 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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 Callback 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__
/** @} */

View File

@@ -0,0 +1,167 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "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. */
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_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;
}

View File

@@ -0,0 +1,132 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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__
/** @} */

View File

@@ -0,0 +1,61 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "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;
}

View File

@@ -0,0 +1,125 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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 or SoftDevice, the version must be greater than
or equal to the current version. For a bootloader, it must be greater than the current version.
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 or the first FWID is '0' on a
bootloader which requires the SoftDevice to be present. */
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__
/** @} */

View File

@@ -0,0 +1,105 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "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;
#if !defined(BLE_STACK_SUPPORT_REQD) && !defined(ANT_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;
}
return ret_val;
}

View File

@@ -0,0 +1,90 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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__
/** @} */

View File

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

View File

@@ -0,0 +1,345 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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 Callback 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__
/** @} */

View File

@@ -0,0 +1,433 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_dfu_settings.h"
#include <stddef.h>
#include <string.h>
#include "nrf_dfu_flash.h"
#include "nrf_soc.h"
#include "crc32.h"
#include "nrf_nvmc.h"
#include "sdk_config.h"
#define DFU_SETTINGS_VERSION_OFFSET (offsetof(nrf_dfu_settings_t, settings_version)) //<! Offset in the settings struct where the settings version is located.
#define DFU_SETTINGS_INIT_COMMAND_OFFSET (offsetof(nrf_dfu_settings_t, init_command)) //<! Offset in the settings struct where the InitCommand is located.
#define DFU_SETTINGS_BOOT_VALIDATION_OFFSET (offsetof(nrf_dfu_settings_t, boot_validation_crc)) //<! Offset in the settings struct where the boot validation info is located.
#define DFU_SETTINGS_BOOT_VALIDATION_SIZE ((3 * sizeof(boot_validation_t)) + 4)
#define DFU_SETTINGS_BOND_DATA_OFFSET_V1 (offsetof(nrf_dfu_settings_t, init_command) + INIT_COMMAND_MAX_SIZE_v1) //<! Offset in the settings struct where the bond data was located in settings version 1.
#define DFU_SETTINGS_ADV_NAME_OFFSET_V1 (offsetof(nrf_dfu_settings_t, init_command) + INIT_COMMAND_MAX_SIZE_v1 + NRF_DFU_PEER_DATA_LEN) //<! Offset in the settings struct where the bond data was located in settings version 1.
#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
#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")))
__attribute__((used));
#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
uint8_t * mp_dfu_settings_backup_buffer = &m_mbr_params_page[0];
#ifndef NRF_DFU_IN_APP
#define NRF_DFU_IN_APP 0
#endif
#define UICR_PARAM_PAGE_ADDR 0x10001018
#if !defined(BL_SETTINGS_ACCESS_ONLY) && !NRF_DFU_IN_APP
/**@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(UICR_PARAM_PAGE_ADDR))) = 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
@ UICR_PARAM_PAGE_ADDR = NRF_MBR_PARAMS_PAGE_ADDRESS;
#else
#error Not a valid compiler/linker for m_mbr_params_page placement.
#endif // Compiler specific
#endif // #ifndef BL_SETTINGS_ACCESS_ONLY
#endif // #if defined( NRF52_SERIES )
nrf_dfu_settings_t s_dfu_settings;
static uint32_t settings_crc_get(nrf_dfu_settings_t const * p_settings)
{
ASSERT(offsetof(nrf_dfu_settings_t, crc) == 0);
// The crc is calculated from the s_dfu_settings struct, except the crc itself, the init command, bond data, and boot validation.
return crc32_compute((uint8_t*)(p_settings) + 4, DFU_SETTINGS_INIT_COMMAND_OFFSET - 4, NULL);
}
static bool crc_ok(nrf_dfu_settings_t const * p_settings)
{
if (p_settings->crc != 0xFFFFFFFF)
{
// CRC is set. Content must be valid
uint32_t crc = settings_crc_get(p_settings);
if (crc == p_settings->crc)
{
return true;
}
}
return false;
}
static uint32_t boot_validation_crc(nrf_dfu_settings_t const * p_settings)
{
return crc32_compute((const uint8_t *)&p_settings->boot_validation_softdevice,
DFU_SETTINGS_BOOT_VALIDATION_SIZE - 4,
NULL);
}
static bool boot_validation_crc_ok(nrf_dfu_settings_t const * p_settings)
{
return (boot_validation_crc(p_settings) == p_settings->boot_validation_crc);
}
static bool settings_crc_ok(void)
{
nrf_dfu_settings_t const * p_settings = (nrf_dfu_settings_t const *)m_dfu_settings_buffer;
return crc_ok(p_settings);
}
static bool settings_backup_crc_ok(void)
{
nrf_dfu_settings_t const * p_settings = (nrf_dfu_settings_t const *)mp_dfu_settings_backup_buffer;
return crc_ok(p_settings) && ((p_settings->settings_version == 1) || boot_validation_crc_ok(p_settings));
}
#define REGION_COPY_BY_MEMBER(start_member, end_member, p_dst_addr) \
memcpy(p_dst_addr + offsetof(nrf_dfu_settings_t, start_member), \
mp_dfu_settings_backup_buffer + offsetof(nrf_dfu_settings_t, start_member), \
offsetof(nrf_dfu_settings_t, end_member) - offsetof(nrf_dfu_settings_t, start_member))
static void settings_forbidden_parts_copy_from_backup(uint8_t * p_dst_addr)
{
#if NRF_DFU_IN_APP || NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
REGION_COPY_BY_MEMBER(settings_version, bank_current, p_dst_addr);
REGION_COPY_BY_MEMBER(bank_0, write_offset, p_dst_addr);
REGION_COPY_BY_MEMBER(sd_size, progress, p_dst_addr);
REGION_COPY_BY_MEMBER(boot_validation_crc, peer_data, p_dst_addr);
#else
REGION_COPY_BY_MEMBER(settings_version, enter_buttonless_dfu, p_dst_addr);
REGION_COPY_BY_MEMBER(init_command, peer_data, p_dst_addr);
#endif
}
void nrf_dfu_settings_reinit(void)
{
bool settings_valid = settings_crc_ok();
bool settings_backup_valid = settings_backup_crc_ok();
if (settings_valid)
{
NRF_LOG_DEBUG("Using settings page.");
memcpy(&s_dfu_settings, m_dfu_settings_buffer, sizeof(nrf_dfu_settings_t));
if (settings_backup_valid)
{
NRF_LOG_DEBUG("Copying forbidden parts from backup page.");
settings_forbidden_parts_copy_from_backup((uint8_t *)&s_dfu_settings);
}
}
else if (settings_backup_valid)
{
NRF_LOG_INFO("Restoring settings from backup since the settings page contents are "
"invalid (CRC error).");
memcpy(&s_dfu_settings,
mp_dfu_settings_backup_buffer,
sizeof(nrf_dfu_settings_t));
}
else
{
NRF_LOG_WARNING("Resetting bootloader settings since neither the settings page nor the "
"backup are valid (CRC error).");
memset(&s_dfu_settings, 0x00, sizeof(nrf_dfu_settings_t));
s_dfu_settings.settings_version = NRF_DFU_SETTINGS_VERSION;
}
if (NRF_DFU_SETTINGS_COMPATIBILITY_MODE && !NRF_DFU_IN_APP && (s_dfu_settings.settings_version == 1))
{
NRF_LOG_INFO("Old settings page detected. Upgrading info.");
// Old version. Translate.
memcpy(&s_dfu_settings.peer_data, (uint8_t *)&s_dfu_settings + DFU_SETTINGS_BOND_DATA_OFFSET_V1, NRF_DFU_PEER_DATA_LEN);
memcpy(&s_dfu_settings.adv_name, (uint8_t *)&s_dfu_settings + DFU_SETTINGS_ADV_NAME_OFFSET_V1, NRF_DFU_ADV_NAME_LEN);
// Initialize with defaults.
s_dfu_settings.boot_validation_softdevice.type = NO_VALIDATION;
s_dfu_settings.boot_validation_app.type = VALIDATE_CRC;
s_dfu_settings.boot_validation_bootloader.type = NO_VALIDATION;
memcpy(s_dfu_settings.boot_validation_app.bytes, &s_dfu_settings.bank_0.image_crc, sizeof(uint32_t));
s_dfu_settings.settings_version = NRF_DFU_SETTINGS_VERSION;
}
return;
}
ret_code_t nrf_dfu_settings_init(bool sd_irq_initialized)
{
NRF_LOG_DEBUG("Calling nrf_dfu_settings_init()...");
ret_code_t err_code = nrf_dfu_flash_init(sd_irq_initialized);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("nrf_dfu_flash_init() failed with error: %x", err_code);
return NRF_ERROR_INTERNAL;
}
nrf_dfu_settings_reinit();
err_code = nrf_dfu_settings_write_and_backup(NULL);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("nrf_dfu_settings_write_and_backup() failed with error: %x", err_code);
return NRF_ERROR_INTERNAL;
}
return NRF_SUCCESS;
}
static bool settings_forbidden_parts_equal_to_backup(uint8_t * p_compare_addr)
{
nrf_dfu_settings_t temp_settings;
memcpy(&temp_settings, p_compare_addr, sizeof(nrf_dfu_settings_t));
settings_forbidden_parts_copy_from_backup((uint8_t *)&temp_settings);
return memcmp(&temp_settings, p_compare_addr, sizeof(nrf_dfu_settings_t)) == 0;
}
static ret_code_t settings_write(void * p_dst,
void const * p_src,
nrf_dfu_flash_callback_t callback,
nrf_dfu_settings_t * p_dfu_settings_buffer)
{
ret_code_t err_code;
if (memcmp(p_dst, p_src, sizeof(nrf_dfu_settings_t)) == 0)
{
NRF_LOG_DEBUG("Destination settings are identical to source, write not needed. Skipping.");
if (callback != NULL)
{
callback(NULL);
}
return NRF_SUCCESS;
}
if (NRF_DFU_IN_APP && !settings_forbidden_parts_equal_to_backup((uint8_t *)&s_dfu_settings))
{
NRF_LOG_WARNING("Settings write aborted since it tries writing to forbidden settings.");
return NRF_ERROR_FORBIDDEN;
}
NRF_LOG_DEBUG("Writing settings...");
NRF_LOG_DEBUG("Erasing old settings at: 0x%08x", p_dst);
// 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)p_dst, 1, NULL);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Could not erase the settings page!");
return NRF_ERROR_INTERNAL;
}
ASSERT(p_dfu_settings_buffer != NULL);
memcpy(p_dfu_settings_buffer, p_src, sizeof(nrf_dfu_settings_t));
err_code = nrf_dfu_flash_store((uint32_t)p_dst,
p_dfu_settings_buffer,
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;
}
ret_code_t nrf_dfu_settings_write(nrf_dfu_flash_callback_t callback)
{
static nrf_dfu_settings_t dfu_settings_buffer;
s_dfu_settings.crc = settings_crc_get(&s_dfu_settings);
s_dfu_settings.boot_validation_crc = boot_validation_crc(&s_dfu_settings);
return settings_write(m_dfu_settings_buffer,
&s_dfu_settings,
callback,
&dfu_settings_buffer);
}
void settings_backup(nrf_dfu_flash_callback_t callback, void * p_src)
{
#if NRF_DFU_IN_APP
NRF_LOG_INFO("Settings backup not available from app.");
#else
static nrf_dfu_settings_t dfu_settings_buffer;
NRF_LOG_INFO("Backing up settings page to address 0x%x.", mp_dfu_settings_backup_buffer);
ASSERT(crc_ok(p_src));
ret_code_t err_code = settings_write(mp_dfu_settings_backup_buffer,
p_src,
callback,
&dfu_settings_buffer);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_ERROR("Could not perform backup of bootloader settings! Error: 0x%x", err_code);
}
#endif
}
void nrf_dfu_settings_backup(nrf_dfu_flash_callback_t callback)
{
settings_backup(callback, m_dfu_settings_buffer);
}
ret_code_t nrf_dfu_settings_write_and_backup(nrf_dfu_flash_callback_t callback)
{
#if NRF_DFU_IN_APP
ret_code_t err_code = nrf_dfu_settings_write(callback);
#else
ret_code_t err_code = nrf_dfu_settings_write(NULL);
if (err_code == NRF_SUCCESS)
{
settings_backup(callback, &s_dfu_settings);
}
#endif
return err_code;
}
__WEAK ret_code_t nrf_dfu_settings_additional_erase(void)
{
NRF_LOG_WARNING("No additional data erased");
return NRF_SUCCESS;
}
void nrf_dfu_settings_progress_reset(void)
{
memset(s_dfu_settings.init_command, 0xFF, INIT_COMMAND_MAX_SIZE); // Remove the last init command
memset(&s_dfu_settings.progress, 0, sizeof(dfu_progress_t));
s_dfu_settings.write_offset = 0;
}

View File

@@ -0,0 +1,212 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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 backing up the settings.
*
* This function copies the contents of the settings page (in flash) to a separate page (in flash).
* During @ref nrf_dfu_settings_init, the backup is restored if the original is invalid.
*
* @param[in] callback Pointer to a function that is called after completing the write operation.
*/
void nrf_dfu_settings_backup(nrf_dfu_flash_callback_t callback);
/**@brief Function for writing DFU settings to flash and to backup.
*
* This function first calls @ref nrf_dfu_settings_write and then @ref nrf_dfu_settings_backup.
*
* @param[in] callback Pointer to a function that is called after completing the write and backup operation.
*
* @retval NRF_SUCCESS If the write process was successfully initiated.
* @retval NRF_ERROR_INTERNAL If a flash error occurred during the first write.
*/
ret_code_t nrf_dfu_settings_write_and_backup(nrf_dfu_flash_callback_t callback);
/**@brief Function for initializing the DFU settings structure.
*
* Initializes the RAM structure from the flash contents.
* This function is called as part of @ref nrf_dfu_settings_init.
*
* @retval NRF_SUCCESS If the initialization was successful.
* @retval NRF_ERROR_INTERNAL If a flash error occurred.
*/
void nrf_dfu_settings_reinit(void);
/**@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);
/** @brief Function for resetting both init command and DFU transfer progress inside settings structure.
*
* @note This function does not perform flash operation.
* In order to save the reset state, please use @ref nrf_dfu_settings_write function.
*/
void nrf_dfu_settings_progress_reset(void);
#ifdef __cplusplus
}
#endif
#endif // NRF_DFU_SETTINGS_H__
/**@} */

View File

@@ -0,0 +1,185 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <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

View File

@@ -0,0 +1,87 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdint.h>
#include <stdbool.h>
#include "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;
uint32_t bootloader_addr = BOOTLOADER_ADDRESS;
if (bootloader_addr != 0xFFFFFFFF)
{
NRF_LOG_INFO("Setting vector table to bootloader: 0x%08x", bootloader_addr);
err_code = sd_softdevice_vector_table_base_set(bootloader_addr);
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;
}

View File

@@ -0,0 +1,212 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <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);
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);
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

View File

@@ -0,0 +1,91 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "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;
}

View File

@@ -0,0 +1,134 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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 Callback 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__
/** @} */

View File

@@ -0,0 +1,244 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_dfu_trigger_usb.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 strings_create(void)
{
uint8_t prev_char = 'a'; // Arbitrary valid char, not '-'.
// Remove characters that are not supported in semantic version 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 version character.
}
else if (prev_char == '-')
{
m_version_string[i] = '0';
}
else
{
m_version_string[i] = '-';
}
prev_char = 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;
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;
}

View File

@@ -0,0 +1,74 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#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

View File

@@ -0,0 +1,342 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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 "sdk_common.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 512 /**< Maximum size of the init command stored in dfu_settings. */
#define INIT_COMMAND_MAX_SIZE_v1 256 /**< Maximum size of the init command in settings version 1. */
/** @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_SERIES)
#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( NRF52811_XXAA )
#define BOOTLOADER_SETTINGS_ADDRESS (0x0002F000UL)
#elif defined( NRF52820_XXAA )
#define BOOTLOADER_SETTINGS_ADDRESS (0x0003F000UL)
#elif defined( NRF52832_XXAA )
#define BOOTLOADER_SETTINGS_ADDRESS (0x0007F000UL)
#elif defined( NRF52833_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)
#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(NRF52833_XXAA)
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0007E000UL)
#elif defined(NRF52810_XXAA)
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0002E000UL)
#elif defined(NRF52811_XXAA)
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0002E000UL)
#elif defined(NRF52820_XXAA)
#define NRF_MBR_PARAMS_PAGE_ADDRESS (0x0003E000UL)
#endif
#define BOOTLOADER_SETTINGS_BACKUP_ADDRESS NRF_MBR_PARAMS_PAGE_ADDRESS
#ifndef NRF_DFU_APP_DATA_AREA_SIZE
#define NRF_DFU_APP_DATA_AREA_SIZE (CODE_PAGE_SIZE * 3)
#endif
STATIC_ASSERT((NRF_DFU_APP_DATA_AREA_SIZE % CODE_PAGE_SIZE) == 0, "NRF_DFU_APP_DATA_AREA_SIZE must be a multiple of the flash page size.");
#define DFU_APP_DATA_RESERVED NRF_DFU_APP_DATA_AREA_SIZE // For backward compatibility with 15.0.0.
/** @brief Total size of the region between the SoftDevice and the bootloader.
*/
#define DFU_REGION_END(bootloader_start_addr) ((bootloader_start_addr) - (NRF_DFU_APP_DATA_AREA_SIZE))
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_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. */
#define NRF_DFU_BANK_VALID_EXT_APP 0xB1 /**< Valid application designated for a remote node. */
/** @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);
#define NRF_DFU_PEER_DATA_LEN 64 /**< The length in bytes of nrf_dfu_peer_data_t expected by tools manipulating the settings page. Do not change without changing the settings page version. */
#define NRF_DFU_ADV_NAME_LEN 28 /**< The length in bytes of nrf_dfu_adv_name_t expected by tools manipulating the settings page. Do not change without changing the settings page version. */
#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;
#else
typedef struct
{
uint8_t dummy_data[NRF_DFU_PEER_DATA_LEN];
} nrf_dfu_peer_data_t;
typedef struct
{
uint8_t dummy_data[NRF_DFU_ADV_NAME_LEN];
} nrf_dfu_adv_name_t;
#endif // NRF_DFU_TRANSPORT_BLE
STATIC_ASSERT(sizeof(nrf_dfu_peer_data_t) == NRF_DFU_PEER_DATA_LEN, "nrf_dfu_peer_data_t has unexpected length. This can cause incompatibility with tools.");
STATIC_ASSERT(sizeof(nrf_dfu_adv_name_t) == NRF_DFU_ADV_NAME_LEN, "nrf_dfu_adv_name_t has unexpected length. This can cause incompatibility with tools.");
#define SETTINGS_RESERVED_AREA_SIZE 16 /**< The number of words in the reserved area of the DFU settings. */
#define SETTINGS_BOOT_VALIDATION_SIZE 64 /**< The number of bytes reserved for boot_validation value. */
typedef enum
{
NO_VALIDATION,
VALIDATE_CRC,
VALIDATE_SHA256,
VALIDATE_ECDSA_P256_SHA256,
} boot_validation_type_t;
typedef struct
{
boot_validation_type_t type;
uint8_t bytes[SETTINGS_BOOT_VALIDATION_SIZE];
} boot_validation_t;
/**@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. */
uint32_t boot_validation_crc;
boot_validation_t boot_validation_softdevice;
boot_validation_t boot_validation_app;
boot_validation_t boot_validation_bootloader;
nrf_dfu_peer_data_t peer_data; /**< Not included in calculated CRC. */
nrf_dfu_adv_name_t adv_name; /**< Not included in calculated CRC. */
} nrf_dfu_settings_t;
#pragma pack() // revert pack settings
#ifdef __cplusplus
}
#endif
#endif // NRF_DFU_TYPES_H__
/** @} */

View File

@@ -0,0 +1,220 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_dfu_utils.h"
#include "nrf_dfu_settings.h"
#include "nrf_bootloader_info.h"
#include "crc32.h"
#include "nrf_log.h"
#include "nrf_dfu_validation.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;
}
#if !defined(BLE_STACK_SUPPORT_REQD) && !defined(ANT_STACK_SUPPORT_REQD)
void nrf_dfu_softdevice_invalidate(void)
{
static const uint32_t all_zero = 0UL;
if (SD_PRESENT && !NRF_DFU_IN_APP)
{
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;
}
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.
#if !defined(BLE_STACK_SUPPORT_REQD) && !defined(ANT_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);
}
err_code = NRF_SUCCESS;
}
return err_code;
}

View File

@@ -0,0 +1,154 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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 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__
/** @} */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,199 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup 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 "dfu-cc.pb.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 and retrieving the address and length of the firmware.
*
* 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 Start address of received data, if validation is successful.
* @param[out] p_data_len Expected length of received data, 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 validating the init command.
*
* @return Operation result. See @ref nrf_dfu_result_t.
*/
nrf_dfu_result_t nrf_dfu_validation_prevalidate(void);
/**
* @brief Function for validating the firmware for booting.
*
* @param[in] p_validation Validation parameters.
* @param[in] data_addr Start address of the firmware.
* @param[in] data_len Length of the firmware.
*
* @return Whether the firmware is valid for booting.
*/
bool nrf_dfu_validation_boot_validate(boot_validation_t const * p_validation, uint32_t data_addr, uint32_t data_len);
/**
* @brief Function for postvalidating the update after all data is received.
*
* @param[in] data_addr Start address of the received data.
* @param[in] data_len Length of the received data.
*
* @return Operation result. See @ref nrf_dfu_result_t.
*/
nrf_dfu_result_t nrf_dfu_validation_post_data_execute(uint32_t data_addr, uint32_t data_len);
/**
* @brief Function for preparing the update for activation.
*
* This function is called after a reset, after all data is received. This function also runs
* @ref nrf_dfu_validation_post_data_execute internally. If this succeeds, the update is
* activated by the activation machinery in the bootloader the next time it runs.
*
* @note The caller must have permissions to edit the relevant entries in the settings.
*
* @param[in] data_addr Start address of the received data.
* @param[in] data_len Length of the received data.
*
* @return Operation result. See @ref nrf_dfu_result_t
*/
nrf_dfu_result_t nrf_dfu_validation_activation_prepare(uint32_t data_addr, uint32_t data_len);
/**
* @brief Function to execute on a validated external app.
*
* @details This function is called once all data is received with the parameter
* @p is_boot set to false. The function is called during bootup with the parameter
* set to true.
*
*
*
* @note This function requires that @ref NRF_DFU_SUPPORTS_EXTERNAL_APP is set to 1.
* It is up to the user to implement this function.
*
* @warning Parameter @p is_trusted must be used to ensure that no loss of security of process can happen.
* This parameter should only be set if the function is called after a root-of-trust
* reset on the device.
*
* Parameter @p is_trusted can be used for the following:
* - Ensuring that an external application is run only once (after root-of-trust).
* - Ensuring that a bank flag or any other flash access can only happen after root-of-trust.
* - Ensuring that the device reaches the correct state after a power failure on the device.
*
* @param[in] p_init Init command for the firmware upgrade.
* @param[in] is_trusted Must be set to true if this is called after root-of-trust boot.
* Must be set to false if this is called from DFU mode or background
* DFU operation.
*
* @return Operation result. see @ref nrf_dfu_result_t.
*/
nrf_dfu_result_t nrf_dfu_validation_post_external_app_execute(dfu_init_command_t const * p_init, bool is_trusted);
/**
* @brief Function to check if there is a valid external app in Bank 1.
*
* @returns True if valid external app, otherwise false.
*/
bool nrf_dfu_validation_valid_external_app(void);
#endif //__NRF_DFU_VALIDATION_H
/** @} */

View File

@@ -0,0 +1,312 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <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();
/** @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 accept_any)
{
bool result = false;
for (uint8_t i = 0; i < sd_req_cnt; i++)
{
if ((SD_PRESENT && (p_sd_req[i] == _SD_FWID_GET(MBR_SIZE))) ||
(accept_any && (p_sd_req[i] == SD_REQ_ANY_VERSION))
)
{
// 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;
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_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 == 0)
{
result = false;
}
else if (p_init->sd_req[0] != SD_REQ_APP_OVERWRITES_SD)
{
result = sd_req_check(p_init->sd_req,
p_init->sd_req_count,
(p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION));
}
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, false);
// Prevent BLE/ANT bootloaders from allowing applications overwriting the SoftDevice.
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_STACK_SUPPORT_REQD)
result = false;
#endif
}
else
{
result = true;
}
}
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
else if(p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
{
// Won't accept FW upgrade using external application to
// enforce replacing SoftDevice (SD_REQ_APP_OVERWRITES_SD)
result = false;
}
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
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. The special "any" FWID is valid
// for external apps only.
result = false;
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
result = sd_req_check(p_init->sd_req,
p_init->sd_req_count,
(p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION));
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
}
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.
}
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
#if !NRF_DFU_EXTERNAL_APP_VERSIONING
else if (new_fw_type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
{
return false;
}
#endif //!NRF_DFU_EXTERNAL_APP_VERSIONING
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
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)
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
|| (p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
));
}
#ifndef NRF_DFU_APP_ACCEPT_SAME_VERSION
#define NRF_DFU_APP_ACCEPT_SAME_VERSION 1
#endif
// 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))
{
if (!NRF_DFU_APP_DOWNGRADE_PREVENTION)
{
return true;
}
else if ((p_init->fw_version > s_dfu_settings.app_version))
{
return true;
}
else if ((p_init->fw_version == s_dfu_settings.app_version))
{
return NRF_DFU_APP_ACCEPT_SAME_VERSION;
}
else
{
return false;
}
}
#if NRF_DFU_SUPPORTS_EXTERNAL_APP
#if NRF_DFU_EXTERNAL_APP_VERSIONING
else if (p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
{
return (p_init->fw_version >= s_dfu_settings.app_version);
}
#else
else if(p_init->type == DFU_FW_TYPE_EXTERNAL_APPLICATION)
{
return true;
}
#endif // NRF_DFU_EXTERNAL_APP_VERSIONING
#endif // NRF_DFU_SUPPORTS_EXTERNAL_APP
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;
}

View File

@@ -0,0 +1,64 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#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 SD_REQ_ANY_VERSION field value which indicates that any SoftDevice version is valid.
*
* @note This is used by external application in case SoftDevice version compatibility isn't needed.
*/
#define SD_REQ_ANY_VERSION (0xFFFE)
/**
* @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

View File

@@ -0,0 +1,528 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "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 "nrf_dfu_validation.h"
static nrf_dfu_observer_t m_user_observer; //<! Observer callback set by the user.
static volatile bool m_flash_write_done;
#define SCHED_QUEUE_SIZE 32 /**< Maximum number of events in the scheduler queue. */
#define SCHED_EVENT_DATA_SIZE NRF_DFU_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)&& \
defined(NRF_BL_RESET_DELAY_MS) && \
defined(NRF_BL_DEBUG_PORT_DISABLE))
#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 flash_write_callback(void * p_context)
{
UNUSED_PARAMETER(p_context);
m_flash_write_done = true;
}
static void do_reset(void * p_context)
{
UNUSED_PARAMETER(p_context);
NRF_LOG_FINAL_FLUSH();
nrf_delay_ms(NRF_BL_RESET_DELAY_MS);
NVIC_SystemReset();
}
static void bootloader_reset(bool do_backup)
{
NRF_LOG_DEBUG("Resetting bootloader.");
if (do_backup)
{
m_flash_write_done = false;
nrf_dfu_settings_backup(do_reset);
}
else
{
do_reset(NULL);
}
}
static void inactivity_timeout(void)
{
NRF_LOG_INFO("Inactivity timeout.");
bootloader_reset(true);
}
/**@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_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS),
inactivity_timeout);
break;
case NRF_DFU_EVT_DFU_COMPLETED:
case NRF_DFU_EVT_DFU_ABORTED:
bootloader_reset(true);
break;
case NRF_DFU_EVT_TRANSPORT_DEACTIVATED:
// Reset the internal state of the DFU settings to the last stored state.
nrf_dfu_settings_reinit();
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)
{
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_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();
}
}
}
#if NRF_BL_DFU_ENTER_METHOD_BUTTON
#ifndef BUTTON_PULL
#error NRF_BL_DFU_ENTER_METHOD_BUTTON is enabled but not buttons seem to be available on the board.
#endif
/**@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);
}
#endif
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_GPREGRET2_MASK) == BOOTLOADER_DFU_GPREGRET2)
&& (nrf_power_gpregret2_get() & BOOTLOADER_DFU_SKIP_CRC_BIT_MASK))
{
nrf_power_gpregret2_set(nrf_power_gpregret2_get() & ~BOOTLOADER_DFU_SKIP_CRC);
ret = false;
}
else
{
}
return ret;
}
static bool boot_validate(boot_validation_t const * p_validation, uint32_t data_addr, uint32_t data_len, bool do_crc)
{
if (!do_crc && (p_validation->type == VALIDATE_CRC))
{
return true;
}
return nrf_dfu_validation_boot_validate(p_validation, data_addr, data_len);
}
/** @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. Only CRC checks
can be skipped. For other boot validation types,
this parameter is ignored.
*
* @retval true If a valid application has been detected.
* @retval false If there is no valid application.
*/
static bool app_is_valid(bool do_crc)
{
if (s_dfu_settings.bank_0.bank_code != NRF_DFU_BANK_VALID_APP)
{
NRF_LOG_INFO("Boot validation failed. No valid app to boot.");
return false;
}
else if (NRF_BL_APP_SIGNATURE_CHECK_REQUIRED &&
(s_dfu_settings.boot_validation_app.type != VALIDATE_ECDSA_P256_SHA256))
{
NRF_LOG_WARNING("Boot validation failed. The boot validation of the app must be a signature check.");
return false;
}
else if (SD_PRESENT && !boot_validate(&s_dfu_settings.boot_validation_softdevice, MBR_SIZE, s_dfu_settings.sd_size, do_crc))
{
NRF_LOG_WARNING("Boot validation failed. SoftDevice is present but invalid.");
return false;
}
else if (!boot_validate(&s_dfu_settings.boot_validation_app, nrf_dfu_bank0_start_addr(), s_dfu_settings.bank_0.image_size, do_crc))
{
NRF_LOG_WARNING("Boot validation failed. App is invalid.");
return false;
}
// The bootloader itself is not checked, since a self-check of this kind gives little to no benefit
// compared to the cost incurred on each bootup.
NRF_LOG_DEBUG("App is valid");
return true;
}
/**@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_GPREGRET_MASK) == BOOTLOADER_DFU_GPREGRET)
&& (nrf_power_gpregret_get() & BOOTLOADER_DFU_START_BIT_MASK))
{
// 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 (!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;
}
#if NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
static void postvalidate(void)
{
NRF_LOG_INFO("Postvalidating update after reset.");
nrf_dfu_validation_init();
if (nrf_dfu_validation_init_cmd_present())
{
uint32_t firmware_start_addr;
uint32_t firmware_size;
// Execute a previously received init packed. Subsequent executes will have no effect.
if (nrf_dfu_validation_init_cmd_execute(&firmware_start_addr, &firmware_size) == NRF_DFU_RES_CODE_SUCCESS)
{
if (nrf_dfu_validation_prevalidate() == NRF_DFU_RES_CODE_SUCCESS)
{
if (nrf_dfu_validation_activation_prepare(firmware_start_addr, firmware_size) == NRF_DFU_RES_CODE_SUCCESS)
{
NRF_LOG_INFO("Postvalidation successful.");
}
}
}
}
s_dfu_settings.bank_current = NRF_DFU_CURRENT_BANK_0;
UNUSED_RETURN_VALUE(nrf_dfu_settings_write_and_backup(flash_write_callback));
}
#endif
ret_code_t nrf_bootloader_init(nrf_dfu_observer_t observer)
{
NRF_LOG_DEBUG("In nrf_bootloader_init");
ret_code_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_DEBUG_PORT_DISABLE)
{
nrf_bootloader_debug_port_disable();
}
#if NRF_BL_DFU_ENTER_METHOD_BUTTON
dfu_enter_button_init();
#endif
ret_val = nrf_dfu_settings_init(false);
if (ret_val != NRF_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
#if NRF_BL_DFU_ALLOW_UPDATE_FROM_APP
// Postvalidate if DFU has signaled that update is ready.
if (s_dfu_settings.bank_current == NRF_DFU_CURRENT_BANK_1)
{
postvalidate();
}
#endif
// 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_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_INACTIVITY_TIMEOUT_MS);
dfu_enter = dfu_enter_check();
break;
case ACTIVATION_SUCCESS_EXPECT_ADDITIONAL_UPDATE:
initial_timeout = NRF_BOOTLOADER_MS_TO_TICKS(NRF_BL_DFU_CONTINUATION_TIMEOUT_MS);
dfu_enter = true;
break;
case ACTIVATION_SUCCESS:
bootloader_reset(true);
NRF_LOG_ERROR("Unreachable");
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();
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("Unreachable");
}
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;
}
m_flash_write_done = false;
nrf_dfu_settings_backup(flash_write_callback);
ASSERT(m_flash_write_done);
nrf_bootloader_app_start();
NRF_LOG_ERROR("Unreachable");
}
// Should not be reached.
return NRF_ERROR_INTERNAL;
}

View File

@@ -0,0 +1,79 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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__
/** @} */

View File

@@ -0,0 +1,77 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdint.h>
#include "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);
}

View File

@@ -0,0 +1,88 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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 applies write/erase protection to a specific area, using 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.
*
* @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);
/**@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__
/** @} */

View File

@@ -0,0 +1,188 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "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_dfu_utils.h"
#include "nrf_dfu_settings.h"
#include "nrf_assert.h"
#include "nrf_log.h"
#include "sdk_config.h"
#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 starts executing a particular address.
*
* @param[in] new_msp The new value to set in the main stack pointer.
* @param[in] addr The address to execute.
*/
void jump_to_addr(uint32_t new_msp, uint32_t addr)
{
__set_MSP(new_msp);
((void (*)(void))addr)();
}
/**@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.
__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.
ASSERT(current_isr_num == 0); // If this is triggered, the CPU is currently in an interrupt.
// The CPU is in Thread mode (main context).
jump_to_addr(new_msp, reset_handler); // Jump directly to the App's Reset Handler.
}
ret_code_t nrf_bootloader_flash_protect(uint32_t address, uint32_t size)
{
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 mask = (ACL_ACL_PERM_WRITE_Disable << ACL_ACL_PERM_WRITE_Pos);
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++;
#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;
#if BPROT_REGIONS_NUM > 64
case 2:
NRF_BPROT->CONFIG2 = mask;
break;
case 3:
NRF_BPROT->CONFIG3 = mask;
break;
#endif
}
}
#endif
return NRF_SUCCESS;
}
void nrf_bootloader_app_start_final(uint32_t vector_table_addr)
{
ret_code_t ret_val;
// Size of the flash area to protect.
uint32_t area_size;
area_size = BOOTLOADER_SIZE + NRF_MBR_PARAMS_PAGE_SIZE;
if (!NRF_BL_DFU_ALLOW_UPDATE_FROM_APP && !NRF_BL_DFU_ENTER_METHOD_BUTTONLESS && !NRF_DFU_TRANSPORT_BLE)
{
area_size += BOOTLOADER_SETTINGS_PAGE_SIZE;
}
ret_val = nrf_bootloader_flash_protect(BOOTLOADER_START_ADDR, area_size);
if (ret_val != NRF_SUCCESS)
{
NRF_LOG_ERROR("Could not protect bootloader and settings pages, 0x%x.", ret_val);
}
APP_ERROR_CHECK(ret_val);
ret_val = nrf_bootloader_flash_protect(0,
nrf_dfu_bank0_start_addr() + ALIGN_TO_PAGE(s_dfu_settings.bank_0.image_size));
if (ret_val != NRF_SUCCESS)
{
NRF_LOG_ERROR("Could not protect SoftDevice and application, 0x%x.", ret_val);
}
APP_ERROR_CHECK(ret_val);
// Run application
app_start(vector_table_addr);
}

View File

@@ -0,0 +1,268 @@
/**
* Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_bootloader_dfu_timers.h"
#include <stdint.h>
#include <stdbool.h>
#include <nrfx.h>
#include "nrf_clock.h"
#include "nrf_rtc.h"
#include "nrf_delay.h"
#include "nrf_log.h"
#define RTC_PRESCALER (0) //!< The value provided to the RTC as the prescaler. 0 corresponds to one tick per clock cycle of the LFCLK (32768 ticks/s).
#define RTC_WRAP_TICKS ((1 << 24) - 1) //!< The largest possible value in the RTC counter register.
#define MAX_TIMEOUT_TICKS (RTC_WRAP_TICKS) //!< The longest fire timeout allowed. Longer timeouts are handled by multiple firings.
typedef struct
{
nrf_bootloader_dfu_timeout_callback_t callback; //!< Callback that is called when this timer times out.
uint32_t timeout; //!< The number of ticks from the next firing until the actual timeout. This value will be different from 0 if the original timeout was longer than MAX_TIMEOUT_TICKS, so multiple firings were needed.
uint32_t repeated_timeout; //!< If different from 0, this timer will be reactivated with this value after timing out.
uint8_t cc_channel; //!< Which CC register this timer uses.
} dfu_timer_t;
dfu_timer_t m_timers[2] = {{.cc_channel = 0}, {.cc_channel = 1}}; //!< The timers used by this module.
dfu_timer_t * mp_inactivity = &m_timers[0]; //!< Direct pointer to the inactivity timer, for convenience and readability.
dfu_timer_t * mp_wdt_feed = &m_timers[1]; //!< Direct pointer to the wdt feed timer, for convenience and readability.
uint32_t m_counter_loops = 0; //!< The number of times the RTC counter register has overflowed (wrapped around) since the RTC was started.
#if RTC_COUNT > 2
#define RTC_INSTANCE 2
#define RTC_STRUCT NRF_RTC2
#define RTC_IRQHandler RTC2_IRQHandler
#define RTC_IRQn RTC2_IRQn
#define RTC_CC_COUNT NRF_RTC_CC_CHANNEL_COUNT(2))
#elif RTC_COUNT > 1
#define RTC_INSTANCE 1
#define RTC_STRUCT NRF_RTC1
#define RTC_IRQHandler RTC1_IRQHandler
#define RTC_IRQn RTC1_IRQn
#define RTC_CC_COUNT NRF_RTC_CC_CHANNEL_COUNT(1))
#else
#error Not enough RTC instances.
#endif
/**@brief Function for initializing the timer if it is not already initialized.
*/
static void timer_init(void)
{
static bool m_timer_initialized;
if (!m_timer_initialized)
{
if (!nrf_clock_lf_is_running())
{
nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART);
}
nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_TICK);
nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_COMPARE_0);
nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_COMPARE_1);
NRFX_IRQ_PRIORITY_SET(RTC_IRQn, 5);
NRFX_IRQ_ENABLE(RTC_IRQn);
nrf_rtc_prescaler_set(RTC_STRUCT, RTC_PRESCALER);
nrf_rtc_task_trigger(RTC_STRUCT, NRF_RTC_TASK_CLEAR);
nrf_rtc_task_trigger(RTC_STRUCT, NRF_RTC_TASK_START);
nrf_rtc_int_enable(RTC_STRUCT, RTC_INTENSET_OVRFLW_Msk);
m_timer_initialized = true;
}
}
/**@brief Function for scheduling an RTC compare event.
*
* @param[in] cc_channel Which of the RTC compare registers to use.
* @param[in] cc_value The ticks value at which to receive the event.
*/
static void rtc_update(uint32_t cc_channel, uint32_t cc_value)
{
ASSERT(cc_channel < NRF_RTC_CC_CHANNEL_COUNT(RTC_INSTANCE));
nrf_rtc_cc_set(RTC_STRUCT, cc_channel, cc_value);
nrf_delay_us(31);
nrf_rtc_event_clear(RTC_STRUCT, RTC_CHANNEL_EVENT_ADDR(cc_channel));
nrf_rtc_int_enable(RTC_STRUCT, RTC_CHANNEL_INT_MASK(cc_channel));
}
/**@brief Function for activating a timer, so that it will be fired.
*
* This can happen multiple times before the actual timeout happens if the timeout is longer than
* @ref MAX_TIMEOUT_TICKS.
*
* @param[in] p_timer The timer to activate.
* @param[in] timeout_ticks The number of ticks until the timeout.
*
* @retval true If the timer was activated.
* @retval false If the timer is already active.
*/
static void timer_activate(dfu_timer_t * p_timer, uint32_t timeout_ticks)
{
NRF_LOG_DEBUG("timer_activate (0x%x)", p_timer);
ASSERT(timeout_ticks <= MAX_TIMEOUT_TICKS);
ASSERT(timeout_ticks >= NRF_BOOTLOADER_MIN_TIMEOUT_TICKS);
uint32_t next_timeout_ticks = MIN(timeout_ticks, MAX_TIMEOUT_TICKS);
uint32_t cc_value = RTC_WRAP(next_timeout_ticks + nrf_rtc_counter_get(RTC_STRUCT));
p_timer->timeout = timeout_ticks - next_timeout_ticks;
if ((p_timer->timeout > 0) && (p_timer->timeout < NRF_BOOTLOADER_MIN_TIMEOUT_TICKS))
{
p_timer->timeout += NRF_BOOTLOADER_MIN_TIMEOUT_TICKS;
cc_value -= NRF_BOOTLOADER_MIN_TIMEOUT_TICKS;
}
rtc_update(p_timer->cc_channel, cc_value);
}
/**@brief Function for deactivating a timer, so that it will not fire.
*
* @param[in] p_timer The timer to deactivate.
*
* @retval true If the timer was deactivated.
* @retval false If the timer is already inactive.
*/
static void timer_stop(dfu_timer_t * p_timer)
{
NRF_LOG_DEBUG("timer_stop (0x%x)", p_timer);
nrf_rtc_int_disable(RTC_STRUCT, RTC_CHANNEL_INT_MASK(p_timer->cc_channel));
}
/**@brief Function for firing a timer.
*
* This can happen multiple times before the actual timeout happens if the timeout is longer than
* @ref MAX_TIMEOUT_TICKS.
* This function reactivates the timer if the timer is repeating, or if the timer has not yet
* timed out. It then calls the callback if the timer (repeating or not) has timed out.
*
* @param[in] p_timer The timer to fire.
*/
static void timer_fire(dfu_timer_t * p_timer)
{
NRF_LOG_DEBUG("timer_fire (0x%x)", p_timer);
if (p_timer->timeout != 0)
{
// The timer has not yet timed out.
timer_activate(p_timer, p_timer->timeout);
return;
}
if (p_timer->repeated_timeout != 0)
{
timer_activate(p_timer, p_timer->repeated_timeout);
}
if (p_timer->callback != NULL)
{
p_timer->callback();
}
}
/**@brief Function for requesting a timeout.
*
* The timer will time out @p timeout_ticks ticks from now. When it times out, @p callback
* will be called, and if @p p_timer->repeated_timeout is not 0, a new timeout will be scheduled.
*
* @param[in] p_timer The timer to start.
* @param[in] timeout_ticks The number of ticks until the timeout.
* @param[in] callback The callback to call when the timer times out.
*/
static void timer_start(dfu_timer_t * p_timer,
uint32_t timeout_ticks,
nrf_bootloader_dfu_timeout_callback_t callback)
{
timer_init(); // Initialize if needed.
p_timer->callback = callback;
timer_activate(p_timer, timeout_ticks);
}
/**@brief Interrupt handler for the RTC (Real Time Clock) used for the DFU timers.
*/
void RTC_IRQHandler(void)
{
if (nrf_rtc_event_pending(RTC_STRUCT, NRF_RTC_EVENT_OVERFLOW))
{
m_counter_loops++;
nrf_rtc_event_clear(RTC_STRUCT, NRF_RTC_EVENT_OVERFLOW);
}
for (uint32_t channel = 0; channel < 2; channel++)
{
if (nrf_rtc_event_pending(RTC_STRUCT, RTC_CHANNEL_EVENT_ADDR(channel)))
{
nrf_rtc_event_clear(RTC_STRUCT, RTC_CHANNEL_EVENT_ADDR(channel));
timer_stop(&m_timers[channel]);
timer_fire(&m_timers[channel]);
}
}
}
void nrf_bootloader_dfu_inactivity_timer_restart(uint32_t timeout_ticks,
nrf_bootloader_dfu_timeout_callback_t callback)
{
timer_stop(mp_inactivity);
if (timeout_ticks != 0)
{
timer_start(mp_inactivity, timeout_ticks, callback);
}
}
void nrf_bootloader_wdt_feed_timer_start(uint32_t timeout_ticks,
nrf_bootloader_dfu_timeout_callback_t callback)
{
mp_wdt_feed->repeated_timeout = timeout_ticks;
timer_start(mp_wdt_feed, timeout_ticks, callback);
}
uint32_t nrf_bootloader_dfu_timer_counter_get(void)
{
return nrf_rtc_counter_get(RTC_STRUCT) + (m_counter_loops << 24);
}

View File

@@ -0,0 +1,111 @@
/**
* Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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
#define NRF_BOOTLOADER_MIN_TIMEOUT_TICKS (150) //!< The shortest timeout allowed. To avoid the timeout not being activated before the time has passed.
/**@brief Macro for converting milliseconds to timer ticks.
*
* @param[in] ms The milliseconds to convert.
*
* @return @p ms converted to ticks.
*/
#define NRF_BOOTLOADER_MS_TO_TICKS(ms) ((((uint64_t)(ms) * 32768)) / 1000)
/**@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_ticks The number of ticks until reset. There are 32768 ticks per second.
* 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_ticks,
nrf_bootloader_dfu_timeout_callback_t callback);
/**@brief Function for initializing and starting a repeated timer for feeding the watchdog.
*
* @param[in] timeout_ticks The number of ticks between each feeding of the watchdog. There are
* 32768 ticks per second.
* @param[in] callback Function called on every timeout.
*/
void nrf_bootloader_wdt_feed_timer_start(uint32_t timeout_ticks,
nrf_bootloader_dfu_timeout_callback_t callback);
/**@brief Function for retrieving the number of ticks since the RTC was started.
*
* There are 32768 ticks per second. This value does not wrap, even when the RTC counter wraps.
*
* @note The value can be 2^24 ticks too small if sampled immediately after the RTC counter wraps,
* but before the internal loop counter has been incremented.
*
* @return The number of ticks since the RTC was started.
*/
uint32_t nrf_bootloader_dfu_timer_counter_get(void);
#ifdef __cplusplus
}
#endif
#endif // NRF_BOOTLOADER_DFU_TIMERS_H__
/** @} */

View File

@@ -0,0 +1,441 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "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");
return NRF_SUCCESS;
}
ASSERT(src_addr >= dst_addr);
ASSERT(progress_update_step > 0);
if (size != 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_and_backup(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_and_backup(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;
}
else if (src_addr == 0)
{
src_addr = nrf_dfu_bank1_start_addr();
}
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_and_backup(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 && (s_dfu_settings.bank_0.bank_code == NRF_DFU_BANK_VALID_APP))
{
//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;
}

View File

@@ -0,0 +1,96 @@
/**
* Copyright (c) 2018 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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__
/** @} */

View File

@@ -0,0 +1,91 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_bootloader_info.h"
#include "nrf_dfu_types.h"
#include "nrf_nvmc.h"
#define UICR_BOOTLOADER_ADDR 0x10001014
/** @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(UICR_BOOTLOADER_ADDR)))
= 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 @ UICR_BOOTLOADER_ADDR
= BOOTLOADER_START_ADDR;
#endif
void nrf_bootloader_mbr_addrs_populate(void)
{
if (*(const uint32_t *)MBR_BOOTLOADER_ADDR == 0xFFFFFFFF)
{
nrf_nvmc_write_word(MBR_BOOTLOADER_ADDR, BOOTLOADER_START_ADDR);
}
if (*(const uint32_t *)MBR_PARAM_PAGE_ADDR == 0xFFFFFFFF)
{
nrf_nvmc_write_word(MBR_PARAM_PAGE_ADDR, NRF_MBR_PARAMS_PAGE_ADDRESS);
}
}
void nrf_bootloader_debug_port_disable(void)
{
if (NRF_UICR->APPROTECT != 0x0)
{
nrf_nvmc_write_word((uint32_t)&NRF_UICR->APPROTECT, 0x0);
NVIC_SystemReset();
}
#if (!defined (NRF52810_XXAA) && !defined (NRF52811_XXAA) && !defined (NRF52832_XXAA) && !defined (NRF52832_XXAB))
if (NRF_UICR->DEBUGCTRL != 0x0)
{
nrf_nvmc_write_word((uint32_t)&NRF_UICR->DEBUGCTRL, 0x0);
NVIC_SystemReset();
}
#endif
}

View File

@@ -0,0 +1,210 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@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 (__LINT__ == 1)
#define BOOTLOADER_SIZE (0x6000)
#elif 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)
#endif
#endif
// 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)))
#if defined(BLE_STACK_SUPPORT_REQD) || defined(ANT_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
/** @brief Defines a macro for retrieving the actual SoftDevice ID from a given base address. Use
* @ref MBR_SIZE as the argument when the SoftDevice is installed just above the MBR (the
* usual case). */
#ifndef SD_ID_GET
#define SD_ID_GET(baseaddr) ((SD_INFO_STRUCT_SIZE(baseaddr) > 0x10) \
? SD_OFFSET_GET_UINT32(baseaddr, 0x10) : 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 (0xF8) /**< Mask for GPGPREGRET bits used for the magic pattern written to GPREGRET register to signal between main app and DFU. */
#define BOOTLOADER_DFU_GPREGRET (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 (0xF8) /**< Mask for GPGPREGRET2 bits used for the magic pattern written to GPREGRET2 register to signal between main app and DFU. */
#define BOOTLOADER_DFU_GPREGRET2 (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 | 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 | BOOTLOADER_DFU_SKIP_CRC_BIT_MASK) /**< Magic number to signal that CRC can be skipped due to low power modes.*/
/** @brief Macro based on @c NRF_DFU_DEBUG_VERSION that can be checked for true/false instead of defined/not defined.
*/
#ifndef NRF_DFU_DEBUG
#ifdef NRF_DFU_DEBUG_VERSION
#define NRF_DFU_DEBUG 1
#else
#define NRF_DFU_DEBUG 0
#endif
#endif
/** @brief Function for populating addresses in the MBR code page.
*
* This function writes two words to flash if the flash is 0xFFFFFFFF. This is done in code because
* doing this through the hex file interferes with flashing algorithms. See nrf_mbr.h.
*/
void nrf_bootloader_mbr_addrs_populate(void);
/** @brief Function for checking if the debug port access is disabled.
*
* If the debug port access is enabled, disable it. This function checks and writes to the UICR
* registers APPROTECT and DEBUGCTRL.
*/
void nrf_bootloader_debug_port_disable(void);
#ifdef __cplusplus
}
#endif
#endif // #ifndef NRF_BOOTLOADER_INFO_H__
/** @} */

View File

@@ -0,0 +1,121 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "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();
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)
{
NRF_LOG_INFO("Internal feed");
wdt_feed();
}
void WDT_IRQHandler(void)
{
nrf_wdt_event_clear(NRF_WDT_EVENT_TIMEOUT);
NRF_LOG_FINAL_FLUSH();
}
#define MAX_FLASH_OP_TIME_TICKS 3200 // ~100 ms
void nrf_bootloader_wdt_init(void)
{
static bool initialized = false;
if (initialized)
{
return;
}
if (nrf_wdt_started())
{
uint32_t wdt_ticks = nrf_wdt_reload_value_get();
NRF_LOG_INFO("WDT enabled CRV:%d ticks", wdt_ticks);
//wdt_ticks must be reduced to feed the watchdog before the timeout.
uint32_t reduced_timeout_ticks = MAX((int32_t)wdt_ticks - MAX_FLASH_OP_TIME_TICKS,
NRF_BOOTLOADER_MIN_TIMEOUT_TICKS);
/* initial watchdog feed */
wdt_feed();
NRF_LOG_INFO("Starting a timer (%d ticks) for feeding watchdog.", reduced_timeout_ticks);
nrf_bootloader_wdt_feed_timer_start(reduced_timeout_ticks, 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();
}
}

View File

@@ -0,0 +1,79 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#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 a 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 timeout 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

View File

@@ -0,0 +1,273 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "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))
#if defined(NRF_DFU_PROTOCOL_REDUCED) && NRF_DFU_PROTOCOL_REDUCED
#error Serial DFU (UART and USB) cannot function with the reduced protocol set.
#endif
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]);
if (request.create.object_type == NRF_DFU_OBJ_TYPE_COMMAND)
{
/* Activity on the current transport. Close all except the current one. */
(void) nrf_dfu_transports_close(p_transport->p_low_level_transport);
}
} 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);
}

View File

@@ -0,0 +1,111 @@
/**
* Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_DFU_SERIAL_H__
#define NRF_DFU_SERIAL_H__
#include <stdint.h>
#include "sdk_errors.h"
#include "nrf_dfu_req_handler.h"
#include "nrf_dfu_transport.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_transport_t const * p_low_level_transport;
} 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__

View File

@@ -0,0 +1,238 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "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 = NRF_ERROR_TIMEOUT;
// Check if there is byte to process. Zero length transfer means that RXTO occured.
if (len)
{
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)
{
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];
m_serial.p_low_level_transport = &uart_dfu_transport;
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;
}

View File

@@ -0,0 +1,368 @@
/**
* Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <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;
}
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];
m_serial.p_low_level_transport = &usb_dfu_transport;
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;
}