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

The IOmcu end of the link: page dispatch, the arm latch and the failsafe tick. More...

#include "link_dev.h"
#include <string.h>

Functions

static bool elapsed (uint32_t now, uint32_t then, uint32_t ms)
 Wrap-safe: (uint32_t)(now - then) >= timeout holds across the 32-bit millisecond wrap at 49.7 days; now >= then + timeout does not.
static const link_page_t * find_page (const link_dev_t *d, uint8_t page)
 Find the page with a given number.
void link_dev_init (link_dev_t *d, const link_page_t *pages, uint8_t page_count, void *ctx, uint32_t now_ms)
 Start with no request heard, out of failsafe and with the arm latch set: the first ARM after a start needs a CLEAR ahead of it.
void link_dev_latch_arm (link_dev_t *d)
 Set the arm latch: a cause other than link silence took the outputs down, and the ARM the host goes on writing does not bring them back.
bool link_dev_arm_latched (const link_dev_t *d)
 Whether a write of ARM is refused until the host writes CLEAR.
void link_dev_clear_failsafe (link_dev_t *d, uint32_t now_ms)
 Leave failsafe and release the arm latch.
static void refuse (link_msg_t *reply, const link_msg_t *req, link_nack_t why)
 Build a NACK for a request, with its reason in regs[0].
bool link_dev_dispatch (link_dev_t *d, const link_msg_t *req, link_msg_t *reply, uint32_t now_ms)
 Decide what to answer, without deciding how to carry it: which page, whether the range fits, whether the write is accepted, and what a NACK (negative acknowledge) says.
bool link_dev_apply (const link_dev_t *d, const link_msg_t *req, link_msg_t *reply)
 What link_dev_dispatch() answers, without touching the silence watchdog: the same page lookup, range check, read, write and refusals.
bool link_dev_tick (link_dev_t *d, uint32_t now_ms)
 Advance the silence watchdog.

Detailed Description

The IOmcu end of the link: page dispatch, the arm latch and the failsafe tick.

SPDX-License-Identifier: MIT

Function Documentation

◆ elapsed()

bool elapsed ( uint32_t now,
uint32_t then,
uint32_t ms )
static

Wrap-safe: (uint32_t)(now - then) >= timeout holds across the 32-bit millisecond wrap at 49.7 days; now >= then + timeout does not.

Parameters
nowThe current time, in ms.
thenThe time the wait started, in ms.
msThe timeout, in ms.
Returns
true when at least ms milliseconds have passed since then.

◆ find_page()

const link_page_t * find_page ( const link_dev_t * d,
uint8_t page )
static

Find the page with a given number.

Parameters
dThe link state holding the page table.
pageThe page number to find.
Returns
The table entry, or NULL when the table has no such page.

◆ link_dev_apply()

bool link_dev_apply ( const link_dev_t * d,
const link_msg_t * req,
link_msg_t * reply )

What link_dev_dispatch() answers, without touching the silence watchdog: the same page lookup, range check, read, write and refusals.

For a caller on this end that is not the link, such as the bench console (page_console.h): a request from there proves nothing about the panel, so it must not hold the failsafe off.

False only on a null argument.

Parameters
dThe link state.
reqThe request to answer.
replyReceives the answer.
Returns
true when a reply was built, false on a null argument.

◆ link_dev_arm_latched()

bool link_dev_arm_latched ( const link_dev_t * d)

Whether a write of ARM is refused until the host writes CLEAR.

Parameters
dThe link state; NULL counts as latched.
Returns
true while the latch is set.

◆ link_dev_clear_failsafe()

void link_dev_clear_failsafe ( link_dev_t * d,
uint32_t now_ms )

Leave failsafe and release the arm latch.

Not exposed as "the link came back": recovery of the wire is not consent to spin a propeller, so the host asks for this by writing LINK_CLEAR_MAGIC to the control page.

Parameters
dThe link state.
now_msThe current time, in ms; restarts the silence watchdog.

◆ link_dev_dispatch()

bool link_dev_dispatch ( link_dev_t * d,
const link_msg_t * req,
link_msg_t * reply,
uint32_t now_ms )

Decide what to answer, without deciding how to carry it: which page, whether the range fits, whether the write is accepted, and what a NACK (negative acknowledge) says.

No transport is visible from here.

False only on a null argument. Every request produces exactly one reply, refusals included: silence means an IOmcu that is not there, and must not also mean a declined request.

Parameters
dThe link state.
reqThe request received.
replyReceives the answer: DATA, ACK or NACK.
now_msThe current time, in ms; restarts the silence watchdog.
Returns
true when a reply was built, false on a null argument.

◆ link_dev_init()

void link_dev_init ( link_dev_t * d,
const link_page_t * pages,
uint8_t page_count,
void * ctx,
uint32_t now_ms )

Start with no request heard, out of failsafe and with the arm latch set: the first ARM after a start needs a CLEAR ahead of it.

Parameters
dThe link state to set up.
pagesThe page table; kept, not copied.
page_countEntries in pages.
ctxPassed to every page callback.
now_msThe current time, in ms.

◆ link_dev_latch_arm()

void link_dev_latch_arm ( link_dev_t * d)

Set the arm latch: a cause other than link silence took the outputs down, and the ARM the host goes on writing does not bring them back.

Leaves failsafe as it is.

Parameters
dThe link state.

◆ link_dev_tick()

bool link_dev_tick ( link_dev_t * d,
uint32_t now_ms )

Advance the silence watchdog.

Returns true on the edge where failsafe fires, so the caller can drop the outputs once rather than every tick. The edge sets the arm latch too.

Parameters
dThe link state.
now_msThe current time, in ms.
Returns
true only on the tick where failsafe fires.

◆ refuse()

void refuse ( link_msg_t * reply,
const link_msg_t * req,
link_nack_t why )
static

Build a NACK for a request, with its reason in regs[0].

Parameters
replyReceives the NACK; cleared first.
reqThe request being refused; its page and offset are echoed.
whyThe reason, sent as regs[0].