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:

examples/demo/demo.yaml
# 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
  1. version is the format version (currently 2). Older projects are migrated automatically; newer ones are rejected with an error message.
  2. includes moves a section (here the system variables) into its own file, so teams get fewer merge conflicts.
  3. networks holds one network per application channel (channel: 1 = CAN1), with name and bitrate.
  4. bus: can_fd goes with data_bitrate. Optional fields are sample_point, fd_mode: iso|non_iso and listen_only.
  5. hardware is the channel mapping: virtual (a named virtual network), a backend-specific form such as pcan, vector, kvaser, socketcan, slcan or gs_usb (see arnodiqa hw list), or the generic form device. In simulated bus mode, all networks are virtual regardless of the mapping.
  6. databases lists the DBC files for decoding, triggers on signal values and the interaction layer.
  7. measurement holds mode: online|offline, working_mode: real_bus|simulated_bus, duration, event sorting, offline sources and pacing.
  8. measurement_setup.blocks describes the analysis data flow; see Measurement Setup.
  9. File names can contain field codes. A block without input is attached to source (all events).
  10. input chains blocks, or merges several when it holds a list of ids.
  11. Durations are written as 50ms, 1.5s, 2min (units ns, us, ms, s, min, h, d).
  12. simulation.restbus configures 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. Use exclude: [ECM] to leave out a node and test a real ECU; il.counters defines alive counters. Further options are simulation.nodes for individual nodes, for example a CAPL program (kind: capl, file: capl/gateway.can), and replay blocks. Panels are listed under panels: as YAML files.

Value types

TypeNotation
TimeSpan250ms, 1.5s, 10s, 2min; bare number = milliseconds
FrameId"0x123" (standard), "0x18FEF100x" (extended), or an integer (extended if > 0x7FF)
SysVar typesint32 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:

Measurement setup of the demo project Source feeds four branches: the Logging block writing all events to a BLF file; the PowerTrainOnly filter passing channel 1, then the HighRpm trigger on EngineSpeed equals 800 with 50 ms pre-trigger and 200 ms post-trigger, then the HighRpmLog block writing an ASC file; the Trace view; and the Statistics view. source logging · Logginglogs/{ConfigName}_{…}.blf filter · passPowerTrainOnly · ch 1 trigger · singleEngineSpeed == 800 logging · HighRpmLoghigh_rpm_{IncMeas.}.asc pre 50 ms · post 200 ms · max 1 view · Trace view · Statistics

Block types

BlockPurposeKey fields
filterPass 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
triggerPasses 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
loggingWrites 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
viewOutput to a window; carries exactly what the window receives.kind: trace|data|graphics|statistics
breakBlocks 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)

CommandResult
load_project(path)ProjectInfo (networks, messages + signals, blocks)
start_measurement / stop_measurement() / MeasurementReport
measurement_statusstate, 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_sysvarSysVarInfo[] / bool
messages / subscribe_messagesmessages for the Write window

JSON fields are camelCase, times are nanoseconds since measurement start (i64), CAN IDs are strings ("0x123", "0x18FEF100x").