|
rcbench
Servo and ESC test bench: panel, IOmcu and shared C
|
Search for the order of the register writes that changes an image. More...
Macros | |
| #define | GROUPS 2u |
| #define | UNITS_CHOOSE KST_PLAN_PIECE_UNITS |
| Units of the work that is no image check, by its cost against one. | |
| #define | UNITS_SETTLE 4u |
Enumerations | |
| enum | { PH_IDLE = 0 , PH_GROUP , PH_SEARCH , PH_FIELD , PH_OPEN , PH_CHOOSE , PH_SETTLE , PH_DONE } |
| What a job does next. More... | |
Functions | |
| static bool | bit_of (const uint8_t *set, unsigned i) |
| static void | bit_set (uint8_t *set, unsigned i) |
| Set one bit of a bit set. | |
| static void | bit_clear (uint8_t *set, unsigned i) |
| Clear one bit of a bit set. | |
| static const uint8_t * | regs_of (const kst_plan_job_t *j) |
| The register list of the group the job works on. | |
| static unsigned | count_of (const kst_plan_job_t *j) |
| Number of registers in the group the job is working on. | |
| static void | emit (kst_plan_job_t *j, uint8_t reg, uint8_t value) |
| Append a write to the plan and apply it to the job's image. | |
| static bool | valid (kst_plan_job_t *j) |
| Check the job's image against the hard rules it may not break. | |
| static bool | sound (kst_plan_job_t *j, unsigned todo) |
Whether the image with the registers of todo still to write is valid; j->img is that image. | |
| static void | forget (kst_plan_job_t *j, unsigned lo) |
Forget what is known of every subset that holds register index lo: its images change with the value of that register. | |
| static uint16_t | raw_of (const kst_image_t *img, kst_field_id_t id) |
| A field's raw value, as kst_field_get() gives it, read from the table row in place: the search reads two fields for every image it scores. | |
| static int32_t | authority (const kst_plan_job_t *j) |
| Lower is better: less travel between the end points, or less speed. | |
| static unsigned | pick (kst_plan_job_t *j) |
| The register of j->todo, not tried at this depth, whose write leaves a valid image of the least authority; of two alike the first. | |
| static void | take_back (kst_plan_job_t *j) |
| Take back the write at the depth below. | |
| static void | search_begin (kst_plan_job_t *j) |
| Start the depth-first search for an order of the group's changed registers. | |
| static void | search_found (kst_plan_job_t *j) |
| The search found an order: its writes go into the plan, after the extra write when the search ran from a detour value. | |
| static void | search_level (kst_plan_job_t *j) |
| One level of a depth-first search for an order of the registers in j->todo, bit i for the group's register i, in which every image is valid. | |
| static uint16_t | excursion (uint16_t a, uint16_t b) |
| Absolute difference of two 16-bit values. | |
| static uint16_t | low_part (const kst_field_t *f, unsigned x) |
The part of a field's value that its low register holds when the register holds x. | |
| static unsigned | index_of (const kst_plan_job_t *j, uint8_t reg) |
| Index of a register in the group the job is working on. | |
| static void | finish (kst_plan_job_t *j, kst_plan_result_t result) |
| End the job with a result. | |
| static void | emit_if_changed (kst_plan_job_t *j, uint8_t reg) |
| Write a register to its target value when the job's image differs from it. | |
| static void | emit_duty (kst_plan_job_t *j) |
| Write Max. | |
| static void | settle_begin (kst_plan_job_t *j) |
| Start the settled-mark pass from the start image. | |
| static void | group_failed (kst_plan_job_t *j) |
| No order and no detour for a group. | |
| static void | field_next (kst_plan_job_t *j) |
| The next field, from j->field on, that lies in two of the group's registers which both change: its low byte can take one extra write to a third value before the search runs again. | |
| static void | open_one (kst_plan_job_t *j) |
| One value of the detour byte: it is a candidate when the image with it is valid and it is neither the old nor the new value. | |
| static void | choose (kst_plan_job_t *j) |
| The untried detour value with the smallest excursion of the field from its old value before, and from its new value after, the high part changes; of two alike the lower value. | |
| static bool | in_group (uint8_t reg) |
| Check whether a register is one of the two searched groups. | |
| static bool | pair_is (const kst_image_t *img, const kst_image_t *ref) |
| Check whether registers 0x02 and 0x01 of two images agree. | |
| static bool | is_settled (const kst_plan_t *plan, const kst_image_t *img) |
| Check that every two-register field of an image holds its start or its target value. | |
| static void | settle_one (kst_plan_job_t *j) |
| The settled mark of the next write, or the end of the job after the last. j->img follows the plan from its start image. | |
| static void | group_begin (kst_plan_job_t *j) |
| Take up the next group: the registers of it that change, and nothing known of their subsets. | |
| static void | advance (kst_plan_job_t *j) |
| Run one step of the job, selected by its phase. | |
| kst_plan_result_t | kst_plan_step (kst_plan_job_t *job, uint32_t budget) |
Advance a job by budget units. | |
| uint32_t | kst_plan_units (const kst_plan_job_t *job) |
| Units the job has taken so far. | |
| static void | begin (kst_plan_t *out, const kst_image_t *start, const kst_image_t *target, kst_plan_kind_t kind) |
start and target may lie in out, as a plan's own start or target do: both are read before the plan is cleared. | |
| static kst_plan_result_t | ended (kst_plan_job_t *job, kst_plan_result_t result) |
| A final result at a begin call. | |
| static kst_plan_result_t | job_begin (kst_plan_job_t *job, kst_plan_t *out, bool may_be_unchecked, uint32_t cap) |
| Set up a planning job for a plan from its start and target images. | |
| kst_plan_result_t | kst_plan_edit_begin (kst_plan_job_t *job, const kst_image_t *start, const kst_image_t *target, kst_field_set_t unlocked, kst_plan_t *out, kst_rules_t *violated, uint32_t cap) |
Check an edit from start to target and prepare job to plan it into out. | |
| kst_plan_result_t | kst_plan_restore_begin (kst_plan_job_t *job, const kst_image_t *current, const kst_image_t *backup, kst_plan_t *out, uint32_t cap) |
| The same for kst_plan_restore(): KST_PLAN_BUSY, or KST_PLAN_ERR_ARG or KST_PLAN_ERR_R00 at once. | |
| static kst_plan_result_t | run (kst_plan_job_t *job, kst_plan_result_t r) |
| Run a job to its end in one call. | |
| kst_plan_result_t | kst_plan_edit (const kst_image_t *start, const kst_image_t *target, kst_field_set_t unlocked, kst_plan_t *out, kst_rules_t *violated) |
Plan an edit from start to target. | |
| kst_plan_result_t | kst_plan_restore (const kst_image_t *current, const kst_image_t *backup, kst_plan_t *out) |
Plan the way from current back to backup. | |
| kst_plan_result_t | kst_plan_release_pairing (const kst_image_t *current, kst_plan_t *out) |
| Plan the write of 0x00 to register 0x1D. | |
| bool | kst_plan_image_after (const kst_plan_t *plan, unsigned steps, kst_image_t *out) |
The image after the first steps writes of a plan. | |
Variables | |
| static const uint8_t | k_position [] = { 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D } |
| The registers whose hard rules read each other. | |
| static const uint8_t | k_speed [] = { 0x04, 0x1B, 0x1C } |
Search for the order of the register writes that changes an image.
SPDX-License-Identifier: MIT
| #define UNITS_SETTLE 4u |
the settled mark of one write
| anonymous enum |
What a job does next.
One call of advance() does one of these once.
|
static |
Lower is better: less travel between the end points, or less speed.
With spd_sel off the servo runs at its own speed, taken as the highest.
|
static |
start and target may lie in out, as a plan's own start or target do: both are read before the plan is cleared.
The caller reads them from the plan afterwards.
|
static |
The untried detour value with the smallest excursion of the field from its old value before, and from its new value after, the high part changes; of two alike the lower value.
The search then runs from it. The excursion is computed again for every pass, from the field's layout: the open set is 32 bytes, a table of the 256 excursions is 512.
|
static |
Write Max.
Duty and its copy to their target values when they differ.
|
static |
A final result at a begin call.
The job, when there is one, holds it.
|
static |
End the job with a result.
A result other than KST_PLAN_OK leaves no writes in the plan.
|
static |
Forget what is known of every subset that holds register index lo: its images change with the value of that register.
The subsets without it keep their verdicts, which hold for every detour value.
|
static |
Take up the next group: the registers of it that change, and nothing known of their subsets.
After the last group the duty pair and every other register follow, which need no search.
|
static |
No order and no detour for a group.
An edit ends here; a restore takes ascending address order and is marked unchecked.
|
static |
Index of a register in the group the job is working on.
The group's count when the register is not in it.
| kst_plan_result_t kst_plan_edit | ( | const kst_image_t * | start, |
| const kst_image_t * | target, | ||
| kst_field_set_t | unlocked, | ||
| kst_plan_t * | out, | ||
| kst_rules_t * | violated ) |
Plan an edit from start to target.
The hard rules of kst_limits_edit(start, target, unlocked) are checked first; violated, when not NULL, receives the broken ones. Soft rules do not refuse a plan: the caller shows them and asks.
out holds a plan with 0 writes when the result is not KST_PLAN_OK.
| start | Image the servo holds. |
| target | Image to reach. |
| unlocked | Fields whose KST_ACCESS_LOCKED is lifted. |
| out | Receives the plan. |
| violated | Receives the hard rules broken; may be NULL. |
| kst_plan_result_t kst_plan_edit_begin | ( | kst_plan_job_t * | job, |
| const kst_image_t * | start, | ||
| const kst_image_t * | target, | ||
| kst_field_set_t | unlocked, | ||
| kst_plan_t * | out, | ||
| kst_rules_t * | violated, | ||
| uint32_t | cap ) |
Check an edit from start to target and prepare job to plan it into out.
KST_PLAN_BUSY: the job is ready for kst_plan_step(). Every other result is final and is what kst_plan_edit() returns for the same request before it searches: KST_PLAN_ERR_ARG, _R00, _PAIRING, _RULES. The call checks at most 4 images; its cost does not grow with the request.
start and target are copied before out is cleared: either may lie in out. The same holds for kst_plan_restore_begin(), kst_plan_edit(), kst_plan_restore() and kst_plan_release_pairing().
cap is the most units the job may take, or KST_PLAN_NO_CAP.
| job | Job to prepare. |
| start | Image the servo holds. |
| target | Image to reach. |
| unlocked | Fields whose KST_ACCESS_LOCKED is lifted. |
| out | Receives the plan. |
| violated | Receives the hard rules broken; may be NULL. |
| cap | Most units the job may take, or KST_PLAN_NO_CAP. |
| bool kst_plan_image_after | ( | const kst_plan_t * | plan, |
| unsigned | steps, | ||
| kst_image_t * | out ) |
The image after the first steps writes of a plan.
False for more steps than the plan has.
| plan | Plan to apply. |
| steps | Number of writes to apply. |
| out | Receives the image. |
| kst_plan_result_t kst_plan_release_pairing | ( | const kst_image_t * | current, |
| kst_plan_t * | out ) |
Plan the write of 0x00 to register 0x1D.
0x00 is the only value the vendor's card does not refuse in any tested case. The effect inside the servo is not known. A card identifier is never written.
| current | Image the servo holds. |
| out | Receives the plan. |
| kst_plan_result_t kst_plan_restore | ( | const kst_image_t * | current, |
| const kst_image_t * | backup, | ||
| kst_plan_t * | out ) |
Plan the way from current back to backup.
Access classes and limits do not apply: every value is one this servo held. Register 0x1D is written back like any other. A difference in register 0x00 is refused.
| current | Image the servo holds. |
| backup | Image to return to. |
| out | Receives the plan. |
| kst_plan_result_t kst_plan_restore_begin | ( | kst_plan_job_t * | job, |
| const kst_image_t * | current, | ||
| const kst_image_t * | backup, | ||
| kst_plan_t * | out, | ||
| uint32_t | cap ) |
The same for kst_plan_restore(): KST_PLAN_BUSY, or KST_PLAN_ERR_ARG or KST_PLAN_ERR_R00 at once.
| job | Job to prepare. |
| current | Image the servo holds. |
| backup | Image to return to. |
| out | Receives the plan. |
| cap | Most units the job may take, or KST_PLAN_NO_CAP. |
| kst_plan_result_t kst_plan_step | ( | kst_plan_job_t * | job, |
| uint32_t | budget ) |
Advance a job by budget units.
The call ends after the piece of work that brings its count to budget or above; a piece is at most KST_PLAN_PIECE_UNITS units. budget 0 does nothing.
KST_PLAN_BUSY while work is left. Then the job's result, and the same result on every later call: KST_PLAN_OK, KST_PLAN_ERR_NO_PATH, or KST_PLAN_ERR_TOO_COMPLEX when the job needs more units than its cap. A job that needs as many units as its cap ends with its verdict. The plan holds 0 writes after every result but KST_PLAN_OK.
A job whose begin call returned a final result gives that result. KST_PLAN_ERR_ARG for NULL and for a job of zeroed memory.
| job | Job to advance. |
| budget | Units to take. |
| uint32_t kst_plan_units | ( | const kst_plan_job_t * | job | ) |
Units the job has taken so far.
| job | Job to read. |
|
static |
The register of j->todo, not tried at this depth, whose write leaves a valid image of the least authority; of two alike the first.
The group's count when there is none. A register whose write leaves an invalid image, or a set of registers known to have no order, is marked tried.
|
static |
The register list of the group the job works on.
| j | Job whose group is read. |
|
static |
One level of a depth-first search for an order of the registers in j->todo, bit i for the group's register i, in which every image is valid.
At most 7 levels deep; the levels are the entries of order, tried and held. No image is copied and no function calls itself: a write is tried in j->img and taken back.
|
static |
Whether the image with the registers of todo still to write is valid; j->img is that image.
The image is a function of todo and, while the detour byte is in todo, of the detour value, so the verdict is kept per subset and an image is checked once.
|
static |
Take back the write at the depth below.
Its bit returns to the todo set.
|
static |
Check the job's image against the hard rules it may not break.
Costs one unit.
|
static |
The registers whose hard rules read each other.
Every other register has rules that read that register alone.