A channel calculation derives a numeric value from other channels. It runs as part of the channel update path, so use it for conversions and immediate reactions that must not wait for a periodic task.
Derive a value
This example updates a percentage whenever either input changes. Create the two input channels first and use the same units for both.
channel_calculation docs_demo_level_percent:
local capacity = |docs_demo_capacity|
if capacity <= 0:
return 0
return clamp((|docs_demo_level| / capacity) * 100, 0, 100)Here, zero capacity produces zero as an explicit fallback. In a real controller, choose an appropriate invalid-input policy and report the fault separately; a plausible numeric fallback should not hide a failed sensor.
When it runs
| Update | Calculation behavior |
|---|---|
| A write to the calculation’s target | Runs the attached calculation before committing the target value. |
| A write to an input dependency | Commits that input, then runs dependent calculations inline before the original write returns. |
| A display refresh or telemetry packet | Does not schedule the local calculation; publication happens separately. |
This is a synchronous dependency chain, not a polling loop. A hardware driver still determines when a measurement enters RAPID and when an output reaches the device. Keep inline work short; slow calculations also delay the writer. In a prepared periodic path, that is an explicit inline dependency: its wait and execution time are charged to the triggering task rather than hidden in telemetry or a background worker. See Execution and Timing and Deterministic Automation.
For a task’s fixed-channel transaction, target transformations run while outputs are staged. Accepted numeric writes then commit as a generation. Dependency reactions run after that commit, and a calculation reached by multiple writes in the same generation is evaluated once for that generation. Separate generations can evaluate it again. This preserves completed producer batches; it does not impose an order on independent producer tasks.
A denied fixed numeric write does not publish a successful value notification or trigger dependency calculations. Other accepted writes in the batch still commit. Authority operations and arbitrary task state are not rolled back with staged values.
The engine prepares target and dependency lookup lists, event-trigger lookups, and attribution text at activation. Each executing callback retains its selected list. Local numeric fixed outputs can reuse the originating task’s publication buffers while their inline chain runs. These changes reduce allocation while preserving immediate results and evaluation order. Calculation execution still uses synchronization; a busy publication pool or large dependency list can allocate, and event handling still has runtime work. Compiling a calculation does not establish a timing bound for its complete chain.
Calculations are not CAESAR tasks and have no running, hold, or frequency controls.
Dependencies
The first example also fits the Native C++ subset. The dynamic-name example below requires Lua; native files use static value pipes and cannot construct channel names at runtime.
Static pipe reads in the body automatically become dependencies. Assignment targets are outputs. An explicit list can add dependencies:
channel_calculation docs_demo_selected_pressure:
depends_on: docs_demo_left_pressure, docs_demo_right_pressure
local side = "left"
return |docs_demo_{side}_pressure|Dynamic references are resolved at runtime and are not discovered as static inputs. List every channel that should cause reevaluation, including any selection channel. Entries in depends_on are channel keys, without pipe delimiters or metadata-field suffixes.
Errors and cycles
Return a number. A failed calculation or nonnumeric result leaves the existing value unchanged and records an error; a displayed old value is not proof that the latest calculation succeeded.
Keep dependencies one-way. If a chain would reenter a calculation already executing, DCode logs a cycle error and leaves that calculation’s current value unchanged. Make one channel the source of truth, or use a periodic task when the intended behavior depends on previous iterations.