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

Binding a protocol to pins. More...

#include "out_bind.h"
#include <stddef.h>
#include <string.h>
#include "link_pages.h"
#include "out_pwm_map.h"
#include "outputs_pages.h"

Functions

const outbind_board_t * outbind_board (uint16_t id)
 The board with this identity, or NULL when nothing here describes it.
static const char * hold_name (uint8_t hold)
 The panel's words for what the wire can only number. The panel shows them through ui_pin_holder(), in the language showing.
void outbind_board_to_regs (const outbind_board_t *board, uint16_t *regs)
 Render a board's catalogue into LINK_CAT_COUNT registers for the wire.
bool outbind_learn_board (uint16_t id, const uint16_t *regs)
 Learn the board a catalogue page describes, replacing any previous one.
const outbind_pad_t * outbind_pads (uint16_t board)
 The pads that are not pins, and how many.
uint8_t outbind_pad_count (uint16_t board)
 How many pads that are not pins the board has, or 0 for a board nothing here describes that way.
void outbind_pads_to_regs (const outbind_board_t *board, uint16_t *regs)
 Render them into LINK_PAD_COUNT registers, or leave them zero.
bool outbind_learn_pads (uint16_t id, const uint16_t *regs)
 Give the learned board its grounds and rails.
void outbind_shape_to_regs (const outbind_board_t *board, uint16_t *regs)
 Render a board's shape into LINK_SH_COUNT registers, or leave them zero when it has none.
bool outbind_learn_shape (uint16_t id, const uint16_t *regs)
 Give the learned board a shape from a shape page.
bool outbind_pad_xy (const outbind_shape_t *shape, uint8_t pad, uint16_t *x_cmm, uint16_t *y_cmm)
 Where a pad's centre is, in hundredths of a millimetre from the top-left of the outline.
void outbind_forget_learned (void)
 Forget it.
uint8_t outbind_board_count (void)
 The table itself, so a caller can walk every board rather than guess at a range of identities. outbind_board_at() returns NULL past the end.
const outbind_board_t * outbind_board_at (uint8_t index)
 The board at index in the table, or NULL past the end.
static uint32_t board_mask (const outbind_board_t *bd)
 Which bits of a selection can mean anything on this board.
bool outbind_pin_selectable (const outbind_board_t *board, uint8_t index)
 Whether index may be added to a selection on board.
const outbind_pin_t * outbind_pins (uint16_t board)
 Its catalogue and how long it is.
uint8_t outbind_pin_count (uint16_t board)
 How many pins the board's catalogue lists, or 0 for a board this build does not know.
uint8_t outbind_index_of (uint16_t board, uint8_t gpio)
 Index of gpio in that board's catalogue, or its count when the board does not bring that pin out.
uint64_t outbind_reserved_mask (uint16_t board)
 Every pin of a board that no output and no PD mini pin may take, one bit per GPIO (0 to 63).
const outbind_proto_t * outbind_protos (void)
 The protocol table, indexed by protocol number; entry 0 is OFF.
void outbind_init (outbind_t *b)
 Empty, and belonging to no board: nothing can be chosen until one is set.
void outbind_set_board (outbind_t *b, uint16_t board)
 Say which board this binding is for.
static uint8_t count_pins (uint32_t pins, uint8_t width)
 How many bits are set in one protocol's pin set.
static uint8_t cap_of (const outbind_proto_t *p)
 What a protocol may take: its own cap, and never more slots than the page has.
uint8_t outbind_chosen (const outbind_t *b)
 How many pins the protocol being edited has chosen.
uint8_t outbind_wire_proto (const outbind_t *b)
 The protocol a page rendered from this selection reads back as: the lowest-numbered one holding a pin, or OFF when nothing does.
uint8_t outbind_chosen_total (const outbind_t *b)
 Pins chosen across every protocol, and the channels they render.
uint8_t outbind_channels_used (const outbind_t *b)
 Channels the chosen pins render, across every protocol.
uint8_t outbind_group_of (const outbind_t *b, uint8_t index)
 Which protocol holds index, or 0 (OFF) when nothing does.
void outbind_trim (outbind_t *b)
 Drop anything a selection cannot mean on its board.
bool outbind_can_add (const outbind_t *b, uint8_t index)
 True when this pin may still be added to the protocol being edited, for a screen drawing it.
outbind_clash_t outbind_pwm_clash (const outbind_t *b, uint8_t index, uint8_t prog_gpio, uint8_t *with)
 Whether the IOmcu refuses catalogue entry index for the protocol being edited, beside prog_gpio and the pins b binds as PWM.
outbind_clash_t outbind_pwm_clash_ports (const outbind_t *b, uint8_t index, const uint8_t *ports, uint8_t count, uint8_t *with)
 outbind_pwm_clash() beside every programming port's pin: count pins from ports (NULL or 0 for none), each OUTBIND_NO_GPIO for a port without one.
bool outbind_toggle (outbind_t *b, uint8_t index)
 Add or remove a pin, in the protocol being edited.
void outbind_set_proto (outbind_t *b, uint8_t proto)
 Choose which protocol is being edited.
uint8_t outbind_to_slots (const outbind_t *b, uint16_t *regs)
 Render the selection into the OUTPUTS page.
static out_role_t role_of_slot (const uint16_t *chan_cfg, const uint16_t *r)
 What the CHAN_CFG page says the channels of this slot are for.
uint8_t outbind_role_proto (const uint16_t *regs, const uint16_t *chan_cfg, out_role_t role)
 The entry the slots of role are bound as, an index into outbind_protos(), read from an OUTPUTS page and the CHAN_CFG page that came back with it: what MOTOR & ESC's TARGET row names before the throttle's pins.
bool outbind_from_slots (outbind_t *b, uint16_t board, const uint16_t *regs, const uint16_t *chan_cfg)
 Read a selection back out of an OUTPUTS page.
void outbind_to_chan_cfg (const outbind_t *b, uint16_t *regs, uint16_t min_us, uint16_t max_us)
 Render the channel configuration to match.

Variables

static const outbind_pin_t k_pico_pins [OUTBIND_PINS]
 The header, in GPIO order.
static const outbind_shape_t k_pico_shape
 The Pico form factor: 51.00 x 21.00mm, forty pads on 2.54mm, twenty a side, pad 1 at the bottom left with the numbers running away from it.
static const outbind_pad_t k_pico_pads []
 The pads that are not pins, in pad order.
static const outbind_board_t k_boards []
 Every board this build knows.
static outbind_pin_t s_learned_pins [LINK_CAT_PINS]
 One board learned over the link, for an IOmcu this build ships no catalogue for.
static outbind_pad_t s_learned_pads [LINK_PAD_SLOTS]
static outbind_shape_t s_learned_shape
static char s_learned_name [16]
static outbind_board_t s_learned
static bool s_have_learned
static const outbind_proto_t k_protos [OUTBIND_PROTOS]
 PWM runs at 50Hz, which every analogue and digital servo takes.

Detailed Description

Binding a protocol to pins.

See out_bind.h.

SPDX-License-Identifier: MIT

Function Documentation

◆ board_mask()

uint32_t board_mask ( const outbind_board_t * bd)
static

Which bits of a selection can mean anything on this board.

Parameters
bdThe board, or NULL.
Returns
One bit per catalogue entry, from bit 0. 0 for NULL, all 32 bits for a catalogue of 32 or more entries.

◆ cap_of()

uint8_t cap_of ( const outbind_proto_t * p)
static

What a protocol may take: its own cap, and never more slots than the page has.

Parameters
pThe protocol entry.
Returns
The lower of p's max_pins and OUT_MAX_SLOTS.

◆ count_pins()

uint8_t count_pins ( uint32_t pins,
uint8_t width )
static

How many bits are set in one protocol's pin set.

Parameters
pinsThe pin set, one bit per catalogue index.
widthHow many low bits to count, 0 to 32.
Returns
The number of set bits among the first width.

◆ hold_name()

const char * hold_name ( uint8_t hold)
static

The panel's words for what the wire can only number. The panel shows them through ui_pin_holder(), in the language showing.

Parameters
holdA LINK_PIN_* value from the catalogue page.
Returns
The word for hold, or "in use" for any other value.

◆ outbind_board()

const outbind_board_t * outbind_board ( uint16_t id)

The board with this identity, or NULL when nothing here describes it.

The table compiled into this build first, then a board learned over the link. A build that ships a catalogue for a board uses its own: the compiled one has been read by somebody, names the exact signal holding each reserved pin, and cannot change under a running bench.

Parameters
idIdentity the IOmcu reports, an outbind_board_id_t value or a learned identity.
Returns
The board, or NULL when neither the table nor the learned board has id. OUTBIND_BOARD_UNKNOWN always returns NULL.

◆ outbind_board_at()

const outbind_board_t * outbind_board_at ( uint8_t index)

The board at index in the table, or NULL past the end.

Parameters
indexPosition in the table, 0 to outbind_board_count() - 1.
Returns
The board, or NULL when index is past the end.

◆ outbind_board_count()

uint8_t outbind_board_count ( void )

The table itself, so a caller can walk every board rather than guess at a range of identities. outbind_board_at() returns NULL past the end.

Returns
The number of boards in the compiled table.

◆ outbind_board_to_regs()

void outbind_board_to_regs ( const outbind_board_t * board,
uint16_t * regs )

Render a board's catalogue into LINK_CAT_COUNT registers for the wire.

Slots past the board's own pins are left with a pad number of zero, which is how the page says there is no pin there.

Parameters
boardThe board to render, or NULL for a page of zeroes.
regsLINK_CAT_COUNT registers to write. NULL does nothing.

◆ outbind_can_add()

bool outbind_can_add ( const outbind_t * b,
uint8_t index )

True when this pin may still be added to the protocol being edited, for a screen drawing it.

Includes the compare-register rule of outbind_pwm_clash(), which needs no programming port: a PWM protocol is not offered the partner of a pin bound as PWM. The slice rule needs the port's pin, which this binding does not carry, so a screen asks outbind_pwm_clash() for it.

Parameters
bThe selection.
indexCatalogue index of the pin.
Returns
true when the pin may be added; false otherwise.

◆ outbind_channels_used()

uint8_t outbind_channels_used ( const outbind_t * b)

Channels the chosen pins render, across every protocol.

Parameters
bThe selection.
Returns
The sum of each chosen pin's channels, capped at 255. 0 for NULL.

◆ outbind_chosen()

uint8_t outbind_chosen ( const outbind_t * b)

How many pins the protocol being edited has chosen.

Parameters
bThe selection.
Returns
The count of pins in the edited protocol. 0 for NULL.

◆ outbind_chosen_total()

uint8_t outbind_chosen_total ( const outbind_t * b)

Pins chosen across every protocol, and the channels they render.

Both are budgets shared by all of them: LINK_OUT_SLOTS and LINK_OUT_CHANNELS.

Parameters
bThe selection.
Returns
The number of pins chosen in protocols 1 and up. 0 for NULL.

◆ outbind_forget_learned()

void outbind_forget_learned ( void )

Forget it.

Not needed when the link drops. The slot is keyed by identity and is returned for that identity alone, so a board that has been unplugged cannot be reached by the one that replaces it – and keeping it means the screen still knows the pins of a board whose link merely blinked, which is what a compiled-in catalogue already gives a board this build knows.

◆ outbind_from_slots()

bool outbind_from_slots ( outbind_t * b,
uint16_t board,
const uint16_t * regs,
const uint16_t * chan_cfg )

Read a selection back out of an OUTPUTS page.

The IOmcu holds the configuration, so the panel asks it what is driving rather than remembering: a binding is a description of wiring, and a panel that reapplied a remembered one would be applying it to whatever is on the bench now.

Slots on different protocols are the ordinary case; slots on the same driver and rate are one protocol's set, because that pair is what names a set. The protocol left being edited is the lowest-numbered one the page uses, so a page with anything on it opens on something.

Returns false for a page this shape cannot describe – a rate no entry uses, a pin not on the header, a channel run that does not follow the slot order – and leaves b cleared. The screen then shows nothing chosen rather than a selection that disagrees with the page it came from.

chan_cfg is the CHAN_CFG page that came back with regs, and it is what separates two entries the slots page cannot: SERVO PWM and MOTOR PWM are one driver at one rate, and only the role of the slot's first channel says which was chosen. NULL takes the first entry that matches driver and rate, which on this catalogue reads a motor back as a servo and rests it at half throttle, so pass the page whenever there is one.

Parameters
bReceives the selection. Cleared on refusal.
boardIdentity of the board the page was read from.
regsLINK_OS_COUNT registers of the OUTPUTS page.
chan_cfgLINK_CC_COUNT registers of the CHAN_CFG page, or NULL.
Returns
true when the page reads back to itself as a selection on board; false when it is refused and b is cleared.

◆ outbind_group_of()

uint8_t outbind_group_of ( const outbind_t * b,
uint8_t index )

Which protocol holds index, or 0 (OFF) when nothing does.

A pin refused because another protocol holds it is a different fact from one the IOmcu reserves: the first is a choice the operator can undo by going to that protocol, the second is the wiring. A screen that drew them alike would offer to free the heartbeat line.

Parameters
bThe selection.
indexCatalogue index of the pin.
Returns
The protocol number holding the pin, or 0 when none does or b is NULL.

◆ outbind_index_of()

uint8_t outbind_index_of ( uint16_t board,
uint8_t gpio )

Index of gpio in that board's catalogue, or its count when the board does not bring that pin out.

Parameters
boardIdentity of the board, as for outbind_board().
gpioGPIO number to look up.
Returns
Catalogue index of gpio. The board's count when it is not listed, and 0 for a board this build does not know.

◆ outbind_init()

void outbind_init ( outbind_t * b)

Empty, and belonging to no board: nothing can be chosen until one is set.

Parameters
bThe selection to clear. NULL does nothing.

◆ outbind_learn_board()

bool outbind_learn_board ( uint16_t id,
const uint16_t * regs )

Learn the board a catalogue page describes, replacing any previous one.

There is room for exactly one: the panel talks to one IOmcu, and a second learned board would be a pin map for hardware that is not on the bench. Refuses a page that cannot be a board – no pins, a GPIO past OUT_MAX_PIN, pins out of GPIO order, or the same GPIO twice – and learns nothing rather than half of it, because a catalogue half read is a pin map that disagrees with the board sending it.

Refuses an identity the compiled table already has: that board is described here already, and letting the wire replace it would let an IOmcu rename the pin holding the safety line.

Parameters
idIdentity the catalogue page came from. Must not be OUTBIND_BOARD_UNKNOWN or an identity in the compiled table.
regsLINK_CAT_COUNT registers of the catalogue page. NULL is refused.
Returns
true when the board was learned, false when it was refused and the previous learned board, if any, is unchanged.

◆ outbind_learn_pads()

bool outbind_learn_pads ( uint16_t id,
const uint16_t * regs )

Give the learned board its grounds and rails.

Refuses a list that cannot belong to the board: a pad of zero, a kind that is not one, pads out of order or repeated, or a pad the catalogue already calls a pin – one pad cannot be both a GPIO and a ground, and a page saying so is describing something other than this board. Refusing costs the marks and nothing else.

Parameters
idIdentity of the learned board. Must equal the learned board's identity.
regsLINK_PAD_COUNT registers of the pad page. NULL is refused.
Returns
true when the pads were learned, false when the page was refused.

◆ outbind_learn_shape()

bool outbind_learn_shape ( uint16_t id,
const uint16_t * regs )

Give the learned board a shape from a shape page.

Refuses one that cannot be a board: no pads in a row, a corner that is not one, no pitch, or an outline too small to hold the row it claims. Refuses one whose rows cannot hold the catalogue's pins, since the two pages describe the same board and a pad with nowhere to sit would be drawn off the outline. A board with no shape is used and not drawn, so refusing costs the picture and nothing else.

Parameters
idIdentity of the learned board. Must equal the learned board's identity.
regsLINK_SH_COUNT registers of the shape page. NULL is refused.
Returns
true when the shape was learned, false when it was refused.

◆ outbind_pad_count()

uint8_t outbind_pad_count ( uint16_t board)

How many pads that are not pins the board has, or 0 for a board nothing here describes that way.

Parameters
boardIdentity of the board, as for outbind_board().
Returns
The number of entries in outbind_pads(), or 0.

◆ outbind_pad_xy()

bool outbind_pad_xy ( const outbind_shape_t * shape,
uint8_t pad,
uint16_t * x_cmm,
uint16_t * y_cmm )

Where a pad's centre is, in hundredths of a millimetre from the top-left of the outline.

False for a pad the shape does not place: pads are numbered from one, up to twice the row length.

Parameters
shapeThe outline to place the pad on.
padPad number, 1 to twice shape's per_side.
x_cmmReceives the x coordinate of the pad centre.
y_cmmReceives the y coordinate of the pad centre.
Returns
true when the pad is placed and both outputs are written; false for a NULL argument, a shape with no pads per side, or a pad outside the range above.

◆ outbind_pads()

const outbind_pad_t * outbind_pads ( uint16_t board)

The pads that are not pins, and how many.

NULL and 0 for a board nothing here describes that way.

Parameters
boardIdentity of the board, as for outbind_board().
Returns
The pad table, or NULL. The count is outbind_pad_count().

◆ outbind_pads_to_regs()

void outbind_pads_to_regs ( const outbind_board_t * board,
uint16_t * regs )

Render them into LINK_PAD_COUNT registers, or leave them zero.

Parameters
boardThe board whose pads to render, or NULL for a page of zeroes.
regsLINK_PAD_COUNT registers to write. NULL does nothing.

◆ outbind_pin_count()

uint8_t outbind_pin_count ( uint16_t board)

How many pins the board's catalogue lists, or 0 for a board this build does not know.

Parameters
boardIdentity of the board, as for outbind_board().
Returns
The number of entries in outbind_pins(), or 0.

◆ outbind_pin_selectable()

bool outbind_pin_selectable ( const outbind_board_t * board,
uint8_t index )

Whether index may be added to a selection on board.

Takes the board rather than reading it from the table, so the rule can be held against a board this build does not yet contain – a soldered one, for instance, which refuses every pin because there is nothing there to choose.

Parameters
boardThe board whose catalogue index indexes.
indexCatalogue index, 0 to the board's count - 1.
Returns
true when the pin is in range, the board is not soldered and the pin is not reserved; false otherwise.

◆ outbind_pins()

const outbind_pin_t * outbind_pins ( uint16_t board)

Its catalogue and how long it is.

NULL and 0 for a board this build does not know, so a caller that forgets to check offers nothing rather than offering the wrong thing.

Parameters
boardIdentity of the board, as for outbind_board().
Returns
The catalogue, in GPIO order, or NULL. The length is outbind_pin_count().

◆ outbind_protos()

const outbind_proto_t * outbind_protos ( void )

The protocol table, indexed by protocol number; entry 0 is OFF.

Returns
The table of OUTBIND_PROTOS entries.

◆ outbind_pwm_clash()

outbind_clash_t outbind_pwm_clash ( const outbind_t * b,
uint8_t index,
uint8_t prog_gpio,
uint8_t * with )

Whether the IOmcu refuses catalogue entry index for the protocol being edited, beside prog_gpio and the pins b binds as PWM.

Applies to a protocol on OUT_DRIVER_PWM and a pin that is not reserved and that no protocol holds; any other pin or protocol is OUTBIND_CLASH_NONE. Two refusals, in this order:

  • OUTBIND_CLASH_PROG_SLICE: the pin shares a slice with prog_gpio, the programming port's pin (prog_port_slots_check()). Only while no protocol holds prog_gpio: a slot on that pin leaves the port without one. OUTBIND_NO_GPIO, or any GPIO past OUT_MAX_PIN, is no port.
  • OUTBIND_CLASH_COMPARE: the pin shares a compare register with a pin a PWM protocol holds (out_pwm_bind() in the IOmcu).

Both are out_pwm_same_slice() and out_pwm_same_compare(), the helpers the IOmcu decides with. with, when not NULL, gets the GPIO the pin clashes with, or OUTBIND_NO_GPIO for OUTBIND_CLASH_NONE.

Parameters
bThe selection.
indexCatalogue index of the pin being checked.
prog_gpioGPIO of the programming port's pin, or OUTBIND_NO_GPIO.
withReceives the GPIO clashed with, or NULL to skip it.
Returns
The refusal, or OUTBIND_CLASH_NONE.

◆ outbind_pwm_clash_ports()

outbind_clash_t outbind_pwm_clash_ports ( const outbind_t * b,
uint8_t index,
const uint8_t * ports,
uint8_t count,
uint8_t * with )

outbind_pwm_clash() beside every programming port's pin: count pins from ports (NULL or 0 for none), each OUTBIND_NO_GPIO for a port without one.

The slice rule is checked against each in order, the first clash named; then the compare rule. The IOmcu checks a slot against every port it has (prog_port_slots_check()).

Parameters
bThe selection.
indexCatalogue index of the pin being checked.
portsGPIOs of the programming ports, or NULL.
countNumber of entries in ports.
withReceives the GPIO clashed with, or NULL to skip it.
Returns
The first refusal found, or OUTBIND_CLASH_NONE.

◆ outbind_reserved_mask()

uint64_t outbind_reserved_mask ( uint16_t board)

Every pin of a board that no output and no PD mini pin may take, one bit per GPIO (0 to 63).

That is the catalogue's reserved pins, plus every pin the catalogue does not list: the pins the board uses without bringing them out and the numbers the part does not have. The IOmcu hands this mask to outputs_reserve_pins(), which the OUTPUTS and SUPPLY pages both consult, and the panel greys the catalogue's reserved pins, so the two ends cannot disagree about which pins exist to be given away. An unknown board reserves everything: a build that cannot say which pins are safe must not hand any of them out.

Parameters
boardIdentity of the board, as for outbind_board().
Returns
Bit n is set when GPIO n is reserved. All 64 bits are set for an unknown board.

◆ outbind_role_proto()

uint8_t outbind_role_proto ( const uint16_t * regs,
const uint16_t * chan_cfg,
out_role_t role )

The entry the slots of role are bound as, an index into outbind_protos(), read from an OUTPUTS page and the CHAN_CFG page that came back with it: what MOTOR & ESC's TARGET row names before the throttle's pins.

A slot is the role's when its first channel carries the role on chan_cfg, as outbind_from_slots() reads it; its entry is the one of that role with the slot's driver and rate. Returns 0 when no slot is the role's, when a page is NULL, or when the role's one slot set matches no entry, and OUTBIND_PROTO_MIXED when the role's slots match two entries or one matches none beside one that does.

Parameters
regsLINK_OS_COUNT registers of the OUTPUTS page.
chan_cfgLINK_CC_COUNT registers of the CHAN_CFG page.
roleThe role to look for.
Returns
The entry index, 0, or OUTBIND_PROTO_MIXED as above.

◆ outbind_set_board()

void outbind_set_board ( outbind_t * b,
uint16_t board )

Say which board this binding is for.

Clears the selection whenever the board changes, and that is the point: a bit in pins is an index into one board's catalogue and means a different pin – or no pin – in another's. Carrying a selection across would bind whatever happened to sit at that index on the board now in front of the operator.

Parameters
bThe selection. NULL does nothing.
boardIdentity of the board the selection is now for.

◆ outbind_set_proto()

void outbind_set_proto ( outbind_t * b,
uint8_t proto )

Choose which protocol is being edited.

Nothing is dropped. The pins chosen for the protocol being left stay bound and appear as held on the grid, and the pins of the one arrived at come back as they were: a selector that retargeted the current pins would make binding a second protocol mean unbinding the first.

The whole selection is trimmed here, since this is every screen's way in to a binding that came from outside.

Parameters
bThe selection. NULL does nothing.
protoProtocol number, an index into outbind_protos(). A value of OUTBIND_PROTOS or more does nothing.

◆ outbind_shape_to_regs()

void outbind_shape_to_regs ( const outbind_board_t * board,
uint16_t * regs )

Render a board's shape into LINK_SH_COUNT registers, or leave them zero when it has none.

Parameters
boardThe board whose shape to render, or NULL for a page of zeroes.
regsLINK_SH_COUNT registers to write. NULL does nothing.

◆ outbind_to_chan_cfg()

void outbind_to_chan_cfg ( const outbind_t * b,
uint16_t * regs,
uint16_t min_us,
uint16_t max_us )

Render the channel configuration to match.

Each entry says what its channels are for, and that is what decides where a channel rests when it stops being commanded – stopped, or centred. With more than one protocol bound the roles are mixed, and each channel takes the role of the protocol whose pin renders it. Channels the selection does not use keep the schema's defaults.

min_us and max_us go to the throttle channels only, through outputs_chan_cfg_set_throttle_range(); every surface channel keeps the schema's 1000 to 2000us. Endpoints that page would refuse are not written at all.

Parameters
bThe selection. NULL leaves regs at the defaults.
regsLINK_CC_COUNT registers to write. NULL does nothing.
min_usLow endpoint of the throttle channels, in microseconds.
max_usHigh endpoint of the throttle channels, in microseconds.

◆ outbind_to_slots()

uint8_t outbind_to_slots ( const outbind_t * b,
uint16_t * regs )

Render the selection into the OUTPUTS page.

regs is LINK_OS_COUNT registers, cleared and rebuilt: every slot the selection does not use is set to no driver, so a page written from this is the whole truth rather than a change to what was there.

Slots are filled in pin order across every protocol and take channels from zero upward, so the lowest chosen pin is channel 0 whichever protocol holds it. Filling stops at LINK_OUT_SLOTS slots or LINK_OUT_CHANNELS channels, whichever comes first. Returns how many slots were used.

Parameters
bThe selection. NULL leaves regs with the default slots.
regsLINK_OS_COUNT registers to write. NULL does nothing.
Returns
The number of slots used, 0 for NULL arguments.

◆ outbind_toggle()

bool outbind_toggle ( outbind_t * b,
uint8_t index )

Add or remove a pin, in the protocol being edited.

Refuses a reserved pin, an index off the end, one more pin than the protocol can take – PPM's second pin is not a second output, it is a mistake – and a pin another protocol holds, which is that protocol's to give up. Removing a pin this protocol holds always succeeds, because an operator must always be able to undo what they just did.

Parameters
bThe selection, changed on success.
indexCatalogue index of the pin.
Returns
true when the pin was toggled; false when it was refused, and the selection is unchanged.

◆ outbind_trim()

void outbind_trim ( outbind_t * b)

Drop anything a selection cannot mean on its board.

Bits above the catalogue's width, and pins past what a protocol takes. outbind_t is a plain struct and one arrives from outside – read off the wire, or restored – so it is trimmed before it is shown rather than trusted.

Parameters
bThe selection, trimmed in place. NULL does nothing.

◆ outbind_wire_proto()

uint8_t outbind_wire_proto ( const outbind_t * b)

The protocol a page rendered from this selection reads back as: the lowest-numbered one holding a pin, or OFF when nothing does.

Which protocol is being edited is not on the wire. A page carries pins, and outbind_from_slots() has to name a protocol from them, so it names this one. A screen that has just been handed a binding uses this to tell the two apart: a protocol equal to it says only what the pins already said, and any other is somebody's choice.

Parameters
bThe selection.
Returns
The protocol number, or 0 (OFF) when no pin is chosen or b is NULL.

◆ role_of_slot()

out_role_t role_of_slot ( const uint16_t * chan_cfg,
const uint16_t * r )
static

What the CHAN_CFG page says the channels of this slot are for.

The slot's first channel answers for the run: outbind_to_chan_cfg() writes one role across every channel a slot renders, so no page this end produced can disagree with itself. A page that does – which nothing here writes – is read by its first channel rather than refused, and a first channel past the page reads as a surface, which is where an unconfigured channel already rests.

Parameters
chan_cfgThe CHAN_CFG page, or NULL.
rThe slot's OUTPUTS registers.
Returns
OUT_ROLE_THROTTLE or OUT_ROLE_SURFACE.

Variable Documentation

◆ k_boards

const outbind_board_t k_boards[]
static
Initial value:
= {
(uint8_t)(sizeof(k_pico_pads) / sizeof(k_pico_pads[0])) },
}
static const outbind_shape_t k_pico_shape
The Pico form factor: 51.00 x 21.00mm, forty pads on 2.54mm, twenty a side, pad 1 at the bottom left ...
Definition out_bind.c:75
static const outbind_pad_t k_pico_pads[]
The pads that are not pins, in pad order.
Definition out_bind.c:87
static const outbind_pin_t k_pico_pins[OUTBIND_PINS]
The header, in GPIO order.
Definition out_bind.c:37
@ OUTBIND_BOARD_PICO_HEADER
Definition out_bind.h:64
#define OUTBIND_PINS
The most pins any board in this build brings out.
Definition out_bind.h:68

Every board this build knows.

A second one appends a row here and a catalogue above it; nothing else in this file is per-board.

◆ k_pico_pads

const outbind_pad_t k_pico_pads[]
static
Initial value:
= {
{ 3, LINK_PAD_GROUND, 0 },
{ 8, LINK_PAD_GROUND, 0 },
{ 13, LINK_PAD_GROUND, 0 },
{ 18, LINK_PAD_GROUND, 0 },
{ 23, LINK_PAD_GROUND, 0 },
{ 28, LINK_PAD_GROUND, 0 },
{ 30, LINK_PAD_OTHER, 0 },
{ 33, LINK_PAD_GROUND, 0 },
{ 35, LINK_PAD_POWER, 33 },
{ 36, LINK_PAD_POWER, 33 },
{ 37, LINK_PAD_OTHER, 0 },
{ 38, LINK_PAD_GROUND, 0 },
{ 39, LINK_PAD_POWER, 0 },
{ 40, LINK_PAD_POWER, 50 },
}

The pads that are not pins, in pad order.

VSYS carries no voltage here because it does not have one: it is the input rail and follows whatever feeds it, which on the bring-up module is USB and on a bench could be anything. A number that is only sometimes true is worse on this screen than no number.

◆ k_pico_pins

const outbind_pin_t k_pico_pins[OUTBIND_PINS]
static
Initial value:
= {
{ 0, 1, false, NULL },
{ 1, 2, false, NULL },
{ 2, 4, false, NULL },
{ 3, 5, true, "heartbeat" },
{ 4, 6, false, NULL },
{ 5, 7, false, NULL },
{ 6, 9, false, NULL },
{ 7, 10, false, NULL },
{ 8, 11, true, "CAN INT" },
{ 9, 12, true, "CAN CS" },
{ 10, 14, true, "CAN SCK" },
{ 11, 15, true, "CAN MOSI" },
{ 12, 16, true, "CAN MISO" },
{ 13, 17, false, NULL },
{ 14, 19, false, NULL },
{ 15, 20, false, NULL },
{ 16, 21, false, NULL },
{ 17, 22, false, NULL },
{ 18, 24, false, NULL },
{ 19, 25, false, NULL },
{ 20, 26, false, NULL },
{ 21, 27, false, NULL },
{ 22, 29, false, NULL },
{ 26, 31, false, NULL },
{ 27, 32, false, NULL },
{ 28, 34, false, NULL },
}

The header, in GPIO order.

GP23 to GP25 and GP29 are missing because the Pico form factor does not bring them out: on the module GP23 is the MODE pin of the MP28164 power converter, GP24 senses VBUS, GP25 drives LED1 and GP29 senses VSYS. outbind_reserved_mask() reserves every pin the catalogue leaves out, so those four and every number from GP30 up are refused. The pad numbers are the ones printed on the board so an operator counting pads and an operator reading GPIOs arrive at the same pin.

The reserved six are the IOmcu's: GP3 carries the safety heartbeat in from the panel, and GP8 to GP12 are the CAN (Controller Area Network) controller's interrupt and its SPI (Serial Peripheral Interface) bus. firmware/iomcu/include/iomcu_pins.h assigns the same pins for the drivers that use them; the IOmcu reserves the union of both, so the two disagreeing costs a pin rather than the safety line.

◆ k_pico_shape

const outbind_shape_t k_pico_shape
static
Initial value:
= {
5100u, 2100u, 254u, 161u, 20u, (uint8_t)LINK_SH_BOTTOM_LEFT,
}

The Pico form factor: 51.00 x 21.00mm, forty pads on 2.54mm, twenty a side, pad 1 at the bottom left with the numbers running away from it.

The outline's own numbers. The board drawing the IOmcu serves places its pads on the same grid, and the picker refuses a drawing that does not (board_drawing_agrees()).

◆ k_protos

const outbind_proto_t k_protos[OUTBIND_PROTOS]
static
Initial value:
= {
{ "OFF", OUT_DRIVER_NONE, 0, 0, 0, OUT_ROLE_SURFACE },
{ "SERVO PWM", OUT_DRIVER_PWM, 50, 8, 1, OUT_ROLE_SURFACE },
{ "MOTOR PWM", OUT_DRIVER_PWM, 50, 8, 1, OUT_ROLE_THROTTLE },
{ "PPM", OUT_DRIVER_PPM, 40, 1, 8, OUT_ROLE_SURFACE },
{ "DSHOT300", OUT_DRIVER_DSHOT, 300, 8, 1, OUT_ROLE_THROTTLE },
{ "DSHOT600", OUT_DRIVER_DSHOT, 600, 8, 1, OUT_ROLE_THROTTLE },
{ "DSHOT300 BIDIR", OUT_DRIVER_DSHOT_BIDIR, 300, 8, 1, OUT_ROLE_THROTTLE },
{ "DSHOT600 BIDIR", OUT_DRIVER_DSHOT_BIDIR, 600, 8, 1, OUT_ROLE_THROTTLE },
}
@ OUT_DRIVER_DSHOT_BIDIR
Definition outputs.h:88
@ OUT_DRIVER_PPM
Definition outputs.h:86
@ OUT_DRIVER_NONE
Definition outputs.h:84
@ OUT_DRIVER_PWM
Definition outputs.h:85
@ OUT_DRIVER_DSHOT
Definition outputs.h:87
@ OUT_ROLE_SURFACE
Definition outputs.h:72
@ OUT_ROLE_THROTTLE
Definition outputs.h:71

PWM runs at 50Hz, which every analogue and digital servo takes.

PPM runs at 40Hz because eight channels do not fit in a 50Hz frame. A channel is at most OUT_CEILING_US (2500us), and the frame also carries the mark and a sync gap of at least PPM_SYNC_MIN_US, so eight of them need 8 x 2500 + 300 + 3000 = 23,300us and 50Hz gives 20,000. The IOmcu refuses the bind and leaves the slot unbound, having acknowledged the page that asked for it, so the screen shows a binding the bench does not have. 40Hz gives 25,000us and binds.

The DShot rates are bit rates and the two bidirectional entries are the same wire asking for telemetry back.

SERVO PWM and MOTOR PWM are the same signal at the same rate and differ only in what the channel is for. A servo centres when nothing commands it; a motor stops. Nothing in the pulse says which is on the pin, so the two are separate entries and the operator picks the one that is wired.

◆ s_learned_pins

outbind_pin_t s_learned_pins[LINK_CAT_PINS]
static

One board learned over the link, for an IOmcu this build ships no catalogue for.

The name is formatted rather than carried: a name is a string and the page is registers, and the identity is what the operator needs to match against the board in front of them.