Reference
Project format (YAML)
A project is one YAML file, optionally split with includes:. Paths are relative to the project file. The JSON Schema (arnodiqa schema, also in docs/arnodiqa.schema.json) gives autocomplete and validation in VS Code through the first line of the file. This is the actual demo project:
# yaml-language-server: $schema=../../docs/arnodiqa.schema.json # # Arnodiqa demo project: two virtual CAN channels with a remaining bus # simulation built from the databases (every database node runs the CAN # interaction layer), so it runs without hardware: # # arnodiqa run examples/demo/demo.yaml --simulated --duration 10s # version: 21 name: Demo description: PowerTrain (CAN FD) and Comfort (CAN) on virtual networks. includes:2 system_variables: sysvars.yaml networks:3 - name: PowerTrain channel: 1 bus: can_fd4 bitrate: 500000 data_bitrate: 2000000 hardware:5 virtual: network: vcan1 databases:6 - powertrain.dbc - name: Comfort channel: 2 bitrate: 500000 hardware: virtual: network: vcan2 databases: - comfort.dbc measurement:7 working_mode: simulated_bus duration: 10s measurement_setup:8 blocks: - logging: id: Logging file: logs/{ConfigName}_{MeasurementIndex}.blf9 - filter: id: PowerTrainOnly action: pass rules: - channels: [1] # Fires on the first EngineData frame with EngineSpeed = 800 rpm (the # database start value); later ones are ignored while the block is open. - trigger: id: HighRpm input: PowerTrainOnly10 mode: single pre_trigger: 50ms11 post_trigger: 200ms conditions: - event: signal: message: EngineData signal: EngineSpeed op: '==' value: 800 max_triggers: 1 - logging: id: HighRpmLog input: HighRpm file: logs/high_rpm_{IncMeasurement}.asc - view: id: Trace kind: trace - view: id: Statistics kind: statistics simulation:12 # All nodes of both databases become IL nodes. To test a real ECU, list it # under `exclude` (e.g. `exclude: [ECM]`) and connect the hardware. restbus: il: counters: - message: EngineData signal: AliveCounter
versionis the format version (currently 2). Older projects are migrated automatically; newer ones are rejected with an error message.includesmoves a section (here the system variables) into its own file, so teams get fewer merge conflicts.networksholds one network per application channel (channel: 1= CAN1), with name and bitrate.bus: can_fdgoes withdata_bitrate. Optional fields aresample_point,fd_mode: iso|non_isoandlisten_only.hardwareis the channel mapping:virtual(a named virtual network), a backend-specific form such aspcan,vector,kvaser,socketcan,slcanorgs_usb(seearnodiqa hw list), or the generic formdevice. In simulated bus mode, all networks are virtual regardless of the mapping.databaseslists the DBC files for decoding, triggers on signal values and the interaction layer.measurementholdsmode: online|offline,working_mode: real_bus|simulated_bus,duration, event sorting, offline sources and pacing.measurement_setup.blocksdescribes the analysis data flow; see Measurement Setup.- File names can contain field codes. A block without
inputis attached tosource(all events). inputchains blocks, or merges several when it holds a list of ids.- Durations are written as
50ms,1.5s,2min(units ns, us, ms, s, min, h, d). simulation.restbusconfigures the rest-bus simulation. Every node from the databases becomes an interaction layer node that sends its messages according to the send types and cycle times in the DBC. Useexclude: [ECM]to leave out a node and test a real ECU;il.countersdefines alive counters. Further options aresimulation.nodesfor individual nodes, for example a CAPL program (kind: capl,file: capl/gateway.can), and replay blocks. Panels are listed underpanels:as YAML files.
Value types
| Type | Notation |
|---|---|
| TimeSpan | 250ms, 1.5s, 10s, 2min; bare number = milliseconds |
| FrameId | "0x123" (standard), "0x18FEF100x" (extended), or an integer (extended if > 0x7FF) |
| SysVar types | int32 uint32 int64 uint64 float string data int_array float_array |
Measurement Setup
The measurement setup is a tree (DAG) of function blocks rooted in the measurement source (source). Branches run in parallel. A block with several inputs merges them in time order and passes an event that arrives via two branches only once. The demo project as a graph:
Block types
| Block | Purpose | Key fields |
|---|---|---|
filter | Pass or stop filter. An event matches when any rule matches (OR); within a rule, all criteria must match (AND). When disabled, everything passes. | action: pass|stop, rules: [{channels, ids, id_ranges, messages, directions, event_types, signal}], enabled |
trigger | Passes data only around trigger moments, with pre-trigger and post-trigger. | mode: single|toggle|entire_measurement, conditions (start, stop, event, sysvar), pre_trigger, post_trigger, max_triggers, retrigger: ignore|extend, stop_measurement, buffer_size |
logging | Writes BLF or ASC in its own thread; can contain its own trigger. | file (field codes), format: blf|asc, compression 0-9, asc_decimals: 6|9, max_file_size, max_file_duration, log_sysvars, trigger, queue_capacity |
view | Output to a window; carries exactly what the window receives. | kind: trace|data|graphics|statistics |
break | Blocks everything downstream (to disable a branch temporarily). | id, input |
All blocks have id, input (default source, or a list to merge) and comment.
Field codes
File names of logging blocks accept these field codes:
{MeasurementStart} {MeasurementIndex} {IncMeasurement} {IncTrigger} {IncSize} {IncTime} {LoggingBlock} {ConfigName} {TriggerCondition} {@NS::Var}.
Overload
In real time, the measurement never waits. Full queues are counted (mainQueueDropped, lost) and yield exit code 5. In simulated or offline mode ("as fast as possible"), producers wait and nothing is lost. UI subscriptions always drop the oldest events and count them.
Architecture
See How it works for the diagram. In short, the product consists of Rust crates (bf-core, bf-hw, bf-db, bf-log, bf-project, bf-engine, bf-cli, bf-diag, bf-test, the script VM) and a Tauri/React application that communicates with the engine only through the Session facade.
IPC contract (UI ↔ engine)
| Command | Result |
|---|---|
load_project(path) | ProjectInfo (networks, messages + signals, blocks) |
start_measurement / stop_measurement | () / MeasurementReport |
measurement_status | state, time, load 0..1, stopRequested |
pause / resume / step(size) | simulated bus and offline |
transmit(req) | Interactive Generator: channel, id, data, fd, brs |
subscribe_events(tap, interval, capacity) | binary batches every 16 to 33 ms, drop-oldest with counter |
statistics / block_statistics(id) | StatisticsSnapshot |
sysvars / set_sysvar | SysVarInfo[] / bool |
messages / subscribe_messages | messages for the Write window |
JSON fields are camelCase, times are nanoseconds since measurement start (i64), CAN IDs are strings ("0x123", "0x18FEF100x").