Skip to content

Configure the HAL contract

A HAL-backed prompt turns one rising-edge request into one queued operator interaction. Its declared pins form a small machine-facing contract: readable pins supply a snapshot, and writable pins report the selected action.

The producer must use this sequence:

  1. Keep the trigger low while preparing a request.
  2. Set every value pin used by the prompt.
  3. Raise the trigger. The broker captures the values and queues the prompt.
  4. Keep the trigger high while waiting for a result.
  5. Read the action result after the operator responds.
  6. Lower the trigger. The broker acknowledges the request and resets its writable pins.

The rising edge, not the high level, submits the request. A new prompt can be submitted only after the trigger has fallen and rises again.

If the trigger falls while the request is queued or active, the request is cancelled and released. If it falls after an answer, the completed result is released. In both cases the declared reset behavior is applied.

Each pin has a direction and a type:

Property Values
direction in, out, or io, from the ctrl_prompt component’s point of view.
type bit, s32, u32, or float.

The optional properties are restricted by direction:

Pin property Where allowed Behavior
trigger: rising Readable bit pin Marks the request trigger. Exactly one is required for a HAL-backed prompt.
variable in or io Exposes the captured value to prompt content.
on_action out or io Maps declared action IDs to values written after an answer.
initial out or io Sets a writable value when the component starts.
reset out or io Sets a writable value when the trigger falls.

An io pin can be both a captured variable and an action result, but shared ownership must be intentional. Prefer separate in and out pins when that makes the machine sequence easier to reason about.

One action can update several output pins, and one output pin can map several actions:

prompts:
recovery:
# ...
hal:
pins:
show:
direction: in
type: bit
trigger: rising
accepted:
direction: out
type: bit
on_action:
continue: true
result-code:
direction: out
type: s32
on_action:
continue: 1
retry: 2
stop: 3
reset: 0
actions:
- id: continue
label: Continue
intent: primary
- id: retry
label: Retry
intent: secondary
- id: stop
label: Stop
intent: danger

Every mapped key must match a declared action ID. Selecting an action changes only pins that map that action; other writable values keep their current value until release.

An abort is not an action. It never applies on_action, even when a mapping uses an ID that looks like an abort command.

For an out pin:

  • without initial, startup uses the type’s zero value;
  • without reset, release returns it to the type’s zero value; and
  • explicit initial and reset replace those defaults.

The zero values are false, 0, 0, and 0.0 for bit, s32, u32, and float respectively.

For an io pin, the broker writes at startup only when initial is present and writes at release only when reset is present. Otherwise it leaves the shared value untouched at that lifecycle point.

Values in initial, reset, and on_action must match the pin type:

  • bit accepts only true or false;
  • s32 accepts integers from -2147483648 through 2147483647;
  • u32 accepts integers from 0 through 4294967295; and
  • float accepts finite numbers.

The top-level component, configured prompt instance, and declared pin form each qualified HAL name:

component.instance.pin

Prompt instance names, template names, and action IDs may contain letters, numbers, ., _, :, and -, but must begin with a letter or number. HAL component and pin names do not allow :.

A complete HAL pin name may not exceed 47 characters. The broker checks the fully qualified name at startup, so include the component and instance prefixes when planning names.

The broker displays one prompt at a time and queues additional requests in submission order. A queued HAL request still owns its frozen snapshot, so keep its trigger high until it is answered or deliberately cancelled.

Do not infer that a prompt is visible merely because its trigger is high. Machine logic should wait for the mapped result, not for a fixed display delay. If a request must expire, implement the timeout and falling-trigger cancellation deliberately in the owning machine sequence.