xiaozhengsheng 6df0f7d96e 初始版本
2025-08-19 09:49:41 +08:00

773 lines
22 KiB
C

/**
* 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;
}