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

The panel's side of the programming ports' page. More...

#include "prog_link.h"
#include <stddef.h>
#include <string.h>

Functions

void prog_link_init (prog_link_t *p)
 No link, no page, nothing wanted.
void prog_link_came_up (prog_link_t *p, uint16_t minor)
 An IOmcu answered with protocol minor minor.
void prog_link_lost (prog_link_t *p)
 The link is down: no page, no link.
bool prog_link_hitec_due (const prog_link_t *p)
 The HITEC page beside the PROG page (protocol 4.23): a session the bench console opens holds a port the panel's rows must leave alone.
void prog_link_hitec_read (prog_link_t *p, const uint16_t *state)
 The HITEC STATE register as read, state NULL for a read nobody answered: the port it names is held from STOPPING on, free at FREE.
uint8_t prog_link_hitec_held (const prog_link_t *p)
 Bit n: the HITEC page holds port n, as last read; 0 with no link, no page or nothing read since the link came up.
static void target_seen (prog_link_t *p, uint16_t t)
 The TARGET now known to be t: a change from the one known before returned the SERVO rate to 0.
prog_link_rate_t prog_link_rate (prog_link_t *p)
 What the reads and writes since the last call did to the SERVO rate, and forgets it.
void prog_link_want (prog_link_t *p, uint8_t target, bool pwm)
 What the screen wants: target 0 for the standard outputs or 1 + n for port n, and whether that port renders its pulse.
void prog_link_hold (prog_link_t *p, bool held)
 Whether the servo programmer has a port (kst_prog_port_taken()).
bool prog_link_held (const prog_link_t *p)
 Whether the servo programmer holds a port.
bool prog_link_no_drive (const prog_link_t *p)
 Whether the screen wants a port the page cannot make the target: one the IOmcu does not have, one without a pin the PWM generator holds (none, refused, or FUNCTION NONE), or one an ask waits on.
bool prog_link_command (const prog_link_t *p, bool release)
 Whether the tester sends a command now, a release for release.
bool prog_link_read_due (const prog_link_t *p, uint32_t now_ms)
 Whether the page is to be read now: it is unknown, or PROG_LINK_POLL_MS have passed.
void prog_link_read (prog_link_t *p, const uint16_t *regs, uint32_t now_ms)
 The page as read, prog_link_regs() registers, or NULL for a read that was not answered: the page is unknown then.
void prog_link_stale (prog_link_t *p)
 The page is unknown until it is read again.
static bool known (const prog_link_t *p)
 Whether the page is known: the IOmcu has it and it is read.
static bool asking (const prog_link_t *p, unsigned port)
 Whether an ask waits on port port.
uint8_t prog_link_regs (const prog_link_t *p)
 The registers a read of the page asks for: LINK_PG_REGS from 4.26, LINK_PG_REGS_V424 before.
bool prog_link_has_func (const prog_link_t *p)
 Whether the IOmcu takes a FUNC: protocol 4.26 or later.
bool prog_link_has_dshot (const prog_link_t *p)
 Whether the IOmcu takes FUNC DSHOT150 to DSHOT600: protocol 4.28 or later.
bool prog_link_ask (prog_link_t *p, uint8_t port, prog_link_ask_kind_t kind, uint16_t value)
 Ask for port port's PIN (value a GPIO, or LINK_PG_PIN_NONE) or FUNC (a link_pg_func_t) to be written.
prog_link_ask_state_t prog_link_ask_state (const prog_link_t *p, uint8_t *port, uint8_t *kind, uint16_t *value)
 Where the last ask stands, and what it was (port, kind, value may be NULL).
static uint8_t ask_reg (const prog_link_t *p)
 The register the ask waiting writes.
uint8_t prog_link_wanted (const prog_link_t *p)
 The target the screen can have: what is wanted, or 0 when the page has no such port, the port has no pin bound to the PWM generator – the IOmcu refuses such a target – or an ask for that port waits.
bool prog_link_ready (const prog_link_t *p)
 Whether prog_link_target() is the IOmcu's: there is no page, or the page is read.
uint8_t prog_link_target (const prog_link_t *p)
 The target as the IOmcu holds it; 0 without a page or a read.
bool prog_link_pending (const prog_link_t *p)
 Whether a target change waits: the page is known and its target is not the one prog_link_wanted() names.
bool prog_link_settled (const prog_link_t *p)
 Whether the tester may command: there is no page, or the page is known and its target is the one wanted.
bool prog_link_pwm (const prog_link_t *p)
 Whether the target port renders its pulse, as the page holds it.
static uint16_t pwm_wanted (const prog_link_t *p)
 The pulse bits the page is to hold: the wanted port's while that port is the target the page holds, no other.
bool prog_link_next (const prog_link_t *p, bool quiet, prog_link_write_t *w)
 The write that is due, into w.
uint8_t prog_link_pulse_on (const prog_link_t *p, const prog_link_write_t *w)
 The port w switches its pulse on for, as 1 + n, or 0 for a write that switches none on.
void prog_link_written (prog_link_t *p, const prog_link_write_t *w, bool ack)
 What became of w: acknowledged, or not (refused or unanswered), which makes the page unknown.
uint8_t prog_link_count (const prog_link_t *p)
 The ports the IOmcu's page reports (register COUNT), at most LINK_PG_PORTS_MAX: 0 for an IOmcu without the page (protocol older than 4.13), PROG_LINK_COUNT_UNKNOWN with no link or before the page's first read since the link came up, a write not acknowledged, or a read not answered (prog_link_stale()).
uint8_t prog_link_pin (const prog_link_t *p, uint8_t port)
 The GPIO port port is bound to, or PROG_LINK_NO_PIN: no page, no read, no such port, no pin, or a pin the IOmcu refused.
bool prog_link_port (const prog_link_t *p, uint8_t port, prog_link_port_t *out)
 Port port as the page holds it into out.
prog_link_drive_t prog_link_drive (const prog_link_t *p)
 Where the tester's commands go now, for the SERVO screen's TARGET row.
void prog_link_cfg (const uint16_t *cc, uint16_t *out)
 A channel's configuration as the CHAN_CFG page takes it (LINK_CC_STRIDE registers) as a port takes it from LINK_PG_SLEW on: SLEW, MIN_US, MAX_US.

Detailed Description

The panel's side of the programming ports' page.

See prog_link.h.

SPDX-License-Identifier: MIT

Function Documentation

◆ ask_reg()

uint8_t ask_reg ( const prog_link_t * p)
static

The register the ask waiting writes.

Parameters
pThe link state.
Returns
The register number.

◆ asking()

bool asking ( const prog_link_t * p,
unsigned port )
static

Whether an ask waits on port port.

Parameters
pThe link state.
portThe port.
Returns
true when an ask waits on the port.

◆ known()

bool known ( const prog_link_t * p)
static

Whether the page is known: the IOmcu has it and it is read.

Parameters
pThe link state.
Returns
true when the page is known.

◆ prog_link_ask()

bool prog_link_ask ( prog_link_t * p,
uint8_t port,
prog_link_ask_kind_t kind,
uint16_t value )

Ask for port port's PIN (value a GPIO, or LINK_PG_PIN_NONE) or FUNC (a link_pg_func_t) to be written.

True when taken: the page is there, the port is one it has, and for FUNC the IOmcu has the register and value is SERVO PWM or NONE, or from 4.28 DSHOT150, DSHOT300 or DSHOT600. A later ask replaces one still waiting. prog_link_next() writes it on a bench at rest.

Parameters
pThe link state.
portThe port.
kindPIN or FUNC.
valueThe GPIO, or the link_pg_func_t.
Returns
true when the ask is taken.

◆ prog_link_ask_state()

prog_link_ask_state_t prog_link_ask_state ( const prog_link_t * p,
uint8_t * port,
uint8_t * kind,
uint16_t * value )

Where the last ask stands, and what it was (port, kind, value may be NULL).

Parameters
pThe link state.
portReceives the port, or NULL.
kindReceives the kind, or NULL.
valueReceives the value, or NULL.
Returns
Where the last ask stands.

◆ prog_link_came_up()

void prog_link_came_up ( prog_link_t * p,
uint16_t minor )

An IOmcu answered with protocol minor minor.

What is wanted stays; the page is unknown.

Parameters
pThe link state.
minorThe IOmcu's protocol minor version.

◆ prog_link_cfg()

void prog_link_cfg ( const uint16_t * cc,
uint16_t * out )

A channel's configuration as the CHAN_CFG page takes it (LINK_CC_STRIDE registers) as a port takes it from LINK_PG_SLEW on: SLEW, MIN_US, MAX_US.

Parameters
ccThe channel's CHAN_CFG registers, LINK_CC_STRIDE of them.
outReceives SLEW, MIN_US and MAX_US.

◆ prog_link_command()

bool prog_link_command ( const prog_link_t * p,
bool release )

Whether the tester sends a command now, a release for release.

Not before the page is read (prog_link_ready()); not to a port while the programmer has one, a release neither – it stays owed; and a command that is not a release only once the target is the one wanted (prog_link_settled()) and the screen wants one that can be driven (prog_link_no_drive()).

Parameters
pThe link state.
releasetrue for a release command.
Returns
true when the tester sends the command now.

◆ prog_link_count()

uint8_t prog_link_count ( const prog_link_t * p)

The ports the IOmcu's page reports (register COUNT), at most LINK_PG_PORTS_MAX: 0 for an IOmcu without the page (protocol older than 4.13), PROG_LINK_COUNT_UNKNOWN with no link or before the page's first read since the link came up, a write not acknowledged, or a read not answered (prog_link_stale()).

Parameters
pThe link state.
Returns
The ports the page reports, or PROG_LINK_COUNT_UNKNOWN.

◆ prog_link_drive()

prog_link_drive_t prog_link_drive ( const prog_link_t * p)

Where the tester's commands go now, for the SERVO screen's TARGET row.

PROG_LINK_TARGET_NO_LINK with no IOmcu answering (before the first prog_link_came_up() and after prog_link_lost()), PROG_LINK_TARGET_UNKNOWN while the page is there and not known (not read yet, a read not answered, a write not acknowledged). The tester sends no command in either: nothing crosses a link that is down, and prog_link_command() is false while the page is not known. An IOmcu without the page has target 0.

While the servo programmer holds the port (prog_link_hold(true)) the target is unchanged: the line keeps naming the target the IOmcu holds, a port or the standard outputs. The programmer drives the port and the tester sends nothing.

Otherwise the target is prog_link_target(), the one the commands use; the pin is the target port's GPIO, or PROG_LINK_NO_PIN with the standard outputs as target or a port without a usable pin (none, refused, or a port the page does not have); pwm is prog_link_pwm(), false with target

  1. A port target without a pin stays a port target: the commands still go to the port and do not reach the SERVO PWM outputs, which an armed bank holds at their rest, the centre between their endpoints. With prog_link_no_drive() and target 0 the target is the port the screen wants, with no pin and pwm as wanted: the tester sends no command.
Parameters
pThe link state.
Returns
Where the tester's commands go now.

◆ prog_link_has_dshot()

bool prog_link_has_dshot ( const prog_link_t * p)

Whether the IOmcu takes FUNC DSHOT150 to DSHOT600: protocol 4.28 or later.

Parameters
pThe link state.
Returns
true when the IOmcu takes FUNC DSHOT150 to DSHOT600.

◆ prog_link_has_func()

bool prog_link_has_func ( const prog_link_t * p)

Whether the IOmcu takes a FUNC: protocol 4.26 or later.

Parameters
pThe link state.
Returns
true when the IOmcu takes a FUNC.

◆ prog_link_held()

bool prog_link_held ( const prog_link_t * p)

Whether the servo programmer holds a port.

Parameters
pThe link state.
Returns
true while the programmer holds a port.

◆ prog_link_hitec_due()

bool prog_link_hitec_due ( const prog_link_t * p)

The HITEC page beside the PROG page (protocol 4.23): a session the bench console opens holds a port the panel's rows must leave alone.

Whether its STATE register is read with the PROG page: an IOmcu answers that has the page.

Parameters
pThe link state.
Returns
true when the HITEC STATE register is read with the PROG page.

◆ prog_link_hitec_held()

uint8_t prog_link_hitec_held ( const prog_link_t * p)

Bit n: the HITEC page holds port n, as last read; 0 with no link, no page or nothing read since the link came up.

Parameters
pThe link state.
Returns
Bit n set while the HITEC page holds port n.

◆ prog_link_hitec_read()

void prog_link_hitec_read ( prog_link_t * p,
const uint16_t * state )

The HITEC STATE register as read, state NULL for a read nobody answered: the port it names is held from STOPPING on, free at FREE.

A read not answered keeps what was known.

Parameters
pThe link state.
stateThe STATE register as read, or NULL for a read nobody answered.

◆ prog_link_hold()

void prog_link_hold ( prog_link_t * p,
bool held )

Whether the servo programmer has a port (kst_prog_port_taken()).

While it has, the page is read and not written: prog_link_want() changes nothing, prog_link_next() names no write – not a pulse switched off either – prog_link_pending() is false and prog_link_command() takes no command for a port. What is wanted afterwards is what prog_link_want() says after the hold.

Parameters
pThe link state.
heldtrue while the servo programmer has a port.

◆ prog_link_init()

void prog_link_init ( prog_link_t * p)

No link, no page, nothing wanted.

Parameters
pThe link state to set up.

◆ prog_link_lost()

void prog_link_lost ( prog_link_t * p)

The link is down: no page, no link.

Parameters
pThe link state.

◆ prog_link_next()

bool prog_link_next ( const prog_link_t * p,
bool quiet,
prog_link_write_t * w )

The write that is due, into w.

quiet says the bank is disarmed and no surface holds a position this panel wrote. False for none: no page, the page unknown, nothing differs, or what differs waits for quiet. The pulse is switched off before the target changes and on after. An ask (prog_link_ask()) is written on a bench at rest once its port is neither the target nor pulsing, before the pulse goes back on.

Parameters
pThe link state.
quiettrue when the bank is disarmed and no surface holds a position this panel wrote.
wReceives the write that is due.
Returns
true when a write is due.

◆ prog_link_no_drive()

bool prog_link_no_drive ( const prog_link_t * p)

Whether the screen wants a port the page cannot make the target: one the IOmcu does not have, one without a pin the PWM generator holds (none, refused, or FUNCTION NONE), or one an ask waits on.

prog_link_wanted() is then 0, so the IOmcu's target is the standard outputs; the tester drives nothing in their place (prog_link_command() takes no command but a release). False before the page is read and with an IOmcu without the page, whose target is the standard outputs.

Parameters
pThe link state.
Returns
true when the screen wants a port the page cannot make the target.

◆ prog_link_pending()

bool prog_link_pending ( const prog_link_t * p)

Whether a target change waits: the page is known and its target is not the one prog_link_wanted() names.

Parameters
pThe link state.
Returns
true while a target change waits.

◆ prog_link_pin()

uint8_t prog_link_pin ( const prog_link_t * p,
uint8_t port )

The GPIO port port is bound to, or PROG_LINK_NO_PIN: no page, no read, no such port, no pin, or a pin the IOmcu refused.

Parameters
pThe link state.
portThe port.
Returns
The GPIO the port is bound to, or PROG_LINK_NO_PIN.

◆ prog_link_port()

bool prog_link_port ( const prog_link_t * p,
uint8_t port,
prog_link_port_t * out )

Port port as the page holds it into out.

False, and out untouched, with no page, no read or no such port.

Parameters
pThe link state.
portThe port.
outReceives the port as the page holds it.
Returns
true when out holds the port.

◆ prog_link_pulse_on()

uint8_t prog_link_pulse_on ( const prog_link_t * p,
const prog_link_write_t * w )

The port w switches its pulse on for, as 1 + n, or 0 for a write that switches none on.

An IOmcu from protocol 4.16 refuses that write while the port's range is longer than the frame it runs at (1784us at 560Hz), so the panel states the range the screen names to the port first: a range kept from an earlier profile would keep it refused.

Parameters
pThe link state.
wThe write.
Returns
The port the write switches its pulse on for, as 1 + n, or 0 for none.

◆ prog_link_pwm()

bool prog_link_pwm ( const prog_link_t * p)

Whether the target port renders its pulse, as the page holds it.

False with the standard outputs as target.

Parameters
pThe link state.
Returns
true when the target port renders its pulse.

◆ prog_link_rate()

prog_link_rate_t prog_link_rate ( prog_link_t * p)

What the reads and writes since the last call did to the SERVO rate, and forgets it.

From 4.19: PROG_LINK_RATE_RESET once a read or an acknowledged write shows a TARGET other than the one known before, and PROG_LINK_RATE_UNKNOWN once a TARGET write went unacknowledged, which may or may not have changed it; the stronger of the two when both happened. Always PROG_LINK_RATE_KEPT below 4.19, where the rate does not follow the target, and for the first TARGET known after a link-up.

Parameters
pThe link state.
Returns
What the reads and writes did to the SERVO rate.

◆ prog_link_read()

void prog_link_read ( prog_link_t * p,
const uint16_t * regs,
uint32_t now_ms )

The page as read, prog_link_regs() registers, or NULL for a read that was not answered: the page is unknown then.

Below 4.26 every port's FUNC is taken as SERVO PWM.

Parameters
pThe link state.
regsThe page as read, or NULL for a read not answered.
now_msThe time, in ms.

◆ prog_link_read_due()

bool prog_link_read_due ( const prog_link_t * p,
uint32_t now_ms )

Whether the page is to be read now: it is unknown, or PROG_LINK_POLL_MS have passed.

Parameters
pThe link state.
now_msThe time, in ms.
Returns
true when the page is to be read now.

◆ prog_link_ready()

bool prog_link_ready ( const prog_link_t * p)

Whether prog_link_target() is the IOmcu's: there is no page, or the page is read.

A release goes to the target that holds the pulse, so it waits for this and not for prog_link_settled().

Parameters
pThe link state.
Returns
true when prog_link_target() is the IOmcu's.

◆ prog_link_regs()

uint8_t prog_link_regs ( const prog_link_t * p)

The registers a read of the page asks for: LINK_PG_REGS from 4.26, LINK_PG_REGS_V424 before.

Parameters
pThe link state.
Returns
The number of registers a read of the page asks for.

◆ prog_link_settled()

bool prog_link_settled ( const prog_link_t * p)

Whether the tester may command: there is no page, or the page is known and its target is the one wanted.

The pulse bit is not part of it.

Parameters
pThe link state.
Returns
true when the tester may command.

◆ prog_link_stale()

void prog_link_stale ( prog_link_t * p)

The page is unknown until it is read again.

Parameters
pThe link state.

◆ prog_link_target()

uint8_t prog_link_target ( const prog_link_t * p)

The target as the IOmcu holds it; 0 without a page or a read.

Parameters
pThe link state.
Returns
The target as the IOmcu holds it.

◆ prog_link_want()

void prog_link_want ( prog_link_t * p,
uint8_t target,
bool pwm )

What the screen wants: target 0 for the standard outputs or 1 + n for port n, and whether that port renders its pulse.

A target above LINK_PG_PORTS_MAX is taken as 0.

Parameters
pThe link state.
target0 for the standard outputs, or 1 + n for port n.
pwmtrue when that port renders its pulse.

◆ prog_link_wanted()

uint8_t prog_link_wanted ( const prog_link_t * p)

The target the screen can have: what is wanted, or 0 when the page has no such port, the port has no pin bound to the PWM generator – the IOmcu refuses such a target – or an ask for that port waits.

0 while the page is unknown or absent.

Parameters
pThe link state.
Returns
The target the screen can have.

◆ prog_link_written()

void prog_link_written ( prog_link_t * p,
const prog_link_write_t * w,
bool ack )

What became of w: acknowledged, or not (refused or unanswered), which makes the page unknown.

Parameters
pThe link state.
wThe write.
acktrue when the write was acknowledged.

◆ pwm_wanted()

uint16_t pwm_wanted ( const prog_link_t * p)
static

The pulse bits the page is to hold: the wanted port's while that port is the target the page holds, no other.

Parameters
pThe link state.
Returns
The pulse bits: 1 << (target - 1) for the wanted port, else 0.

◆ target_seen()

void target_seen ( prog_link_t * p,
uint16_t t )
static

The TARGET now known to be t: a change from the one known before returned the SERVO rate to 0.

Parameters
pThe link state.
tThe TARGET read or written.