rcbench
Servo and ESC test bench: panel, IOmcu and shared C
Loading...
Searching...
No Matches
link_update_dev.c File Reference

The IOmcu's half of the firmware update. More...

#include "link_update_dev.h"
#include <stddef.h>
#include <string.h>
#include "link_crc.h"
#include "link_msg.h"

Functions

void link_update_dev_init (link_update_dev_t *u, const link_update_io_t *io, const uint8_t *running, const uint8_t *target, uint32_t slot_bytes, uint16_t slot)
 Start idle. slot is LINK_UPD_SLOT as the boot ROM reports it: the running slot, LINK_UPD_SLOT_NONE without a partition table this build writes, and LINK_UPD_SLOT_TRIAL for an image that waits for its BUY. running and target may be NULL with LINK_UPD_SLOT_NONE.
static bool in_session (uint8_t state)
 Test whether a state is inside an update session.
static bool gate_open (const link_update_dev_t *u)
 Ask the callback whether flash may be written.
static uint8_t refuse (link_update_dev_t *u, uint8_t err, uint8_t nack)
 A refusal: the reason kept for LINK_UPD_ERROR, the code for the NACK.
static uint8_t fail (link_update_dev_t *u, uint8_t err)
 A failure that ends the session.
static uint32_t arg32 (const uint16_t *a)
 Read a 32-bit argument held in two registers, low word first.
static uint8_t cmd_hash_running (link_update_dev_t *u, const uint16_t *a)
 Handle HASH_RUNNING: start hashing the running slot's image.
static uint8_t cmd_begin (link_update_dev_t *u, const uint16_t *a)
 Handle BEGIN: erase the first sector and open a receive session.
static void staged_bytes (const link_update_dev_t *u, uint8_t *out)
 The block staged in UPDATE_DATA as bytes, low byte of each register first.
static uint8_t cmd_commit (link_update_dev_t *u, const uint16_t *a)
 Handle COMMIT: check one staged block and place it.
static uint8_t cmd_finish (link_update_dev_t *u)
 Handle FINISH: start hashing the bytes as written.
static uint8_t cmd_activate (link_update_dev_t *u)
 Handle ACTIVATE: write the first sector and owe a restart.
static uint8_t cmd_abort (link_update_dev_t *u)
 Handle ABORT: return to idle.
static uint8_t cmd_buy (link_update_dev_t *u)
 Handle BUY: buy the image on trial and owe the other slot's erase.
void link_update_dev_read_ctl (link_update_dev_t *u, uint8_t offset, uint8_t count, uint16_t *out)
 The two pages' handlers, for the caller's link_page_t table.
uint8_t link_update_dev_write_ctl (link_update_dev_t *u, uint8_t offset, uint8_t count, const uint16_t *in)
 Write registers of the UPDATE_CTL page: one command and its arguments.
void link_update_dev_read_data (link_update_dev_t *u, uint8_t offset, uint8_t count, uint16_t *out)
 Read registers of the UPDATE_DATA page.
uint8_t link_update_dev_write_data (link_update_dev_t *u, uint8_t offset, uint8_t count, const uint16_t *in)
 Write registers of the UPDATE_DATA page: stage part of a block.
static const uint8_t * verify_src (const link_update_dev_t *u, uint32_t pos)
 Where the byte at pos of the image being checked is read from: the first sector from RAM, which ACTIVATE has not written yet.
static void sweep (link_update_dev_t *u, uint32_t now_ms)
 The owed erase of the other slot's first sector: outside a session and a trial, with the gate open, once every LINK_UPD_SWEEP_MS.
void link_update_dev_poll (link_update_dev_t *u, uint32_t now_ms)
 The work that does not fit a reply: LINK_UPD_HASH_STEP bytes of a hash, the restart LINK_UPD_RESTART_MS after ACTIVATE, an owed erase of the other slot's first sector, and the end of a session that has had no request to either update page for LINK_UPD_SILENCE_MS.
bool link_update_dev_holds_arm (const link_update_dev_t *u)
 True while ARM is refused: a session runs or an image waits for BUY.
bool link_update_dev_refuses_arm (const link_update_dev_t *u, uint8_t off, uint8_t n, const uint16_t *in)
 Whether a write of n CONTROL registers from off is refused for the update: it asks for a non-zero ARM while link_update_dev_holds_arm().

Detailed Description

The IOmcu's half of the firmware update.

See link_update_dev.h and the update section of link_pages.h.

SPDX-License-Identifier: MIT

Function Documentation

◆ arg32()

uint32_t arg32 ( const uint16_t * a)
static

Read a 32-bit argument held in two registers, low word first.

Parameters
aThe command registers; the argument is a[1] and a[2].
Returns
The 32-bit value.

◆ cmd_abort()

uint8_t cmd_abort ( link_update_dev_t * u)
static

Handle ABORT: return to idle.

Parameters
uThe update state; refused once ACTIVATED.
Returns
0 when the session is dropped, else the NACK reason.

◆ cmd_activate()

uint8_t cmd_activate ( link_update_dev_t * u)
static

Handle ACTIVATE: write the first sector and owe a restart.

Parameters
uThe update state; it must be VERIFIED.
Returns
0 when the first sector is written, else the NACK reason.

◆ cmd_begin()

uint8_t cmd_begin ( link_update_dev_t * u,
const uint16_t * a )
static

Handle BEGIN: erase the first sector and open a receive session.

Parameters
uThe update state.
aThe command registers; the image size is arg32(a).
Returns
0 when the session opens, else the NACK reason.

◆ cmd_buy()

uint8_t cmd_buy ( link_update_dev_t * u)
static

Handle BUY: buy the image on trial and owe the other slot's erase.

Parameters
uThe update state.
Returns
0 when the image is bought or was never on trial, else the NACK reason.

◆ cmd_commit()

uint8_t cmd_commit ( link_update_dev_t * u,
const uint16_t * a )
static

Handle COMMIT: check one staged block and place it.

Parameters
uThe update state.
aThe command registers: a[1] is the block, a[2] its CRC.
Returns
0 when the block is taken or is the repeat of the block before the next one, else the NACK reason.

◆ cmd_finish()

uint8_t cmd_finish ( link_update_dev_t * u)
static

Handle FINISH: start hashing the bytes as written.

Parameters
uThe update state; it must be RECEIVED.
Returns
0 when the hash starts, else the NACK reason.

◆ cmd_hash_running()

uint8_t cmd_hash_running ( link_update_dev_t * u,
const uint16_t * a )
static

Handle HASH_RUNNING: start hashing the running slot's image.

Parameters
uThe update state.
aThe command registers; the length is arg32(a).
Returns
0 when the hash starts, else the NACK reason.

◆ fail()

uint8_t fail ( link_update_dev_t * u,
uint8_t err )
static

A failure that ends the session.

Parameters
uThe update state.
errThe reason, a link_upd_err_t.
Returns
LINK_NACK_BAD_VALUE.

◆ gate_open()

bool gate_open ( const link_update_dev_t * u)
static

Ask the callback whether flash may be written.

Parameters
uThe update state; u->io must be set.
Returns
true when there is no gate callback or it reports the gate open.

◆ in_session()

bool in_session ( uint8_t state)
static

Test whether a state is inside an update session.

Parameters
stateA link_upd_state_t value.
Returns
true for RECEIVING, RECEIVED, VERIFYING and VERIFIED.

◆ link_update_dev_holds_arm()

bool link_update_dev_holds_arm ( const link_update_dev_t * u)

True while ARM is refused: a session runs or an image waits for BUY.

Parameters
uThe update state; NULL gives false.
Returns
true while a session runs, an ACTIVATE is pending, or an image waits for BUY.

◆ link_update_dev_init()

void link_update_dev_init ( link_update_dev_t * u,
const link_update_io_t * io,
const uint8_t * running,
const uint8_t * target,
uint32_t slot_bytes,
uint16_t slot )

Start idle. slot is LINK_UPD_SLOT as the boot ROM reports it: the running slot, LINK_UPD_SLOT_NONE without a partition table this build writes, and LINK_UPD_SLOT_TRIAL for an image that waits for its BUY. running and target may be NULL with LINK_UPD_SLOT_NONE.

A bought image that finds the other slot's first sector written owes its erase.

Parameters
uThe update state to set up.
ioThe callbacks; kept, not copied.
runningThe running slot's bytes.
targetThe other slot's bytes.
slot_bytesBytes in one slot, a multiple of the 4KiB sector.
slotLINK_UPD_SLOT as the boot ROM reports it.

◆ link_update_dev_poll()

void link_update_dev_poll ( link_update_dev_t * u,
uint32_t now_ms )

The work that does not fit a reply: LINK_UPD_HASH_STEP bytes of a hash, the restart LINK_UPD_RESTART_MS after ACTIVATE, an owed erase of the other slot's first sector, and the end of a session that has had no request to either update page for LINK_UPD_SILENCE_MS.

Once per pass of the caller's loop.

Parameters
uThe update state.
now_msThe current time, in ms.

◆ link_update_dev_read_ctl()

void link_update_dev_read_ctl ( link_update_dev_t * u,
uint8_t offset,
uint8_t count,
uint16_t * out )

The two pages' handlers, for the caller's link_page_t table.

Parameters
uThe update state.
offsetFirst register, 0 to LINK_UPD_COUNT - 1.
countNumber of registers to read.
outReceives the registers.

◆ link_update_dev_read_data()

void link_update_dev_read_data ( link_update_dev_t * u,
uint8_t offset,
uint8_t count,
uint16_t * out )

Read registers of the UPDATE_DATA page.

Parameters
uThe update state.
offsetFirst register of the staged block.
countNumber of registers to read.
outReceives the registers.

◆ link_update_dev_refuses_arm()

bool link_update_dev_refuses_arm ( const link_update_dev_t * u,
uint8_t off,
uint8_t n,
const uint16_t * in )

Whether a write of n CONTROL registers from off is refused for the update: it asks for a non-zero ARM while link_update_dev_holds_arm().

The caller answers it with LINK_NACK_NOT_ARMED before the page's own rules run, so nothing of the frame is stored. A disarm is always taken.

Parameters
uThe update state.
offFirst CONTROL register of the write.
nNumber of registers in the write.
inThe registers written.
Returns
true when the write must be refused.

◆ link_update_dev_write_ctl()

uint8_t link_update_dev_write_ctl ( link_update_dev_t * u,
uint8_t offset,
uint8_t count,
const uint16_t * in )

Write registers of the UPDATE_CTL page: one command and its arguments.

Parameters
uThe update state.
offsetFirst register; must be LINK_UPD_CMD.
countNumber of registers, 1 to 4.
inThe registers written.
Returns
0 when the command is taken, else the NACK reason.

◆ link_update_dev_write_data()

uint8_t link_update_dev_write_data ( link_update_dev_t * u,
uint8_t offset,
uint8_t count,
const uint16_t * in )

Write registers of the UPDATE_DATA page: stage part of a block.

Parameters
uThe update state.
offsetFirst register of the block, 0 to LINK_UPD_DATA_COUNT - 1.
countNumber of registers written.
inThe registers written.
Returns
0 when stored, LINK_NACK_BAD_RANGE when the window does not fit the block, or when the arguments are NULL.

◆ refuse()

uint8_t refuse ( link_update_dev_t * u,
uint8_t err,
uint8_t nack )
static

A refusal: the reason kept for LINK_UPD_ERROR, the code for the NACK.

Parameters
uThe update state.
errThe reason, a link_upd_err_t, kept in u->error.
nackThe NACK code returned to the caller.
Returns
nack.

◆ staged_bytes()

void staged_bytes ( const link_update_dev_t * u,
uint8_t * out )
static

The block staged in UPDATE_DATA as bytes, low byte of each register first.

Parameters
uThe update state; its data registers are read.
outReceives 2 * LINK_UPD_DATA_COUNT bytes.

◆ sweep()

void sweep ( link_update_dev_t * u,
uint32_t now_ms )
static

The owed erase of the other slot's first sector: outside a session and a trial, with the gate open, once every LINK_UPD_SWEEP_MS.

Parameters
uThe update state.
now_msThe current time, in ms.

◆ verify_src()

const uint8_t * verify_src ( const link_update_dev_t * u,
uint32_t pos )
static

Where the byte at pos of the image being checked is read from: the first sector from RAM, which ACTIVATE has not written yet.

Parameters
uThe update state.
posByte offset within the image.
Returns
Pointer to the byte.