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

The automatic servo test. See servo_test.h for the method. More...

#include "servo_test.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

Data Structures

struct  sample_t
 One reading of the run's meter: a reading of the supply, or a window. More...

Functions

static void mean_add (servo_test_mean_t *m, float v)
 Add a reading to a mean.
static float mean_of (const servo_test_mean_t *m)
 Mean of the readings added so far.
static float enc_dir_deg (const servo_test_t *t, uint16_t raw)
 The angle in the commanded direction: with REVERSE on, the horn turns the other way for the same command, and the angle is negated.
float servo_test_enc_deg (uint16_t raw, uint16_t centre)
 raw from centre on the circle, degrees, -180 to just under 180: 360 / 4096 a count. The difference of any two counts the shortest way round.
float servo_test_enc_wrap (float deg)
 deg on the circle: -180 to just under 180.
bool servo_test_enc_end (const servo_test_t *t, const servo_test_step_t *s, unsigned end, float *deg, float *err)
 The mean settled end angle of step s at end (0 low, 1 high) into deg, degrees from cfg.enc_centre in the commanded direction, -180 to just under 180, and its error against cfg.enc_cmd_deg[end] into err, the same range; either may be NULL.
void servo_test_meter_pdmini (servo_test_meter_t *m)
 Describe the PD mini as the run meter.
void servo_test_meter_model (servo_test_meter_t *m)
 The panel's model of the supply: no lag of its own and no repeats, and its travel times held to what a run on the PD mini can check.
void servo_test_meter_ina3221 (servo_test_meter_t *m, uint16_t shunt_dmohm)
 An INA3221 channel on a shunt of shunt_dmohm, in 0.1mOhm (1000 for 0.1Ohm, which ends the range at 1.638A), named "INA3221" until the caller names the channel, read in 50ms windows: a change of current shows in the window that closes after it, up to 50ms later, and the panel times a move from the windows, so travel times are an upper bound.
static long whole_ma (float a)
 A current in whole mA, held to a range every reading lies in.
bool servo_test_over_a (float a, float limit_a)
 Whether a is above limit_a: both in whole mA, a by its magnitude. The one comparison the verdict and the report make of a current against IDLE CURRENT, HOLD CURRENT and STALL AT.
bool servo_test_stall_unreachable (const servo_test_cfg_t *cfg, bool *by_limit, bool *by_range)
 Whether STALL AT cannot be reached in a run of cfg: at or above the current limit, where the supply holds the current (by_limit), or at or above the end of the meter's range (by_range).
static bool on_windows (const servo_test_t *t)
 Tell whether the run reads the INA3221 windows.
static void set_threshold (servo_test_step_t *s)
 The step's threshold, once its idle readings are in: the larger of the smallest and SERVO_TEST_NOISE_K times their standard deviation.
void servo_test_init (servo_test_t *t)
 Clear a run state to idle.
bool servo_test_running (const servo_test_t *t)
 Tell whether a run is under way.
uint32_t servo_test_travel_window_ms (const servo_test_t *t)
 How long a move of t may take before it is late, or unseen: SERVO_TEST_TRAVEL_TIMEOUT_MS plus the meter's lag, 3300ms on the PD mini.
static void put_line (servo_test_t *t, servo_test_out_t kind, const char *text)
 Queue a line for the card; a CSV row is counted as lost when the outbox is full.
servo_test_out_t servo_test_peek (servo_test_t *t, const char **text)
 The next item for the card, without taking it: OPEN, the CSV's lines, then once the run is over the report's (if REPORT) and END. text is the line, valid until the next call. NONE while nothing waits.
void servo_test_pop (servo_test_t *t)
 The item servo_test_peek() gave has been taken.
bool servo_test_drained (const servo_test_t *t)
 Whether everything of the last run has been handed over.
static servo_test_step_t * cur (servo_test_t *t)
 The step running.
static bool enc_raw_at (const servo_test_t *t, uint32_t at_ms, uint16_t *out)
 The count at at_ms, by servo_test_enc_at()'s rule.
static void enc_close (servo_test_t *t)
 The move the encoder was judging is over: counted into its step.
static void enc_open (servo_test_t *t, uint8_t end, bool counted, uint32_t now_ms)
 A move to end is commanded at now_ms: the encoder judges it from the angle read before.
static void finish (servo_test_t *t, servo_test_abort_t why, uint32_t now_ms)
 The run ends: the output off and the servo let go, whatever ended it.
void servo_test_abort (servo_test_t *t, servo_test_abort_t why, uint32_t now_ms)
 End a running run for why: the output is asked off and the servo let go at the next servo_test_step().
void servo_test_meter_now (servo_test_t *t, const servo_test_meter_now_t *m, uint32_t now_ms)
 The meter as a poll decided it, for every answer the caller has: with each window, each supply sample and each frame. A run on the INA3221 holds the change count of its start (cfg.meter_changes). It ends, as servo_test_abort() ends a run, at the first answer that is not the INA3221 or carries another count: the meter changed under it, whatever it is now. The reason is m->dropped when that drop came after the start, and SERVO_TEST_AB_INA_METER otherwise. Nothing for a run on another meter, which goes on with the meter it started with.
static void command (servo_test_t *t, uint16_t us, uint32_t now_ms)
 Command a pulse width.
static void begin_step (servo_test_t *t, uint8_t idx, uint32_t now_ms)
 The voltage step idx begins: its set point, the servo at its centre, and on the first step the output on.
static void begin_move (servo_test_t *t, uint8_t end, bool counted, uint32_t now_ms)
 A move to end end: counted or not, measured against that end's holding level, or the idle current while it is not known.
static void begin_hold (servo_test_t *t, uint32_t from_ms)
 Begin holding at an end.
static void end_move (servo_test_t *t, bool arrived, uint32_t at_ms)
 The move is over: arrived at at_ms, or timed out.
static uint32_t hold_ms (const servo_test_t *t)
 Length of the hold at an end, ms.
static void begin_brownout (servo_test_t *t, float v, uint32_t now_ms)
 Append the brown-out step at v and begin it.
static void end_step (servo_test_t *t, uint32_t now_ms)
 End the step: begin the next one, or finish the run.
static void end_hold (servo_test_t *t, uint32_t now_ms)
 The hold at an end is over: its level, and the next move or the step's end.
servo_test_start_t servo_test_start (servo_test_t *t, const servo_test_cfg_t *cfg, uint32_t now_ms, const servo_test_reading_t *last, float v_min, float v_max)
 Start a run at now_ms with the supply as last read it and its set points' range v_min to v_max.
static void log_row (servo_test_t *t, const sample_t *m, uint8_t mode, uint16_t position_us, const char *tail)
 One row of the CSV, for a reading: the columns every run has, the encoder's two where it is on, and the meter's six in tail.
static void measure (servo_test_t *t, const sample_t *m)
 A new reading of the meter, measured by the phase it falls in.
static void count_step (servo_test_t *t, uint16_t was, uint16_t now)
 A reading count that moved from was to now: what the meter took since, and what of it never reached the run.
void servo_test_reading (servo_test_t *t, const servo_test_reading_t *r, uint16_t position_us)
 A sample of the supply, with position_us the horn's measured pulse width or 0 for none.
void servo_test_window (servo_test_t *t, const servo_test_win_t *w, uint16_t position_us)
 A window of INA3221 CH1, each number once and in order, with position_us as servo_test_reading() takes it.
bool servo_test_enc_at (const servo_test_t *t, uint32_t at_ms, float *deg)
 The angle at at_ms, degrees from cfg.enc_centre: the newest kept reading taken at or before at_ms (a signed difference, so a reading taken later than the row does not count), when it is no older than SERVO_TEST_ENC_STALE_MS. False when there is none.
void servo_test_encoder (servo_test_t *t, const servo_test_enc_t *e)
 A reading of the output encoder, each one once. Judged against the move under way; kept as the angle the CSV and the SERVO screen show.
void servo_test_step (servo_test_t *t, uint32_t now_ms, const servo_test_in_t *in, servo_test_do_t *out)
 One pass at now_ms: the timers, and what the run wants done since the last pass into out.
servo_test_verdict_t servo_test_verdict (const servo_test_t *t)
 Verdict of a run.
unsigned servo_test_steps_planned (const servo_test_t *t)
 Steps planned, the brown-out counted as one, and the one running, 1-based, for "step 2 of 3".
unsigned servo_test_step_now (const servo_test_t *t)
 Number of the step running.
bool servo_test_max_idle (const servo_test_t *t, float *a)
 The highest, the longest and the lowest of a run, over its characterisation steps; false when none was measured. A current is the one of the largest magnitude, with its sign.
bool servo_test_max_hold (const servo_test_t *t, float *a)
 Highest holding current of a run.
bool servo_test_max_travel (const servo_test_t *t, uint32_t *ms)
 Longest travel time of a run.
bool servo_test_brownout (const servo_test_t *t, float *moved_v, bool *stopped)
 The lowest brown-out voltage the servo moved at, and whether one below it showed none.
bool servo_test_negative_at_rest (const servo_test_t *t)
 Whether a step's idle current reads below -SERVO_TEST_NEG_IDLE_A: the shunt is fitted the other way round.
bool servo_test_rates (const servo_test_t *t, float *per_s, float *module_per_s, uint32_t *interval_ms)
 Readings that reached the run per second, the supply's own per second, and the mean interval between two readings; false before two.

Detailed Description

The automatic servo test. See servo_test.h for the method.

SPDX-License-Identifier: MIT

Function Documentation

◆ begin_brownout()

void begin_brownout ( servo_test_t * t,
float v,
uint32_t now_ms )
static

Append the brown-out step at v and begin it.

Parameters
tRun state.
vSet voltage of the step, V.
now_msTime of the start, ms.

◆ begin_hold()

void begin_hold ( servo_test_t * t,
uint32_t from_ms )
static

Begin holding at an end.

Parameters
tRun state.
from_msStart of the hold, ms.

◆ begin_move()

void begin_move ( servo_test_t * t,
uint8_t end,
bool counted,
uint32_t now_ms )
static

A move to end end: counted or not, measured against that end's holding level, or the idle current while it is not known.

Parameters
tRun state.
end0 for the low end, 1 for the high end.
countedtrue when the move counts.
now_msTime of the command, ms.

◆ begin_step()

void begin_step ( servo_test_t * t,
uint8_t idx,
uint32_t now_ms )
static

The voltage step idx begins: its set point, the servo at its centre, and on the first step the output on.

Parameters
tRun state.
idxIndex of the step to begin.
now_msTime of the start, ms.

◆ command()

void command ( servo_test_t * t,
uint16_t us,
uint32_t now_ms )
static

Command a pulse width.

Parameters
tRun state.
usPulse width to command, us.
now_msTime of the command, ms.

◆ count_step()

void count_step ( servo_test_t * t,
uint16_t was,
uint16_t now )
static

A reading count that moved from was to now: what the meter took since, and what of it never reached the run.

Parameters
tRun state.
wasCount before.
nowCount now.

◆ cur()

servo_test_step_t * cur ( servo_test_t * t)
static

The step running.

Parameters
tRun state.
Returns
the step running.

◆ enc_close()

void enc_close ( servo_test_t * t)
static

The move the encoder was judging is over: counted into its step.

Parameters
tRun state.

◆ enc_dir_deg()

float enc_dir_deg ( const servo_test_t * t,
uint16_t raw )
static

The angle in the commanded direction: with REVERSE on, the horn turns the other way for the same command, and the angle is negated.

Parameters
tRun state.
rawEncoder count, 0 to 4095.
Returns
angle in degrees, negated when reverse is on.

◆ enc_open()

void enc_open ( servo_test_t * t,
uint8_t end,
bool counted,
uint32_t now_ms )
static

A move to end is commanded at now_ms: the encoder judges it from the angle read before.

Parameters
tRun state.
end0 for the low end, 1 for the high end.
countedtrue when the move counts.
now_msTime of the command, ms.

◆ enc_raw_at()

bool enc_raw_at ( const servo_test_t * t,
uint32_t at_ms,
uint16_t * out )
static

The count at at_ms, by servo_test_enc_at()'s rule.

Parameters
tRun state.
at_msTime of the row, ms.
outOut: count of the newest reading in reach.
Returns
true when a kept reading no older than SERVO_TEST_ENC_STALE_MS was taken at or before at_ms.

◆ end_hold()

void end_hold ( servo_test_t * t,
uint32_t now_ms )
static

The hold at an end is over: its level, and the next move or the step's end.

Parameters
tRun state.
now_msTime of the end, ms.

◆ end_move()

void end_move ( servo_test_t * t,
bool arrived,
uint32_t at_ms )
static

The move is over: arrived at at_ms, or timed out.

Parameters
tRun state.
arrivedtrue when the move arrived.
at_msTime the move ended, ms.

◆ end_step()

void end_step ( servo_test_t * t,
uint32_t now_ms )
static

End the step: begin the next one, or finish the run.

Parameters
tRun state.
now_msTime of the end, ms.

◆ finish()

void finish ( servo_test_t * t,
servo_test_abort_t why,
uint32_t now_ms )
static

The run ends: the output off and the servo let go, whatever ended it.

Parameters
tRun state.
whyReason for the end of the run.
now_msTime of the end, ms.

◆ hold_ms()

uint32_t hold_ms ( const servo_test_t * t)
static

Length of the hold at an end, ms.

Parameters
tRun state.
Returns
hold time, ms: DWELL or SERVO_TEST_HOLD_MIN_MS, whichever is longer.

◆ log_row()

void log_row ( servo_test_t * t,
const sample_t * m,
uint8_t mode,
uint16_t position_us,
const char * tail )
static

One row of the CSV, for a reading: the columns every run has, the encoder's two where it is on, and the meter's six in tail.

Parameters
tRun state.
mReading.
modeSupply mode, 0 off, 1 CV, 2 CC; other values print no mode.
position_usMeasured pulse width, us; 0 for none.
tailColumns after the meter word.

◆ mean_add()

void mean_add ( servo_test_mean_t * m,
float v )
static

Add a reading to a mean.

Parameters
mMean to add to.
vValue to add.

◆ mean_of()

float mean_of ( const servo_test_mean_t * m)
static

Mean of the readings added so far.

Parameters
mMean to read.
Returns
the mean, or 0 when no readings were added.

◆ measure()

void measure ( servo_test_t * t,
const sample_t * m )
static

A new reading of the meter, measured by the phase it falls in.

Parameters
tRun state.
mReading of the meter.

◆ on_windows()

bool on_windows ( const servo_test_t * t)
static

Tell whether the run reads the INA3221 windows.

Parameters
tRun state.
Returns
true when the meter is the INA3221.

◆ put_line()

void put_line ( servo_test_t * t,
servo_test_out_t kind,
const char * text )
static

Queue a line for the card; a CSV row is counted as lost when the outbox is full.

Parameters
tRun state.
kindKind of the line.
textLine text.

◆ servo_test_abort()

void servo_test_abort ( servo_test_t * t,
servo_test_abort_t why,
uint32_t now_ms )

End a running run for why: the output is asked off and the servo let go at the next servo_test_step().

Nothing for a run not running.

Parameters
tRun state. NULL is ignored.
whyReason the run ends, reported as ABORTED.
now_msTime of the abort, ms.

◆ servo_test_brownout()

bool servo_test_brownout ( const servo_test_t * t,
float * moved_v,
bool * stopped )

The lowest brown-out voltage the servo moved at, and whether one below it showed none.

Parameters
tRun state. NULL gives false.
moved_vOut: lowest brown-out set point at which the servo moved, V. NULL to skip.
stoppedOut: true when a brown-out step that ran showed no movement. NULL to skip.
Returns
true when a brown-out step moved.

◆ servo_test_drained()

bool servo_test_drained ( const servo_test_t * t)

Whether everything of the last run has been handed over.

Parameters
tRun state.
Returns
true for NULL, or when the run is not RUNNING, nothing is queued and END was handed over.

◆ servo_test_enc_at()

bool servo_test_enc_at ( const servo_test_t * t,
uint32_t at_ms,
float * deg )

The angle at at_ms, degrees from cfg.enc_centre: the newest kept reading taken at or before at_ms (a signed difference, so a reading taken later than the row does not count), when it is no older than SERVO_TEST_ENC_STALE_MS. False when there is none.

Parameters
tRun state.
at_msTime of the row, ms.
degOut: angle, degrees from the centre count.
Returns
true when a kept reading no older than SERVO_TEST_ENC_STALE_MS was taken at or before at_ms; deg is set then.

◆ servo_test_enc_deg()

float servo_test_enc_deg ( uint16_t raw,
uint16_t centre )

raw from centre on the circle, degrees, -180 to just under 180: 360 / 4096 a count. The difference of any two counts the shortest way round.

Parameters
rawEncoder count, 0 to 4095.
centreCentre count, 0 to 4095.
Returns
angle, degrees, -180 up to just under 180.

◆ servo_test_enc_end()

bool servo_test_enc_end ( const servo_test_t * t,
const servo_test_step_t * s,
unsigned end,
float * deg,
float * err )

The mean settled end angle of step s at end (0 low, 1 high) into deg, degrees from cfg.enc_centre in the commanded direction, -180 to just under 180, and its error against cfg.enc_cmd_deg[end] into err, the same range; either may be NULL.

The mean is taken on the circle, from the first end angle of the step. False when no move settled there. End angles of one end that lie 180 degrees or more apart have no mean that says anything.

Parameters
tRun state.
sStep whose settled moves are averaged.
end0 for the low end, 1 for the high end.
degOut: mean end angle, degrees. NULL to skip.
errOut: angle error, degrees. NULL to skip.
Returns
true when a move settled at end; false when none did, or for a NULL argument or an end above 1.

◆ servo_test_enc_wrap()

float servo_test_enc_wrap ( float deg)

deg on the circle: -180 to just under 180.

Parameters
degAngle, degrees.
Returns
angle, degrees, -180 up to just under 180.

◆ servo_test_encoder()

void servo_test_encoder ( servo_test_t * t,
const servo_test_enc_t * e )

A reading of the output encoder, each one once. Judged against the move under way; kept as the angle the CSV and the SERVO screen show.

A reading that is not valid, or that carries gap, ends the angle's validity before it. Nothing is judged without cfg.enc_on.

Parameters
tRun state.
eEncoder reading. NULL is ignored.

◆ servo_test_init()

void servo_test_init ( servo_test_t * t)

Clear a run state to idle.

Parameters
tRun state to clear. NULL is ignored.

◆ servo_test_max_hold()

bool servo_test_max_hold ( const servo_test_t * t,
float * a )

Highest holding current of a run.

Parameters
tRun state.
aOut: holding current of largest magnitude, with its sign. NULL to skip.
Returns
true when a characterisation step measured holding current.

◆ servo_test_max_idle()

bool servo_test_max_idle ( const servo_test_t * t,
float * a )

The highest, the longest and the lowest of a run, over its characterisation steps; false when none was measured. A current is the one of the largest magnitude, with its sign.

Parameters
tRun state.
aOut: idle current of largest magnitude, with its sign. NULL to skip.
Returns
true when a characterisation step measured idle current.

◆ servo_test_max_travel()

bool servo_test_max_travel ( const servo_test_t * t,
uint32_t * ms )

Longest travel time of a run.

Parameters
tRun state.
msOut: longest travel time, ms. NULL to skip.
Returns
true when a counted move of a characterisation step arrived.

◆ servo_test_meter_ina3221()

void servo_test_meter_ina3221 ( servo_test_meter_t * m,
uint16_t shunt_dmohm )

An INA3221 channel on a shunt of shunt_dmohm, in 0.1mOhm (1000 for 0.1Ohm, which ends the range at 1.638A), named "INA3221" until the caller names the channel, read in 50ms windows: a change of current shows in the window that closes after it, up to 50ms later, and the panel times a move from the windows, so travel times are an upper bound.

Parameters
mMeter description to fill. NULL is ignored.
shunt_dmohmShunt resistance, 0.1mOhm.

◆ servo_test_meter_model()

void servo_test_meter_model ( servo_test_meter_t * m)

The panel's model of the supply: no lag of its own and no repeats, and its travel times held to what a run on the PD mini can check.

Parameters
mMeter description to fill. NULL is ignored.

◆ servo_test_meter_now()

void servo_test_meter_now ( servo_test_t * t,
const servo_test_meter_now_t * m,
uint32_t now_ms )

The meter as a poll decided it, for every answer the caller has: with each window, each supply sample and each frame. A run on the INA3221 holds the change count of its start (cfg.meter_changes). It ends, as servo_test_abort() ends a run, at the first answer that is not the INA3221 or carries another count: the meter changed under it, whatever it is now. The reason is m->dropped when that drop came after the start, and SERVO_TEST_AB_INA_METER otherwise. Nothing for a run on another meter, which goes on with the meter it started with.

Parameters
tRun state.
mThe answer of the poll. NULL is ignored.
now_msTime of the poll, ms.

◆ servo_test_meter_pdmini()

void servo_test_meter_pdmini ( servo_test_meter_t * m)

Describe the PD mini as the run meter.

Parameters
mMeter description to fill. NULL is ignored.

◆ servo_test_negative_at_rest()

bool servo_test_negative_at_rest ( const servo_test_t * t)

Whether a step's idle current reads below -SERVO_TEST_NEG_IDLE_A: the shunt is fitted the other way round.

Parameters
tRun state.
Returns
true when a step idle mean is below minus SERVO_TEST_NEG_IDLE_A, in whole mA.

◆ servo_test_over_a()

bool servo_test_over_a ( float a,
float limit_a )

Whether a is above limit_a: both in whole mA, a by its magnitude. The one comparison the verdict and the report make of a current against IDLE CURRENT, HOLD CURRENT and STALL AT.

Parameters
aCurrent, A.
limit_aLimit, A.
Returns
true when the magnitude of a, in whole mA, is above limit_a in whole mA.

◆ servo_test_peek()

servo_test_out_t servo_test_peek ( servo_test_t * t,
const char ** text )

The next item for the card, without taking it: OPEN, the CSV's lines, then once the run is over the report's (if REPORT) and END. text is the line, valid until the next call. NONE while nothing waits.

Parameters
tRun state. NULL gives NONE.
textOut: text of the item; empty when none.
Returns
kind of the next item: queued lines first, then the report lines, then END; NONE while nothing waits.

◆ servo_test_pop()

void servo_test_pop ( servo_test_t * t)

The item servo_test_peek() gave has been taken.

Parameters
tRun state.

◆ servo_test_rates()

bool servo_test_rates ( const servo_test_t * t,
float * per_s,
float * module_per_s,
uint32_t * interval_ms )

Readings that reached the run per second, the supply's own per second, and the mean interval between two readings; false before two.

Parameters
tRun state. NULL gives false.
per_sOut: readings per second that reached the run. NULL to skip.
module_per_sOut: the supply's own samples per second. NULL to skip.
interval_msOut: mean interval between two readings, ms. NULL to skip.
Returns
true when two readings span time; false before two readings or when they share a time.

◆ servo_test_reading()

void servo_test_reading ( servo_test_t * t,
const servo_test_reading_t * r,
uint16_t position_us )

A sample of the supply, with position_us the horn's measured pulse width or 0 for none.

One that repeats the last reading's sample count is checked for the supply's state and measures nothing. In a run on the INA3221 no sample measures: each is the supply's state alone.

Parameters
tRun state.
rThe sample. NULL is ignored.
position_usHorn pulse width, us; 0 for none.

◆ servo_test_running()

bool servo_test_running ( const servo_test_t * t)

Tell whether a run is under way.

Parameters
tRun state. NULL gives false.
Returns
true while the state is RUNNING.

◆ servo_test_stall_unreachable()

bool servo_test_stall_unreachable ( const servo_test_cfg_t * cfg,
bool * by_limit,
bool * by_range )

Whether STALL AT cannot be reached in a run of cfg: at or above the current limit, where the supply holds the current (by_limit), or at or above the end of the meter's range (by_range).

Either may be NULL. Compared in whole mA.

Parameters
cfgConfiguration of the run. NULL gives false.
by_limitOut: true when STALL AT is at or above the current limit. NULL to skip.
by_rangeOut: true when the meter is the INA3221 and STALL AT is at or above its range. NULL to skip.
Returns
true when either holds.

◆ servo_test_start()

servo_test_start_t servo_test_start ( servo_test_t * t,
const servo_test_cfg_t * cfg,
uint32_t now_ms,
const servo_test_reading_t * last,
float v_min,
float v_max )

Start a run at now_ms with the supply as last read it and its set points' range v_min to v_max.

Refused, and nothing changed, for no step and no brown-out, a step outside the range, a supply that does not answer, or ends not either side of the centre. A run that starts hands over OPEN and the CSV header first.

Parameters
tRun state to start. NULL is refused as NO_STEPS.
cfgConfiguration of the run, copied into the state. NULL is refused as NO_STEPS.
now_msTime of the start, ms.
lastThe supply as last read. NULL or offline is refused as NO_SUPPLY.
v_minLowest set point of the supply, V.
v_maxHighest set point of the supply, V.
Returns
SERVO_TEST_START_OK when the run started; otherwise the reason it was refused.

◆ servo_test_step()

void servo_test_step ( servo_test_t * t,
uint32_t now_ms,
const servo_test_in_t * in,
servo_test_do_t * out )

One pass at now_ms: the timers, and what the run wants done since the last pass into out.

Parameters
tRun state. NULL is ignored.
now_msTime of the pass, ms.
inWhat the caller knows: armed and the voltage cap. NULL keeps the cap as it was and does not disarm the run.
outOut: what the run wants done. NULL is ignored.

◆ servo_test_step_now()

unsigned servo_test_step_now ( const servo_test_t * t)

Number of the step running.

Parameters
tRun state. NULL gives 0.
Returns
1-based number of the step running; 0 for NULL or a run with no steps.

◆ servo_test_steps_planned()

unsigned servo_test_steps_planned ( const servo_test_t * t)

Steps planned, the brown-out counted as one, and the one running, 1-based, for "step 2 of 3".

Parameters
tRun state. NULL gives 0.
Returns
steps planned, the brown-out walk counted as one.

◆ servo_test_travel_window_ms()

uint32_t servo_test_travel_window_ms ( const servo_test_t * t)

How long a move of t may take before it is late, or unseen: SERVO_TEST_TRAVEL_TIMEOUT_MS plus the meter's lag, 3300ms on the PD mini.

Parameters
tRun state. NULL uses no meter lag.
Returns
SERVO_TEST_TRAVEL_TIMEOUT_MS plus the meter lag_ms, ms.

◆ servo_test_verdict()

servo_test_verdict_t servo_test_verdict ( const servo_test_t * t)

Verdict of a run.

Parameters
tRun state.
Returns
ABORTED for NULL or an aborted run; FAIL on a stall, a limit exceeded or a timed-out move; NOT_MEASURABLE when a counted move showed no movement; otherwise PASS.

◆ servo_test_window()

void servo_test_window ( servo_test_t * t,
const servo_test_win_t * w,
uint16_t position_us )

A window of INA3221 CH1, each number once and in order, with position_us as servo_test_reading() takes it.

The reading of a run on the INA3221, and nothing to any other run. A window without current or without voltage samples, and one that repeats the last number, measures nothing and does not count as a window that arrived.

Parameters
tRun state.
wThe window. NULL is ignored.
position_usHorn pulse width, us; 0 for none.

◆ set_threshold()

void set_threshold ( servo_test_step_t * s)
static

The step's threshold, once its idle readings are in: the larger of the smallest and SERVO_TEST_NOISE_K times their standard deviation.

Parameters
sStep whose idle readings are in.

◆ whole_ma()

long whole_ma ( float a)
static

A current in whole mA, held to a range every reading lies in.

Parameters
aCurrent, A.
Returns
the current in whole mA; a value beyond +-1000000A is clamped to +-1000000000mA, and NaN gives 0.