Channels and Series
How Arc connects to Synnax telemetry through channels and handles array data with series
Channels are Arc’s connection to Synnax telemetry data. They let you read sensor values, write to actuators, and respond to operator inputs. Series are arrays of values, useful for batch processing and aggregation.
Channels
A channel in Arc references a channel that exists in your Synnax cluster. You don’t declare channels. Just use them by name:
// Read from a pressure transducer and scale it into another channel
tank_pressure -> scale{factor=2.0} -> pressure_scaled
// Write a fixed value to a valve command
1 -> valve_cmdChannel names follow the same conventions as Synnax channels: start with a letter or
underscore, then letters, digits, or underscores. Examples: tank_pressure,
inlet_temp, start_btn.
Channel Discovery
The Arc text editor provides autocomplete for channels in your cluster. As you type, matching channel names appear with their data types. You can also browse available channels in the Console’s resources panel before writing code.
Reading Channels
Channels behave differently depending on whether you’re in a reactive context (flow statements) or an imperative context (inside a function body).
In flow statements, channels are event-driven data sources:
sensor -> controller{} -> actuatorWhen new data arrives on sensor, the entire pipeline executes.
Inside function bodies, channel reads are non-blocking snapshots:
func controller{setpoint chan f64} (pressure f64) f64 {
error := pressure - setpoint // Read latest value (non-blocking)
return error
}You can also bind a channel, or an expression over channels, to a variable that updates as new data arrives.
Channels as Inputs
Channels can be passed to functions as input parameters:
func monitor{sensor chan f64, limit f64} () u8 {
return sensor > limit
}
// Wire it up on a 50ms cadence
time.interval{period=50ms} -> monitor{sensor=tank_pressure, limit=500.0} -> pressure_highThis lets you write reusable functions that work with different channels.
Writing to Channels
Write to a channel by making it the final target of a flow statement, or with assignment syntax inside a function.
stage control {
sensor -> scale{factor=2.0} -> output_channel
}func control{valve chan u8} (pressure f64) {
if pressure > 500 { valve = 1 }
}Writes are queued until the end of the execution cycle. Multiple writes to the same channel in a single cycle result in the last value being sent.
Series
Series are homogeneous arrays of values. They’re useful for batch operations and working with buffered data.
Creating Series
// Literal
data := [1.0, 2.0, 3.0]
// Empty (requires type annotation)
buffer series f64 := []Indexing and Slicing
data := [10.0, 20.0, 30.0, 40.0]
first := data[0] // 10.0
last := data[3] // 40.0
middle := data[1: 3] // [20.0, 30.0]Out-of-bounds access causes a runtime error.
Series Length
data := [1.0, 2.0, 3.0]
count := len(data) // 3 (i64)Element-wise Operations
Arithmetic and comparison operators work element-wise on series:
data := [1.0, 2.0, 3.0]
// Scalar operations (broadcast)
scaled := data * 2.0 // [2.0, 4.0, 6.0]
offset := data + 10.0 // [11.0, 12.0, 13.0]
// Series operations (must be equal length)
other := [4.0, 5.0, 6.0]
sum := data + other // [5.0, 7.0, 9.0]
// Comparisons return series u8
mask := data > 2.0 // [0, 0, 1]Binary operations between two series require them to have equal length. Mismatched lengths cause a runtime error.
Channel Types
When passing channels as input parameters, you declare their type:
func process{input chan f64, output chan f64} () {
// ...
}The type system ensures you don’t accidentally connect incompatible channels. If you try
to read an f64 channel and use it where an i32 is expected, the compiler will catch
it.