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

Hitec session: entry, reads, write plans and leave, handed out as steps. More...

#include "hitec_session.h"
#include <string.h>

Macros

#define C_FIRST_P1   0x00u
 The first command's first byte, as the HPP-21 Plus sends it.
#define C_FIRST_P2   0x00u
 The first command's second byte, as the HPP-21 Plus sends it.
#define SET_BITS   (HITEC_SES_SET_BYTES * 8u)
 Bits of an address set.

Enumerations

enum  {
  OP_NONE = 0 , OP_ENTER , OP_READ , OP_WRITE ,
  OP_LEAVE
}
 Operation the session runs.
enum  {
  PH_C_POWER = 0 , PH_C_NEXT , PH_C_FIRST , PH_D_POWER ,
  PH_READ , PH_WRITE , PH_LEAVE
}
 The step an operation is at.

Functions

bool hitec_ses_in_set (const uint8_t *set, uint8_t addr)
 True when address addr is in the set set.
static void set_add (uint8_t *set, uint8_t addr)
 Put addr into set.
static void set_drop (uint8_t *set, uint8_t addr)
 Take addr out of set.
static bool set_first (const uint8_t *set, uint8_t *out)
 The lowest address in set.
static uint16_t set_count (const uint8_t *set)
 Addresses in set.
static void set_full_read (uint8_t series, uint8_t *set)
 Put the series' full read into set.
static uint32_t ticks (const hitec_session_t *s, uint32_t ms)
 ms in ticks of the session's clock.
static void gap_from (hitec_session_t *s, uint32_t now, uint32_t ms)
 Start the gap of ms before the next step, from now.
static uint32_t series_gap (const hitec_session_t *s)
 The gap after a transaction of the session's series.
static uint32_t step_gap (const hitec_session_t *s)
 The wait the step that is out asks for once its result comes, whether it ran, was cut or was lost.
static bool read_back (const hitec_session_t *s, uint8_t addr)
 True when the read-back of the running write has read addr.
static void forget_unsure (hitec_session_t *s)
 After a write that failed: mark every address the servo may have changed and the read-back has not read as not known.
static hitec_ses_t finish (hitec_session_t *s, hitec_ses_t res)
 End the operation with res; an abort asked for ends it with HITEC_SES_ERR_ABORTED. A write that ends with an error after a step was handed out and its result fed forgets what the servo may have changed.
static void begin (hitec_session_t *s, uint8_t op, uint8_t phase)
 Begin operation op at phase.
static void begin_read (hitec_session_t *s)
 Go to a read of the addresses in todo.
static hitec_ses_t may_start (const hitec_session_t *s, bool in_mode)
 The common refusals of an operation.
bool hitec_session_init (hitec_session_t *s, uint8_t series, uint8_t clock)
 Prepare a session for one series.
hitec_ses_t hitec_session_enter (hitec_session_t *s, bool power, uint16_t off_ms)
 Enter programming mode.
hitec_ses_t hitec_session_read_all (hitec_session_t *s)
 Read the series' full set: hitec_d_read_list() or hitec_c_read_ranges().
hitec_ses_t hitec_session_read_set (hitec_session_t *s, const uint8_t *addrs, uint16_t n)
 Read n addresses into the image, which keeps the rest.
static bool plan_fits (const hitec_session_t *s, const hitec_plan_t *plan)
 True when every step of plan is one the session runs on its series.
static hitec_ses_t start_plan (hitec_session_t *s, bool compare)
 Start the plan in s->plan; the read-back compares with target when compare.
hitec_ses_t hitec_session_write (hitec_session_t *s, const hitec_image_t *target)
 Write the servo from the image to target, then read it back.
hitec_ses_t hitec_session_run_plan (hitec_session_t *s, const hitec_plan_t *plan, const hitec_image_t *expect)
 Run a plan the caller built, such as hitec_d_factory_plan(), then read back as hitec_session_write() does.
hitec_ses_t hitec_session_leave (hitec_session_t *s)
 Leave programming mode.
bool hitec_session_abort (hitec_session_t *s)
 End the running operation with HITEC_SES_ERR_ABORTED.
hitec_ses_t hitec_session_result (const hitec_session_t *s)
 The running operation's state.
static void power_step (const hitec_session_t *s, hitec_ses_step_t *st, uint32_t window_us, bool answer)
 A POWER step whose LISTEN waits window_us.
static void build (hitec_session_t *s)
 Build the step of the operation's phase into s->step.
hitec_ses_kind_t hitec_session_next (hitec_session_t *s, uint32_t now, hitec_ses_step_t *out)
 The step to run at now.
static bool compare (hitec_session_t *s)
 True when the image holds what target holds at every address the read-back checks; diff names the others.
static hitec_ses_t fail (hitec_session_t *s, uint8_t rx)
 The end of a failed transaction with no tries left, or with none at all.
static hitec_ses_t read_took (hitec_session_t *s, uint16_t value)
 The read of s->addr took value: store it, then the next address or the operation's end. The gap is the one feed started.
static hitec_ses_t write_took (hitec_session_t *s, uint32_t now)
 The write of plan.step[step_index] took: count it, start its wait, then the next write or the read-back.
static hitec_ses_t decoded (hitec_session_t *s, uint32_t now, uint8_t rx, uint16_t value)
 A decoded transaction ended with rx.
hitec_ses_t hitec_session_feed (hitec_session_t *s, uint32_t now, const hitec_ses_result_t *r)
 Take the result of the step that is out.

Detailed Description

Hitec session: entry, reads, write plans and leave, handed out as steps.

SPDX-License-Identifier: MIT

Function Documentation

◆ begin()

void begin ( hitec_session_t * s,
uint8_t op,
uint8_t phase )
static

Begin operation op at phase.

Parameters
sSession.
opOperation.
phaseIts first step.

◆ begin_read()

void begin_read ( hitec_session_t * s)
static

Go to a read of the addresses in todo.

Parameters
sSession.

◆ build()

void build ( hitec_session_t * s)
static

Build the step of the operation's phase into s->step.

Parameters
sSession.

◆ compare()

bool compare ( hitec_session_t * s)
static

True when the image holds what target holds at every address the read-back checks; diff names the others.

Parameters
sSession.
Returns
true when nothing differs.

◆ decoded()

hitec_ses_t decoded ( hitec_session_t * s,
uint32_t now,
uint8_t rx,
uint16_t value )
static

A decoded transaction ended with rx.

Parameters
sSession.
nowThe clock.
rxhitec_rx_t.
valueThe decoded value.
Returns
HITEC_SES_BUSY, or the result the operation ends with.

◆ fail()

hitec_ses_t fail ( hitec_session_t * s,
uint8_t rx )
static

The end of a failed transaction with no tries left, or with none at all.

Parameters
sSession.
rxThe last try's hitec_rx_t.
Returns
The result the operation ends with.

◆ finish()

hitec_ses_t finish ( hitec_session_t * s,
hitec_ses_t res )
static

End the operation with res; an abort asked for ends it with HITEC_SES_ERR_ABORTED. A write that ends with an error after a step was handed out and its result fed forgets what the servo may have changed.

Parameters
sSession.
resResult.
Returns
The result the operation ended with.

◆ forget_unsure()

void forget_unsure ( hitec_session_t * s)
static

After a write that failed: mark every address the servo may have changed and the read-back has not read as not known.

D series: every register of the full read and every register the plan names; a save, a reboot or a factory reset may change any of them. Classic: the cell of the step that ran with no + +, and the balance.

Parameters
sSession.

◆ gap_from()

void gap_from ( hitec_session_t * s,
uint32_t now,
uint32_t ms )
static

Start the gap of ms before the next step, from now.

Parameters
sSession.
nowThe clock.
msGap, ms; 0 for none.

◆ hitec_ses_in_set()

bool hitec_ses_in_set ( const uint8_t * set,
uint8_t addr )

True when address addr is in the set set.

Parameters
setHITEC_SES_SET_BYTES bytes, bit a % 8 of byte a / 8.
addrAddress.
Returns
true when the bit is set; false for NULL.

◆ hitec_session_abort()

bool hitec_session_abort ( hitec_session_t * s)

End the running operation with HITEC_SES_ERR_ABORTED.

With no step out it ends at once. With a step out it ends when that step's result comes: the caller cuts the step and feeds its result, which the session stores as far as it went. Until then hitec_session_next() gives the same step.

Parameters
sSession.
Returns
true when a step is out and its result is still owed.

◆ hitec_session_enter()

hitec_ses_t hitec_session_enter ( hitec_session_t * s,
bool power,
uint16_t off_ms )

Enter programming mode.

Classic: POWER (off off_ms, on, a LISTEN of HITEC_SES_C_ENTRY_WINDOW_US that answers the servo's + with +), a LISTEN of HITEC_SES_C_NEXT_WINDOW_US for the servo's next +, then the first command 67 00 00 99, whose reply's value is the version. A listen that gets no + ends the entry; the first command has HITEC_SES_TRIES tries. Classic entry always cycles the supply.

D series: with power, POWER (off off_ms, on, a LISTEN of HITEC_SES_POWER_WINDOW_US that waits for nothing) and HITEC_SES_D_ENTRY_WAIT_MS; without it, on the supply as it is. Then a read of register 0x00, the model, with HITEC_SES_TRIES tries.

The image starts empty and holds the version or the model. The off time is kept for the leave.

Parameters
sSession.
powerD series: cycle the supply first; classic: ignored.
off_msSupply off time, 0 to HITEC_SES_OFF_MS_MAX.
Returns
HITEC_SES_BUSY when the entry starts; HITEC_SES_ERR_BUSY, HITEC_SES_ERR_ARG.

◆ hitec_session_feed()

hitec_ses_t hitec_session_feed ( hitec_session_t * s,
uint32_t now,
const hitec_ses_result_t * r )

Take the result of the step that is out.

CUT ends the operation with HITEC_SES_ERR_CUT, FAILED with HITEC_SES_ERR_LINK. A step with a decoder: HITEC_RX_OK goes on; HITEC_RX_ERR_ARG ends it with HITEC_SES_ERR_STEP; HITEC_RX_ERR_ABORTED with HITEC_SES_ERR_CUT; every other code is a failed try. A failed try of a classic entry LISTEN ends the entry. A transaction with tries left goes again after its gap; one with none ends the operation with HITEC_SES_ERR_NO_SERVO when the last try was HITEC_RX_ERR_SILENT, else with the operation's error: ENTRY, READ or WRITE.

Every result starts the gap of the step that ended before anything else, a cut or lost step's included, since its frame may have reached the servo: the series gap, a plan step's longer wait, the D series entry's 1000ms, the 1000ms after a D series leave. An abort, an error or the end of the operation keeps it; the next operation waits it out.

Parameters
sSession.
nowThe clock when the step ended.
rThe result.
Returns
HITEC_SES_BUSY while the operation runs, then its result; HITEC_SES_ERR_ARG, and no change, for NULL or no step out.

◆ hitec_session_init()

bool hitec_session_init ( hitec_session_t * s,
uint8_t series,
uint8_t clock )

Prepare a session for one series.

No operation runs, no step is due, not in mode; off time HITEC_SES_OFF_MS.

Parameters
sSession.
serieshitec_family_t, chosen by the operator.
clockhitec_ses_clock_t of the now the caller passes.
Returns
false for NULL, an unknown series or an unknown clock.

◆ hitec_session_leave()

hitec_ses_t hitec_session_leave ( hitec_session_t * s)

Leave programming mode.

Classic: POWER (off off_ms, on, a LISTEN of HITEC_SES_POWER_WINDOW_US with no answer). D series: the reboot, 0x46 = 1, then HITEC_D_REBOOT_WAIT_MS before the next step of any operation. in_mode is 0 from the start of the leave. Taken in or out of mode.

Parameters
sSession.
Returns
HITEC_SES_BUSY when the leave starts; HITEC_SES_ERR_BUSY, HITEC_SES_ERR_ARG.

◆ hitec_session_next()

hitec_ses_kind_t hitec_session_next ( hitec_session_t * s,
uint32_t now,
hitec_ses_step_t * out )

The step to run at now.

A step stays out, and this call gives it again, until its result is fed. WAIT while the gap before the next transaction runs; DONE when no operation runs.

Parameters
sSession.
nowThe clock.
outReceives the step; NULL takes the kind only.
Returns
The step's hitec_ses_kind_t; DONE for a NULL session.

◆ hitec_session_read_all()

hitec_ses_t hitec_session_read_all ( hitec_session_t * s)

Read the series' full set: hitec_d_read_list() or hitec_c_read_ranges().

The image starts empty, the classic version kept. Addresses go in ascending order, each with HITEC_SES_TRIES tries; one that fails on every try ends the read, and the image keeps what was read before it.

Parameters
sSession.
Returns
HITEC_SES_BUSY when the read starts; HITEC_SES_ERR_BUSY, HITEC_SES_ERR_ARG, HITEC_SES_ERR_NOT_IN_MODE.

◆ hitec_session_read_set()

hitec_ses_t hitec_session_read_set ( hitec_session_t * s,
const uint8_t * addrs,
uint16_t n )

Read n addresses into the image, which keeps the rest.

As hitec_session_read_all(), in ascending order, each address once.

Parameters
sSession.
addrsCells, or even D series registers.
nCount, 1 to 256.
Returns
HITEC_SES_BUSY when the read starts; HITEC_SES_ERR_BUSY, HITEC_SES_ERR_ARG (NULL, n 0 or above 256, an odd D series register), HITEC_SES_ERR_NOT_IN_MODE.

◆ hitec_session_result()

hitec_ses_t hitec_session_result ( const hitec_session_t * s)

The running operation's state.

Parameters
sSession.
Returns
HITEC_SES_BUSY while an operation runs, else the last one's result; HITEC_SES_ERR_ARG for NULL.

◆ hitec_session_run_plan()

hitec_ses_t hitec_session_run_plan ( hitec_session_t * s,
const hitec_plan_t * plan,
const hitec_image_t * expect )

Run a plan the caller built, such as hitec_d_factory_plan(), then read back as hitec_session_write() does.

Parameters
sSession.
planThe plan, copied; steps of the session's series only.
expectThe image the read-back must hold, copied; NULL reads back and compares nothing.
Returns
As hitec_session_write(); HITEC_SES_ERR_PLAN for more than HITEC_PLAN_MAX steps, a step of the other series, a classic value above 255 or an odd D series register.

◆ hitec_session_write()

hitec_ses_t hitec_session_write ( hitec_session_t * s,
const hitec_image_t * target )

Write the servo from the image to target, then read it back.

The plan is hitec_plan(image, target), kept in plan. An empty plan ends with HITEC_SES_OK and sends nothing.

Classic: each cell and each balance (0x1C) as 62 cell value sum, with HITEC_SES_TRIES tries for its + +, HITEC_SES_C_GAP_MS apart. Then a read of cells 0x00 to 0x23.

D series: each write, the save and the reboot as a write frame with no answer, each followed by its plan wait (20ms, 100ms, 1000ms), at least HITEC_SES_D_GAP_MS. Then a read of the full set.

The read-back must hold every writable address (hitec_writable()) and the classic balance as target holds it, where target knows it; diff names the ones that differ. step_index counts the plan's writes that went out.

The image holds only what the servo confirmed. A classic write answered + + goes into it. A D series write has no answer and does not change it; the read-back puts the register there.

A write that ends with anything but HITEC_SES_OK once a plan step was handed out and its result fed (RAN, CUT or FAILED: a cut or lost step may have reached the servo) marks as not known (hitec_image_forget()) every address the servo may have changed and this write's read-back has not read: D series, every register of the full read and every register of the plan, since a save, a reboot or a factory reset may change registers the plan does not name; classic, the cell of a write whose last try got no + + (a cut or lost try included) and the balance 0x1C. hitec_plan() then refuses with HITEC_PLAN_ERR_UNKNOWN (HITEC_SES_ERR_PLAN): the caller reads the servo before it writes again. A write refused or aborted before a step's result was fed, and one whose read-back ended with HITEC_SES_ERR_VERIFY, forget nothing.

Parameters
sSession.
targetThe draft, copied.
Returns
HITEC_SES_BUSY when the write starts, HITEC_SES_OK for an empty plan; HITEC_SES_ERR_BUSY, HITEC_SES_ERR_ARG (NULL, a target of the other series), HITEC_SES_ERR_NOT_IN_MODE, HITEC_SES_ERR_PLAN.

◆ may_start()

hitec_ses_t may_start ( const hitec_session_t * s,
bool in_mode )
static

The common refusals of an operation.

Parameters
sSession.
in_modetrue when the operation needs a successful entry.
Returns
HITEC_SES_OK when it may start.

◆ plan_fits()

bool plan_fits ( const hitec_session_t * s,
const hitec_plan_t * plan )
static

True when every step of plan is one the session runs on its series.

Parameters
sSession.
planPlan.
Returns
true for a plan of the session's series.

◆ power_step()

void power_step ( const hitec_session_t * s,
hitec_ses_step_t * st,
uint32_t window_us,
bool answer )
static

A POWER step whose LISTEN waits window_us.

Parameters
sSession.
stReceives the step.
window_usThe LISTEN's window, us.
answertrue to answer the first byte with +.

◆ read_back()

bool read_back ( const hitec_session_t * s,
uint8_t addr )
static

True when the read-back of the running write has read addr.

Parameters
sSession.
addrAddress.
Returns
true for an address of the read-back's set it has read.

◆ read_took()

hitec_ses_t read_took ( hitec_session_t * s,
uint16_t value )
static

The read of s->addr took value: store it, then the next address or the operation's end. The gap is the one feed started.

Parameters
sSession.
valueThe decoded value.
Returns
HITEC_SES_BUSY, or the result the operation ends with.

◆ series_gap()

uint32_t series_gap ( const hitec_session_t * s)
static

The gap after a transaction of the session's series.

Parameters
sSession.
Returns
HITEC_SES_C_GAP_MS or HITEC_SES_D_GAP_MS.

◆ set_add()

void set_add ( uint8_t * set,
uint8_t addr )
static

Put addr into set.

Parameters
setAddress set.
addrAddress.

◆ set_count()

uint16_t set_count ( const uint8_t * set)
static

Addresses in set.

Parameters
setAddress set.
Returns
The count, 0 to 256.

◆ set_drop()

void set_drop ( uint8_t * set,
uint8_t addr )
static

Take addr out of set.

Parameters
setAddress set.
addrAddress.

◆ set_first()

bool set_first ( const uint8_t * set,
uint8_t * out )
static

The lowest address in set.

Parameters
setAddress set.
outReceives the address.
Returns
false for an empty set.

◆ set_full_read()

void set_full_read ( uint8_t series,
uint8_t * set )
static

Put the series' full read into set.

Parameters
serieshitec_family_t.
setAddress set, emptied first.

◆ start_plan()

hitec_ses_t start_plan ( hitec_session_t * s,
bool compare )
static

Start the plan in s->plan; the read-back compares with target when compare.

Parameters
sSession.
comparetrue to compare the read-back with target.
Returns
HITEC_SES_BUSY, or HITEC_SES_OK for an empty plan.

◆ step_gap()

uint32_t step_gap ( const hitec_session_t * s)
static

The wait the step that is out asks for once its result comes, whether it ran, was cut or was lost.

Parameters
sSession.
Returns
The plan step's wait or the series gap for a write, whichever is longer; HITEC_SES_D_ENTRY_WAIT_MS for the D series POWER; HITEC_D_REBOOT_WAIT_MS for the D series leave; the series gap for every other step.

◆ ticks()

uint32_t ticks ( const hitec_session_t * s,
uint32_t ms )
static

ms in ticks of the session's clock.

Parameters
sSession.
msTime, ms.
Returns
Ticks.

◆ write_took()

hitec_ses_t write_took ( hitec_session_t * s,
uint32_t now )
static

The write of plan.step[step_index] took: count it, start its wait, then the next write or the read-back.

A classic write answered + + goes into the image. A D series write has no answer and leaves the image alone: the read-back puts the value the servo holds there.

Parameters
sSession.
nowThe clock.
Returns
HITEC_SES_BUSY, or the result the operation ends with.