|
rcbench
Servo and ESC test bench: panel, IOmcu and shared C
|
The limit run: see servo_limrun.h. More...
#include "servo_limrun.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include "servo_limrun_int.h"Functions | |
| static bool | due (uint32_t now, uint32_t then, uint32_t ms) |
| Tell whether a millisecond span has elapsed. | |
| void | servo_limrun_init (servo_limrun_t *r) |
| Clear a run state to idle. | |
| bool | servo_limrun_running (const servo_limrun_t *r) |
| Tell whether the run is RUNNING. | |
| bool | servo_limrun_switching (const servo_limrun_t *r) |
| The run asked the bench to SAFE or to ARMED and waits for it, or holds the programmer: a disarm then is its own, not the operator's. Not while the servo returns to the centre before a session: a disarm then is the operator's. | |
| bool | servo_limrun_programming (const servo_limrun_t *r) |
| The run holds the programmer: CONNECT to LEAVE. | |
| bool | servo_limrun_wrote (const servo_limrun_t *r) |
| A value was written and the servo may not hold its own any more. | |
| bool | servo_limrun_restore (const servo_limrun_t *r) |
| The run ended as FAIL or ABORTED with the servo's values changed: RESTORE gives back the ones before it. | |
| bool | servo_limrun_original (const servo_limrun_t *r, uint16_t *left, uint16_t *right) |
| The values the servo held before the run, valid once read. | |
| int32_t | servo_limrun_dist (const servo_limrun_servo_t *sv, uint8_t side, uint16_t p_us) |
The share of travel, 0.1us of pulse: p_us's distance from NEUTRAL on side, positive outward, and the pulse limit's. | |
| int32_t | servo_limrun_span (const servo_limrun_servo_t *sv, uint8_t side) |
| Span of one side, as servo_limrun_span() reports it. | |
| static int32_t | dist_now (const servo_limrun_t *r, uint8_t side, uint16_t p_us) |
| The share's terms from the pulses in force: after SERVO PULSES at 1000-2000 those written, not those read. | |
| static uint16_t | clamp_raw (uint64_t v, uint16_t lo, uint16_t hi) |
| Clamp a register value to the range lo to hi. | |
| uint16_t | servo_limrun_overset (uint16_t v0, int32_t d, int32_t span, uint16_t lo_raw) |
The overset for value v0 and share d / span: ceil(v0 x share x (100 + SERVO_LIMRUN_OVERSET_PCT) / 100), within lo_raw to v0. | |
| uint16_t | servo_limrun_scaled (uint16_t v, int32_t d, int32_t span, uint16_t lo_raw) |
The final value for value v and share d / span: floor(v x
share), within lo_raw to v. | |
| static void | finish (servo_limrun_t *r, servo_limrun_verdict_t v, servo_limrun_why_t why, uint32_t now_ms) |
| The run is over. It lets the servo go; aborted, it also asks the supply's output off. A run that ends between CONNECT and LEAVE with nothing running gives the port back, unless it was aborted: the programmer then holds the port for RESTORE, and a STOP or the supply switched off ends its session by itself. Aborted while it waits for ARMED, it asks SAFE: the ARM it asked may not be taken yet, and a release does not replace one (servo_screen.c, post()). | |
| static void | fail (servo_limrun_t *r, servo_limrun_why_t why, uint32_t now_ms) |
| End the run as FAIL. | |
| static void | abort_why (servo_limrun_t *r, servo_limrun_why_t why, uint32_t now_ms) |
| End the run as ABORTED. | |
| void | servo_limrun_abort (servo_limrun_t *r, servo_test_abort_t why, uint32_t now_ms) |
| The caller's reasons. | |
| static void | begin_search (servo_limrun_t *r, uint8_t side, servo_limrun_phase_t ph, uint32_t now_ms) |
| Start a limit search of one side, from the centre outward. | |
| static servo_limrun_side_t | side_result (const servo_limrun_t *r, uint16_t bind_us) |
| Result of the search that just ended. | |
| static int32_t | outward (uint8_t side, const servo_limrun_side_t *now, const servo_limrun_side_t *was) |
How far now lies outward of was on side, us: positive further from the centre. | |
| static unsigned | reg_of (const servo_limrun_t *r, uint8_t side) |
| Register that limits a side, once the mapping is known. | |
| static unsigned | changes (const servo_limrun_t *r, const uint16_t *want) |
| Count the register values that differ from the servo current ones. | |
| static void | search_span (servo_limrun_t *r) |
| The search centre and ends: the servo's NEUTRAL, PULSE LOWER and PULSE UPPER once read, rounded inward to whole microseconds so no command passes a pulse limit; the bench's PULSE CENTRE, MIN and MAX before. | |
| static bool | prepare_side (servo_limrun_t *r, uint8_t side, unsigned reg) |
A bound side's values worked out for register reg: the overset, or, where it is left out, the final value at once (servo_limrun.h). False where the register holds the smallest value already: nothing lowers it. | |
| static uint16_t | stage_value (const servo_limrun_t *r, uint8_t side, unsigned reg) |
| The value the side's stage puts in its register. | |
| static void | plan (const servo_limrun_t *r, uint16_t *want, int8_t *search) |
| The next session's values and the side searched after it (-1: both ends, the final check). | |
| static void | go_safe (servo_limrun_t *r, uint32_t now_ms) |
| A session next: the servo back to the centre first, SAFE asked once it had SERVO_LIMRUN_RETURN_MS to get there (servo_limrun_step()). | |
| static void | begin_check (servo_limrun_t *r, uint32_t now_ms) |
| Start the final check: both sides searched again. | |
| static void | next_step (servo_limrun_t *r, uint32_t now_ms) |
| A session if the plan changes a value, the final check if not. | |
| static bool | map_side (servo_limrun_t *r, uint32_t now_ms) |
| The first bound side's search after its first write: which register limits it. False where the run ended or tries the other register. | |
| static void | next_after_probe (servo_limrun_t *r, uint32_t now_ms) |
| Continue after the probe search of a side. | |
| static void | after_first_search (servo_limrun_t *r, uint32_t now_ms) |
| The first search of both sides is over. | |
| static void | after_check (servo_limrun_t *r, uint32_t now_ms) |
| The final check is over: PASS with both ends free. An end that binds with its register at the smallest value fails as that. | |
| static void | search_done (servo_limrun_t *r, uint16_t bind_us, uint32_t now_ms) |
| The search under way has ended. | |
| static bool | searching (const servo_limrun_t *r) |
| True while a search phase runs. | |
| bool | servo_limrun_start (servo_limrun_t *r, const servo_limrun_cfg_t *cfg, uint32_t now_ms) |
Start at now_ms. False, and nothing started, for a configuration whose centre is not between its MIN and MAX. | |
| static int32_t | mag (int16_t ma) |
| A current's magnitude, mA. Wider than the reading: -32768mA is 32768 mA, past every ceiling, not a negative value under them. | |
| void | servo_limrun_window (servo_limrun_t *r, const servo_test_win_t *w) |
| One INA3221 window, as the automatic test takes it. | |
| void | servo_limrun_supply (servo_limrun_t *r, const servo_test_reading_t *s, uint32_t now_ms) |
| The supply's reading. | |
| void | servo_limrun_supply_refused (servo_limrun_t *r, bool output_on, uint32_t now_ms) |
The caller will not hand the programmer's CONNECT a PD mini that the run did not start with, or one whose output is off (output_on false). A supply the run started with, its output off, ends the run as a reading outside a session does (SERVO_TEST_AB_SUPPLY_OFF); one the run did not start with ends it as a changed supply (SERVO_LIMRUN_WHY_SUPPLY_CHANGED). | |
| void | servo_limrun_backup (servo_limrun_t *r, const char *name) |
| The file the servo's values before the run were saved in, once the programmer names it: its first write saves it. | |
| static void | ask_leave (servo_limrun_t *r, uint32_t now_ms) |
| Ask the programmer for LEAVE. | |
| static bool | pulses_ordered (const uint16_t *p) |
| NEUTRAL between PULSE LOWER and PULSE UPPER. | |
| static void | read_done (servo_limrun_t *r, uint32_t now_ms) |
| The read session's pulses stand: the search's ends, within the bench's PULSE MIN and PULSE MAX, and the port given back. The bench stays SAFE where they are not. | |
| static void | first_read (servo_limrun_t *r, const servo_limrun_servo_t *sv, uint32_t now_ms) |
| The first CONNECT: the servo as it is. | |
| void | servo_limrun_connected (servo_limrun_t *r, const servo_limrun_servo_t *sv, uint32_t now_ms) |
| The programmer's answers: the servo read after CONNECT, a write's end with the values the servo holds (servo_limrun_pulsed() for the pulse write: NEUTRAL, PULSE LOWER, PULSE UPPER), and the port back in PWM. | |
| static void | mark_programmed (servo_limrun_t *r) |
| Record whether any value differs from the servo own. | |
| static void | sent_failed (servo_limrun_t *r, uint32_t now_ms) |
| A write that failed once sent – no answer, or one the programmer did not take: part of it may have landed, so the servo's values count as changed and RESTORE is offered. A write refused before it was sent is servo_limrun_refused()'s. | |
| void | servo_limrun_written (servo_limrun_t *r, bool ok, const uint16_t *angle, uint32_t now_ms) |
| Feed the end of a write: the values the servo holds. | |
| void | servo_limrun_pulsed (servo_limrun_t *r, bool ok, const uint16_t *pulse_dus, uint32_t now_ms) |
| Feed the end of the pulse write: the pulses the servo holds. | |
| void | servo_limrun_left (servo_limrun_t *r, bool ok, uint32_t now_ms) |
| Feed the answer to LEAVE: the port is given back. | |
| void | servo_limrun_refused (servo_limrun_t *r, uint32_t now_ms) |
| The programmer refused the CONNECT, write or LEAVE asked: it never started. | |
| void | servo_limrun_no_servo (servo_limrun_t *r, uint32_t now_ms) |
| The programmer's CONNECT ended with no servo answering (KST_SES_ERR_NO_SERVO). | |
| void | servo_limrun_step (servo_limrun_t *r, uint32_t now_ms, const servo_limrun_in_t *in, servo_limrun_do_t *out) |
Advance to now_ms: what to do comes back in out. | |
The limit run: see servo_limrun.h.
SPDX-License-Identifier: MIT
|
static |
End the run as ABORTED.
| r | Run state. |
| why | Reason for the abort. |
| now_ms | Time, ms. |
|
static |
The final check is over: PASS with both ends free. An end that binds with its register at the smallest value fails as that.
| r | Run state. |
| now_ms | Time, ms. |
|
static |
The first search of both sides is over.
| r | Run state. |
| now_ms | Time, ms. |
|
static |
Ask the programmer for LEAVE.
| r | Run state. |
| now_ms | Time, ms. |
|
static |
Start the final check: both sides searched again.
| r | Run state. |
| now_ms | Time, ms. |
|
static |
Start a limit search of one side, from the centre outward.
| r | Run state. |
| side | SERVO_LIMRUN_LO or SERVO_LIMRUN_HI. |
| ph | Phase the search runs in. |
| now_ms | Time, ms. |
|
static |
Count the register values that differ from the servo current ones.
| r | Run state. |
| want | The two register values wanted. |
|
static |
Clamp a register value to the range lo to hi.
| v | Value to clamp, 64 bit. |
| lo | Lowest value allowed. |
| hi | Highest value allowed. |
|
static |
The share's terms from the pulses in force: after SERVO PULSES at 1000-2000 those written, not those read.
| r | Run state. |
| side | SERVO_LIMRUN_LO or SERVO_LIMRUN_HI. |
| p_us | Pulse width, microseconds. |
|
static |
Tell whether a millisecond span has elapsed.
| now | Current time, ms. |
| then | Start of the span, ms. |
| ms | Span length, ms. |
|
static |
End the run as FAIL.
| r | Run state. |
| why | Reason for the failure. |
| now_ms | Time, ms. |
|
static |
The run is over. It lets the servo go; aborted, it also asks the supply's output off. A run that ends between CONNECT and LEAVE with nothing running gives the port back, unless it was aborted: the programmer then holds the port for RESTORE, and a STOP or the supply switched off ends its session by itself. Aborted while it waits for ARMED, it asks SAFE: the ARM it asked may not be taken yet, and a release does not replace one (servo_screen.c, post()).
| r | Run state. |
| v | Verdict to store. |
| why | Reason to store. |
| now_ms | Time, ms. |
|
static |
The first CONNECT: the servo as it is.
| r | Run state. |
| sv | Servo as the programmer read it. |
| now_ms | Time, ms. |
|
static |
A session next: the servo back to the centre first, SAFE asked once it had SERVO_LIMRUN_RETURN_MS to get there (servo_limrun_step()).
| r | Run state. |
| now_ms | Time, ms. |
|
static |
A current's magnitude, mA. Wider than the reading: -32768mA is 32768 mA, past every ceiling, not a negative value under them.
| ma | Current, mA, signed. |
|
static |
The first bound side's search after its first write: which register limits it. False where the run ended or tries the other register.
| r | Run state. |
| now_ms | Time, ms. |
|
static |
Record whether any value differs from the servo own.
| r | Run state. |
|
static |
Continue after the probe search of a side.
| r | Run state. |
| now_ms | Time, ms. |
|
static |
A session if the plan changes a value, the final check if not.
| r | Run state. |
| now_ms | Time, ms. |
|
static |
How far now lies outward of was on side, us: positive further from the centre.
| side | SERVO_LIMRUN_LO or SERVO_LIMRUN_HI. |
| now | Result being compared. |
| was | Earlier result to compare against. |
|
static |
The next session's values and the side searched after it (-1: both ends, the final check).
Before the mapping is known: the first bound side's value in the register tried, the other register at its own value. After: each register at its side's stage. Pure: called again at the session's CONNECT it gives the same.
| r | Run state. |
| want | Out: the two register values of the session. |
| search | Out: the side to search after the session, or -1. |
|
static |
A bound side's values worked out for register reg: the overset, or, where it is left out, the final value at once (servo_limrun.h). False where the register holds the smallest value already: nothing lowers it.
| r | Run state. |
| side | SERVO_LIMRUN_LO or SERVO_LIMRUN_HI. |
| reg | Register that limits the side. |
|
static |
NEUTRAL between PULSE LOWER and PULSE UPPER.
| p | Pulses indexed by SERVO_LIMRUN_P_NEUTRAL, _P_LOWER and _P_UPPER, 0.1 us. |
|
static |
The read session's pulses stand: the search's ends, within the bench's PULSE MIN and PULSE MAX, and the port given back. The bench stays SAFE where they are not.
| r | Run state. |
| now_ms | Time, ms. |
|
static |
Register that limits a side, once the mapping is known.
| r | Run state. |
| side | SERVO_LIMRUN_LO or SERVO_LIMRUN_HI. |
|
static |
The search under way has ended.
| r | Run state. |
| bind_us | Position commanded when the bind was seen, us. |
| now_ms | Time, ms. |
|
static |
The search centre and ends: the servo's NEUTRAL, PULSE LOWER and PULSE UPPER once read, rounded inward to whole microseconds so no command passes a pulse limit; the bench's PULSE CENTRE, MIN and MAX before.
| r | Run state. |
|
static |
True while a search phase runs.
| r | Run state. |
|
static |
A write that failed once sent – no answer, or one the programmer did not take: part of it may have landed, so the servo's values count as changed and RESTORE is offered. A write refused before it was sent is servo_limrun_refused()'s.
| r | Run state. |
| now_ms | Time, ms. |
| void servo_limrun_abort | ( | servo_limrun_t * | r, |
| servo_test_abort_t | why, | ||
| uint32_t | now_ms ) |
The caller's reasons.
| r | Run state. Does nothing unless the run is RUNNING. |
| why | Reason from the caller. |
| now_ms | Time of the abort, ms. |
| void servo_limrun_backup | ( | servo_limrun_t * | r, |
| const char * | name ) |
The file the servo's values before the run were saved in, once the programmer names it: its first write saves it.
| r | Run state. |
| name | File name. Ignored when NULL or empty, or when the servo was not read. |
| void servo_limrun_connected | ( | servo_limrun_t * | r, |
| const servo_limrun_servo_t * | sv, | ||
| uint32_t | now_ms ) |
The programmer's answers: the servo read after CONNECT, a write's end with the values the servo holds (servo_limrun_pulsed() for the pulse write: NEUTRAL, PULSE LOWER, PULSE UPPER), and the port back in PWM.
| r | Run state. |
| sv | Servo as read. Ignored when NULL. |
| now_ms | Time of the answer, ms. |
| int32_t servo_limrun_dist | ( | const servo_limrun_servo_t * | sv, |
| uint8_t | side, | ||
| uint16_t | p_us ) |
The share of travel, 0.1us of pulse: p_us's distance from NEUTRAL on side, positive outward, and the pulse limit's.
| sv | Servo pulses, 0.1us. |
| side | SERVO_LIMRUN_LO or SERVO_LIMRUN_HI. |
| p_us | Pulse width, microseconds. |
| void servo_limrun_init | ( | servo_limrun_t * | r | ) |
Clear a run state to idle.
| r | Run state. Does nothing when NULL. |
| void servo_limrun_left | ( | servo_limrun_t * | r, |
| bool | ok, | ||
| uint32_t | now_ms ) |
Feed the answer to LEAVE: the port is given back.
| r | Run state. |
| ok | false ends the run as ABORTED with PROG. |
| now_ms | Time of the answer, ms. |
| void servo_limrun_no_servo | ( | servo_limrun_t * | r, |
| uint32_t | now_ms ) |
The programmer's CONNECT ended with no servo answering (KST_SES_ERR_NO_SERVO).
The run's first CONNECT ends it as FAIL with SERVO_LIMRUN_WHY_NOT_KST, as a read that is no KST or Chaservo servo does; a later CONNECT ends it as servo_limrun_refused() does, with SERVO_LIMRUN_WHY_PROG. Nothing at any other step.
| r | The run; NULL, or one not running, is left as it is. |
| now_ms | Current time, ms. |
| bool servo_limrun_original | ( | const servo_limrun_t * | r, |
| uint16_t * | left, | ||
| uint16_t * | right ) |
The values the servo held before the run, valid once read.
| r | Run state. |
| left | Out: LEFT ANGLE before the run. NULL to skip. |
| right | Out: RIGHT ANGLE before the run. NULL to skip. |
| uint16_t servo_limrun_overset | ( | uint16_t | v0, |
| int32_t | d, | ||
| int32_t | span, | ||
| uint16_t | lo_raw ) |
The overset for value v0 and share d / span: ceil(v0 x share x (100 + SERVO_LIMRUN_OVERSET_PCT) / 100), within lo_raw to v0.
| v0 | Register value at the read. |
| d | Distance of the bound pulse from NEUTRAL, 0.1us. 0 or less returns the lower bound. |
| span | Span of the side, 0.1us. 0 or less returns the lower bound. |
| lo_raw | Smallest value the hard rules take. |
| bool servo_limrun_programming | ( | const servo_limrun_t * | r | ) |
The run holds the programmer: CONNECT to LEAVE.
| r | Run state. NULL gives false. |
| void servo_limrun_pulsed | ( | servo_limrun_t * | r, |
| bool | ok, | ||
| const uint16_t * | pulse_dus, | ||
| uint32_t | now_ms ) |
Feed the end of the pulse write: the pulses the servo holds.
| r | Run state. |
| ok | false ends the run as ABORTED with WRITE. |
| pulse_dus | NEUTRAL, PULSE LOWER and PULSE UPPER, 0.1us. NULL ends the run as WRITE. |
| now_ms | Time of the answer, ms. |
| void servo_limrun_refused | ( | servo_limrun_t * | r, |
| uint32_t | now_ms ) |
The programmer refused the CONNECT, write or LEAVE asked: it never started.
| r | Run state. |
| now_ms | Time of the refusal, ms. |
| bool servo_limrun_restore | ( | const servo_limrun_t * | r | ) |
The run ended as FAIL or ABORTED with the servo's values changed: RESTORE gives back the ones before it.
| r | Run state. |
| bool servo_limrun_running | ( | const servo_limrun_t * | r | ) |
Tell whether the run is RUNNING.
| r | Run state. NULL gives false. |
| uint16_t servo_limrun_scaled | ( | uint16_t | v, |
| int32_t | d, | ||
| int32_t | span, | ||
| uint16_t | lo_raw ) |
The final value for value v and share d / span: floor(v x
share), within lo_raw to v.
| v | Value the share applies to. |
| d | Distance of the free pulse from NEUTRAL, 0.1us. 0 or less returns the lower bound. |
| span | Span of the side, 0.1us. 0 or less returns the lower bound. |
| lo_raw | Smallest value the hard rules take. |
| int32_t servo_limrun_span | ( | const servo_limrun_servo_t * | sv, |
| uint8_t | side ) |
Span of one side, as servo_limrun_span() reports it.
| sv | Servo pulses, 0.1us. |
| side | SERVO_LIMRUN_LO or SERVO_LIMRUN_HI. |
| bool servo_limrun_start | ( | servo_limrun_t * | r, |
| const servo_limrun_cfg_t * | cfg, | ||
| uint32_t | now_ms ) |
Start at now_ms. False, and nothing started, for a configuration whose centre is not between its MIN and MAX.
| r | Run state. Cleared before the run starts. |
| cfg | Configuration of the run. |
| now_ms | Start time, ms. |
| void servo_limrun_step | ( | servo_limrun_t * | r, |
| uint32_t | now_ms, | ||
| const servo_limrun_in_t * | in, | ||
| servo_limrun_do_t * | out ) |
Advance to now_ms: what to do comes back in out.
| r | Run state. |
| now_ms | Current time, ms. |
| in | What the caller knows this step. NULL skips the checks on it. |
| out | Out: cleared, then filled with what the run wants done. NULL to skip. |
| void servo_limrun_supply | ( | servo_limrun_t * | r, |
| const servo_test_reading_t * | s, | ||
| uint32_t | now_ms ) |
The supply's reading.
The first one after the start, answering or not, is what it must stay at: its set points, and its output on or off. An output off then and on later, or a supply that did not answer and answers later, its output on or off, ends the run as a changed supply (SERVO_LIMRUN_WHY_SUPPLY_CHANGED). The caller passes a reading that does not answer where it has none at the start.
| r | Run state. |
| s | Supply reading. Ignored when NULL or during the programmer session. |
| now_ms | Time of the reading, ms. |
| void servo_limrun_supply_refused | ( | servo_limrun_t * | r, |
| bool | output_on, | ||
| uint32_t | now_ms ) |
The caller will not hand the programmer's CONNECT a PD mini that the run did not start with, or one whose output is off (output_on false). A supply the run started with, its output off, ends the run as a reading outside a session does (SERVO_TEST_AB_SUPPLY_OFF); one the run did not start with ends it as a changed supply (SERVO_LIMRUN_WHY_SUPPLY_CHANGED).
| r | Run state. |
| output_on | Whether the supply output is on. |
| now_ms | Time of the refusal, ms. |
| bool servo_limrun_switching | ( | const servo_limrun_t * | r | ) |
The run asked the bench to SAFE or to ARMED and waits for it, or holds the programmer: a disarm then is its own, not the operator's. Not while the servo returns to the centre before a session: a disarm then is the operator's.
| r | Run state. NULL gives false. |
| void servo_limrun_window | ( | servo_limrun_t * | r, |
| const servo_test_win_t * | w ) |
One INA3221 window, as the automatic test takes it.
| r | Run state. |
| w | Window to feed. Ignored when NULL or when it has no current reading. |
| void servo_limrun_written | ( | servo_limrun_t * | r, |
| bool | ok, | ||
| const uint16_t * | angle, | ||
| uint32_t | now_ms ) |
Feed the end of a write: the values the servo holds.
| r | Run state. |
| ok | false ends the run as ABORTED with WRITE. |
| angle | LEFT and RIGHT ANGLE the servo holds, two values. NULL ends the run as WRITE. |
| now_ms | Time of the answer, ms. |
| bool servo_limrun_wrote | ( | const servo_limrun_t * | r | ) |
A value was written and the servo may not hold its own any more.
| r | Run state. |
|
static |
Result of the search that just ended.
| r | Run state. |
| bind_us | Position commanded when the bind was seen, us. Used only when the side bound. |
|
static |
The value the side's stage puts in its register.
| r | Run state. |
| side | SERVO_LIMRUN_LO or SERVO_LIMRUN_HI. |
| reg | Register that limits the side. |