|
rcbench
Servo and ESC test bench: panel, IOmcu and shared C
|
KST servo programming protocol: the order of the writes for a change. More...
Go to the source code of this file.
Data Structures | |
| struct | kst_write_t |
| One write. More... | |
| struct | kst_plan_t |
| A plan: the writes that take the servo from start to target. More... | |
| struct | kst_plan_job_t |
| The state of one planning job: 176 bytes. More... | |
Macros | |
| #define | KST_PLAN_MAX_STEPS 33u |
| 31 writable registers and 1 extra write in each of the 2 searched groups. | |
| #define | KST_PLAN_NO_CAP 0xFFFFFFFFu |
| No cap: a job runs until the planner has its verdict. | |
| #define | KST_PLAN_PIECE_UNITS 10u |
| The most units one piece of work takes. kst_plan_step() ends a call after the piece that brings its count to the budget, so a call takes less than its budget plus this. | |
| #define | KST_PLAN_SLICE_UNITS 100u |
| Units per kst_plan_step() call of a caller that must not block: a call takes 100 to 109 units. | |
| #define | KST_PLAN_WORK_CAP 216000u |
| The cap of such a caller: at most 2,161 calls of KST_PLAN_SLICE_UNITS. | |
Enumerations | |
| enum | kst_plan_kind_t { KST_PLAN_EDIT = 0 , KST_PLAN_RESTORE , KST_PLAN_RELEASE_PAIRING } |
| Kind of a plan. More... | |
| enum | kst_plan_result_t { KST_PLAN_OK = 0 , KST_PLAN_ERR_ARG , KST_PLAN_ERR_RULES , KST_PLAN_ERR_R00 , KST_PLAN_ERR_PAIRING , KST_PLAN_ERR_NO_PATH , KST_PLAN_BUSY , KST_PLAN_ERR_TOO_COMPLEX } |
| Result of a planning request or job. More... | |
Functions | |
| 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. | |
| 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. | |
| 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. | |
KST servo programming protocol: the order of the writes for a change.
Implements the programming protocol of KST and Chaservo servos. KST and Chaservo are names or trademarks of their respective owners; they are used here only to say which servos this module works with (README.md, "Legal notice and disclaimer").
A plan is the list of single-register writes that takes a servo from one image to another. A write frame carries no checksum and a field can lie in two registers, so the order matters: between two writes the servo holds an image that is neither the old nor the new setting.
Rules of a plan:
Order of the register groups in a plan: positions (0x07 to 0x0D), speed (0x04, 0x1B, 0x1C), duty (0x02, 0x01), then every other register by ascending address. A rule that ties the groups to each other is not known.
Execution model: a plan is built by a job, in slices. kst_plan_edit_begin() or kst_plan_restore_begin() checks the request and prepares a kst_plan_job_t; kst_plan_step() then does a bounded amount of work per call and returns KST_PLAN_BUSY until the plan is there. kst_plan_edit() and kst_plan_restore() run a job to its end in one call.
Work is counted in units. One unit is one check of an image against the hard rules, or bookkeeping of about that cost. The count of a request depends on its two images alone, not on how the work is cut into calls. A job has a cap: a request that needs more units than the cap ends with KST_PLAN_ERR_TOO_COMPLEX. That is not KST_PLAN_ERR_NO_PATH: the planner reached no verdict.
SPDX-License-Identifier: MIT
| #define KST_PLAN_SLICE_UNITS 100u |
Units per kst_plan_step() call of a caller that must not block: a call takes 100 to 109 units.
Cost on a Cortex-M33 at 150MHz, computed in an emulator from the instructions a call executes, with ARM GNU 14.2 at -O3; not measured on hardware. The upper estimate counts 1 cycle per instruction, 1 more per load and per store and 2 per basic block. The costliest call found: 122,397 cycles, 816us, over the 71 costliest requests found. The costliest single unit found is 1,228 cycles, which puts a call of 109 units at 133,852 cycles, 892us, or less. A begin call: 9,670 cycles, 64us.
| #define KST_PLAN_WORK_CAP 216000u |
The cap of such a caller: at most 2,161 calls of KST_PLAN_SLICE_UNITS.
The costliest request found takes 120,136 units: a restore that ends unchecked. The cap is 1.8 times that. The costliest edit found takes 118,776 units and ends with KST_PLAN_ERR_NO_PATH. Found by 336 searches that start from the 12 slowest of 10,800,000 random requests, change 1 to 3 register bytes at a time and keep the dearer request; 78 of them end at 120,136 units and none above. A bound over every request is not proven: the cap is what holds one.
| enum kst_plan_kind_t |
| enum kst_plan_result_t |
Result of a planning request or job.
| Enumerator | |
|---|---|
| KST_PLAN_OK | plan made; out holds the writes |
| KST_PLAN_ERR_ARG | a NULL argument |
| KST_PLAN_ERR_RULES | the target breaks a hard rule |
| KST_PLAN_ERR_R00 | the target differs in register 0x00 |
| KST_PLAN_ERR_PAIRING | an edit differs in register 0x1D |
| KST_PLAN_ERR_NO_PATH | no order with valid images in between |
| KST_PLAN_BUSY | the job runs; call kst_plan_step() |
| KST_PLAN_ERR_TOO_COMPLEX | the job's cap is spent; no verdict |
| 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. |