Stellar ControlMission control · by Stellar Systems v0.1.0

Procedure Language

Statement Reference

The grammar and the behaviour of every statement of steps and procedures.

This page is the reference of every line of a .proc file: the declarations, the statements of a step and the actions of a procedure. Square brackets mark optional parts, … a repetition. Durations are literals with a time unit (500 ms, 10 s, 3 min, 1 h); conditions are boolean expressions (see Expressions, Types and Units).

Summary#

LineWhereGrammar
steptop level, procedurestep ["<name>"] [retry …]
proceduretop levelprocedure "<name>"
descriptionstep, proceduredescription "<text>"
usesstep, procedureuses <role>: <platform>
inputstep, procedureinput <name>: <type>
allowed inprocedureallowed in <environment>[, …]
sendstepsend <telecommand> to <target> [with <arg> = <value>[, …]] [via <link>]
expectstepexpect <condition> within <duration>
checkstepcheck <condition>
logsteplog <value> or log "<text with {values}>"
askstepask operator "<question>" [as <type> into <name>]
waitstepwait <duration>
wait untilstepwait until <condition> within <duration>
downloadstepdownload <role>.files[<file id input>]
uploadstepupload <file input> to <role>.files[<file id input>]
configurestepconfigure <role> for <mode>
doproceduredo "<step>" [with <param>[ = <value>][, …]] [retry …]
runprocedurerun "<procedure>" [with <param>[ = <value>][, …]] [retry …]
if failedprocedureif failed, then an indented block of actions

retry is retry [<N> times] [every <duration>] [for <duration>], with a count, a total duration or both; see Retries.

Declarations#

step and procedure#

text
step "TCU answers" retry 3 times every 2 s
  uses sat: platform-v3
  input tcu: tcu_id
  send ping to sat.tcu[tcu] via direct
  expect sat.tcu[tcu].responding is true within 5 s

A step or a procedure needs an indented body. A library step has a name; an inline step in a procedure may have one or not (an unnamed inline step appears as #<n> in the run log, its rank among the inline steps of the procedure). Procedures cannot be nested: a procedure calls another with run.

uses and input#

text
uses psu: lab-psu
input bus_voltage: f32 V
input tcu: tcu_id
input lttm: file_id of lttm
input patch: file

See Roles and inputs and Input types.

allowed in#

text
allowed in AIT, IVV

The environments of the topology where the procedure may run; each must exist (procedure::unknown-environment). Without allowed in, the procedure may run in every environment. A run in another environment is refused at launch (run::not-allowed). A dry run ignores it.

Statements of a step#

The statements of a step run in order; the first that fails stops the step. The executor checks between statements whether an operator asked to suspend or abort the run.

send#

text
send <telecommand> to <target> [with <arg> = <value>, …] [via <link>]
text
send ping to sat.tcu[tcu] via direct
send set_voltage to psu with voltage = bus_voltage
send set_mode to sat.tcu[TCU1] with mode = SAFE_MODE
send delete_file to sat.files[lttm]
  • The target is always given: a role (single-component platform) or a component with its instance. The telecommand must belong to that component (procedure::unknown-telecommand).
  • Arguments are always named. Each value is checked against the type, unit and range of the argument (procedure::type-mismatch, procedure::out-of-range for a literal out of its range); an argument without default must be given (procedure::missing-argument), an unknown or repeated one is refused. Values from inputs are checked when the run request is resolved. Enum values are written bare (mode = SAFE_MODE).
  • via <link> sends through a link of the target other than its default one. The link name is checked against the target when the run request is resolved (run::unknown-link), and the link must carry the component (run::link-component).

At run time, the executor logs telecommand_sent with the identifier of the telecommand before it leaves, then follows its acknowledgement chain: requires, ACK 1 (driver), ACK 2 (gateway), ACK 3 (verify). The statement succeeds when the telecommand ends VERIFIED or COMPLETE, and fails on any other final state. The end of the chain is logged as telecommand_finished, with every acknowledgement.

A send of a hazardous telecommand needs a confirmation first; see Safety Rules.

expect#

text
expect <condition> within <duration>
text
expect sat.tcu[tcu].responding is true within 5 s
expect sat.files[lttm].transfer is PROCESSED within 8 min

Waits until the condition holds on samples received after the last SENT of the step, or after the start of the step when it has sent nothing. A value that was already true before the telecommand never satisfies an expect. Samples received while the send was still waiting for its verification count: the executor reads them back from the PARAMS stream from SENT on. A measure produced once, such as the reply to ping, therefore satisfies the expect that follows.

within is mandatory (procedure::missing-timeout). The statement fails when the window ends first. The samples judged are logged as evidence in a checked event.

check#

text
check <condition>
text
check sat.tcu[tcu].mode is mode
check sat.files[lttm].transfer is PROCESSED

Evaluates the condition once, on the current values. Each measure read must be fresh: its last sample must be younger than the max_age of the measure in the catalogue, measured from its ground reception time. A missing or stale value fails the check. The samples used are logged as evidence.

The current values are never older than what the run already judged: after an expect or a wait until, a check or a log reads, for each component they judged, values at least as recent as the newest sample they saw (waiting up to 2 s for the current value table to catch up). A check right after expect psu.voltage is 28 V +/- 0.5 V within 5 s thus sees that sample, not the one before.

log#

text
log <value>
log "<text with {value} …>"
text
log sat.tcu[tcu].anode_voltage
log param sat.tcu[tcu].anode_voltage in Nominal
log "TCU1 at {sat.tcu[TCU1].anode_voltage} in {sat.tcu[TCU1].mode}"
log "Bus {psu.voltage}, threshold {{5 V}}"

Writes values in the log of the run, where they appear in the report, the web console, stellar watch and the API client, without judging them: the value of a measure, a derived measure, a parameter (param …), an input or any expression of them (psu.voltage * 2, sat.tcu[tcu].anode_voltage > 5 V).

  • log <value> writes the expression as in the procedure, then its value: sat.tcu[tcu].anode_voltage = 248.7 V.
  • log "<text>" writes the text, each {expression} replaced by its value: TCU1 at 248.7 V in STANDBY. {{ and }} write a brace.
  • Numbers keep six significant digits at most and their unit; booleans are true or false, enum values as declared.
  • The expressions are checked when the procedure is compiled, like those of check: an unknown measure or a unit mismatch is an error; temporal functions are refused. A malformed text is procedure::log-template (a { not closed, a } alone, an empty {}).
  • The values are read when the statement runs, on the current values. log never fails: a value that cannot be computed (no sample yet) is written unknown, one computed from a sample older than the max_age of its measure is followed by (stale).
  • It sends nothing, lasts zero and leaves the step eligible for automatic retries.

The event of the run is logged, with the text written and the samples read (value, on-board and ground times), shown in the report like the evidence of a check.

ask#

text
ask operator "<question>"
ask operator "<question>" as <type> into <name>
text
ask operator "Fire the blank on the TCU?"
ask operator "Voltage read on the bench multimeter?" as f32 V into measured
check psu.voltage is measured +/- 0.5 V
  • Confirmation. Without as … into, the operator answers yes or no; no fails the step.
  • Typed answer. With as <type> into <name>, the operator answers a value of that type (unit and enum included); the answer is then a name of the step, usable in the statements that follow. as and into go together.
  • Only operator is asked: who actually confirms is set by the environment, not by the text (hazardous_confirmation, see Hazardous Confirmations).
  • Without human orchestration in the environment, a confirmation is acknowledged automatically and logged as such; a typed answer then fails the step, since no operator is expected.

The run waits for the answer; stellar status shows the question, and stellar answer answers it. See Questions, Decisions and Control.

wait#

text
wait <duration>
wait until <condition> within <duration>
text
wait 5 s
wait until psu.output_enabled is true within 10 s

wait 5 s waits for a duration. wait until waits until a condition holds, starting from the current values: unlike expect, it does not require a sample received after a telecommand. Its timeout is mandatory and fails the step when it expires.

download#

text
download <role>.files[<file id input>]
text
download sat.files[lttm]
expect sat.files[lttm].transfer is PROCESSED within 8 min

Creates the download of the current generation of the file, as last listed, with the run as requester (run <id>), and goes on at once: the transfer continues on its own, pass after pass. Wait for it with expect on the transfer measure of the file. The platform must declare a transfer protocol (procedure::transfer-unavailable). See File Transfers.

upload#

text
upload <file input> to <role>.files[<file id input>]
text
upload patch to sat.files[slot]
expect sat.files[slot].transfer is VERIFIED within 30 min

Creates the upload of a content given at launch, an input of type file (the SHA-256 of a content stored with stellar put), and goes on at once. The platform must declare a write telecommand or CFDP. An upload never activates what it writes: activation is a telecommand of its own.

configure#

text
configure <role> for <mode>
text
step "Configure survival"
  configure sat for Survival

Applies a mode to the target of the role: it sets every parameter of the platform that has a set to its value in the mode, reads back those that have a readback, and records the mode as the current mode of the target. The compiler expands it from the catalogue of the platform of the role:

  1. for each telecommand that sets parameters, in the order of the catalogue, and for each instance of its component in the order of the enum of its instances, a send whose parameter arguments are param <role>.<component>[<instance>].<parameter> in <mode> (its other arguments keep their default);
  2. after each send, for each of its parameters with a readback, an expect <readback> is <value> [+/- <tolerance>] within <window>, the window being the longest within of the verifications of the setter, 10 s without one;
  3. at the end, the current mode of the target becomes <mode>, and the run logs mode_changed.

The first failure stops the step, like any statement, and the mode is not recorded. Each send is logged as usual (telecommand_sent, telecommand_finished) and each readback as a checked event.

  • The mode must be declared in the topology (procedure::unknown-mode), and the platform must have at least one parameter with a set (procedure::nothing-to-configure).
  • The sends follow the rules of send: a hazardous setter needs its ask operator before the configure in the same step, one per hazardous send; a setter with changes_state: true (the default) makes the step ineligible for retries. See Safety Rules.
  • At the resolution of the run, the target must have a value of each parameter in the mode (run::parameter-undefined).

Actions of a procedure#

do and run#

text
do "<step>" [with <param>[ = <value>], …] [retry …]
run "<procedure>" [with <param>[ = <value>], …] [retry …]
text
do "TCU answers" with sat, tcu
do "TCU in mode" with sat, tcu, mode = expected_mode
do "TCU answers" with sat, tcu retry every 5 s for 3 min
run "Check TCU" with sat, tcu, expected_mode = STANDBY

do calls a step of the library, run a procedure of the library (procedure::unknown-step, procedure::unknown-procedure; the help says when the name is the other kind).

Every role and every input of the callee receives:

  • the explicit value written after =: for a role, a role of the caller; for an input, an expression of the caller (input, answer, literal, enum value);
  • otherwise, the role or input of the same name of the caller. Listing the name alone (with sat, tcu) documents it; leaving it out has the same effect.

A parameter left without value is an error (procedure::missing-argument); an unknown one too (procedure::unknown-parameter). A role passed must be of the same platform (procedure::role-mismatch). A file_id input takes a file_id input of the same file type, a file input another file input.

A call succeeds when the step, or every action of the sub-procedure, succeeds. A retry on the call overrides the policy of the step; on a run, it replays the whole sub-procedure. See Retries.

Inline steps#

text
procedure "Safe TCU"
  uses sat: platform-v3
  input tcu: tcu_id

  step "Command safe mode"
    send safe_mode to sat.tcu[tcu]
    expect sat.tcu[tcu].mode is SAFE_MODE within 10 s

An inline step is written where it runs, for a one-off action. It inherits the roles and inputs of its procedure and declares none; it may have a description and a retry on its step line.

if failed#

text
  run "Check TCU" with sat, tcu, expected_mode = STANDBY

  if failed
    run "Safe TCU" with sat, tcu

The actions of a procedure run in order. When one fails:

  1. the following actions are skipped, up to the next if failed block;
  2. that block runs, its actions in order;
  3. the procedure stops there and is failed, even if the block succeeds: if failed handles the failure, it does not cancel it.

Without a failure, if failed blocks are skipped. An if failed block contains actions only: do, run and inline steps; no declaration (procedure::misplaced). A failure with no if failed block after it fails the procedure at once. An abort by an operator ends the run without running any if failed block.

A sub-procedure that fails makes its run fail in the caller, whose own if failed block then applies.

Execution order at a glance#

flowchart TD
    A[Action] -->|succeeds| B[Next action]
    A -->|fails| C{"if failed block<br/>further on?"}
    C -->|yes| D[Run the block] --> E[Procedure failed]
    C -->|no| E
    B -->|no more actions| F[Procedure succeeded]

Stellar Control · v0.1.0

↑↓ to moveEnter to open