Open_XCP_Client is a lightweight, self-contained XCP on Ethernet (UDP/TCP) measurement recorder, real-time 2D/time-series visualizer, .sdf replay analyzer, and live calibration client engineered in Rust (egui/eframe + tokio).
It is purpose-built for embedded ADAS and automotive software integrating Vector xcplite 2.2.2 on POSIX/QNX targets (such as Qualcomm SoC platforms running QNX 7.1), where the ASAM MCD-2 MC (A2L) description file is generated dynamically during target initialization and uploaded over the network.
- System Overview
- Core Capabilities
- Getting Started
- Operator Workflow
- Configuration Reference (
settings.json) - Plot Profiles (Predefined, Reusable Measurement Views)
- SDF & MP4 File Naming Specification
- Codebase Architecture
- Documentation Suite
- Verification & Quality Assurance
flowchart LR
subgraph Target["Embedded ADAS Target (QNX 7.1 / SoC)"]
XCP["Vector xcplite 2.2.2 Server\n(UDP / TCP Port 5555)"]
A2LGen["Runtime A2L Generator"]
RAM["ECU Measurement & Calibration RAM"]
A2LGen --> XCP
RAM <--> XCP
end
subgraph Host["Developer Laptop (Open_XCP_Client)"]
Trans["Async XCP Transport\n(CTO Lockstep + DAQ Stream)"]
Parser["A2L Parser & C/C++ Struct Resolver"]
Planner["Event-Rate DAQ Planner &\nUTC Clock Correlator"]
SDF["Synchronized .sdf + .mp4 Recorder\n& Size Splitter (500 MB default)"]
Replay["Multi-Part .sdf Replay Engine"]
Cal["Type-Safe Live Calibration Engine"]
UI["5-Tab Desktop UI\n(2D Plot | Numerical | Time Plot | Calibration | XCP Info)"]
Trans --> Parser
Parser --> Planner
Parser --> Cal
Trans --> Planner
Planner --> SDF
Planner --> UI
Replay --> UI
UI <--> Cal
UI <--> SDF
Cal --> Trans
end
XCP <== "XCP on Ethernet (UDP/TCP)" ==> Trans
Known limitations (honest status, see
docs/TODO.md): the.mp4files are a proprietary RLE-compressed RGB frame stream in an MP4-like container and are not playable by standard players (T-01); the.sdffiles carry an HDF5 signature but are indexed by an embedded JSON tail and are not readable by h5py/HDFView (T-02); a recording part is held in memory until it is split or stopped (T-03). The project's own replay engine reads both formats.
Open_XCP_Client decouples network acquisition and disk I/O from the user interface thread:
- UI Thread (
eframe/egui): Renders the top navigation bar (Live/Replayswitcher, recording/replay controls,β Settingsbutton) and the 5 interactive tabs (2D Live Plot, Numerical, Time Plot, Calibration, XCP Info) with minimal CPU and memory overhead. - Async XCP & Recording Worker (
tokio): Manages socket communication, dynamic A2L upload, immediate live DAQ DTO packet demultiplexing, UTC timestamp correlation, synchronized.sdf+.mp4(RLE frame stream, see Known limitations) recording with lockstep file-size splitting, and concurrent calibrationSHORT_DOWNLOAD/DOWNLOADrequests.
- Automatically queries the running
xcplite2.2.2 server usingGET_ID (IDT_ASAM_UPLOAD = 4)followed by chunkedUPLOADtransfers to retrieve the target's A2L specification directly over Ethernet (with an optional local.a2lfile that is read only when the upload fails or is empty; the connect status says which source was used). - Reconstructs complex C/C++ data structures from both ASAM MCD-2 MC v1.7
TYPEDEF_STRUCTURE/STRUCTURE_COMPONENT/INSTANCEdeclarations and hierarchical symbol paths (e.g.,Perception.RadarFront.targets[0].distance_m), preserving all nested attributes and multidimensional (MATRIX_DIM) arrays. - Starts live DAQ streaming immediately on connect so all visualization and numerical tabs update in real time before recording to disk.
- Renders a zoomable, pannable 2D ground plane in ISO 8855 vehicle body coordinates (
+xforward/up,+yleft, origin(0, 0)at the rear-axle center) or standard Cartesian coordinates (+xright,+yup) with a zoom-adaptive1-2-5metric grid (0.1 m..50 m). - Configurable Ego Vehicle Footprint in
β Settings: parameterized by Ego Length (m) (default4.85 m), Ego Width (m) (default1.90 m), and Rear-Axle to Center (m) (default1.425 m). - Interactive
(X, Y)Signal Pair Builder with instant search filtering: pair anyXandYA2L signals regardless of whetherXandYare scalars or vectors (MATRIX_DIM) β supporting scalar-scalar, vector-vector, scalar-vector broadcast, optional valid-count truncation, and 4-corner polygon sets (P0..P3) acrossScatter,Connected Line,History Trail, and4-Corner Polygonstyles.
- Stores recordings by default in
./logfile/using matched part filenames:<Prefix>_<YYYY-MM-DD_HH-MM-SSZ>_PART001.sdf <Prefix>_<YYYY-MM-DD_HH-MM-SSZ>_PART001.mp4 - Records every complete DAQ cycle at its native event rate into
.sdfpart files (an HDF5-signature container with an embedded JSON index, readable by this client's replay engine; not by generic HDF5 tools yet, T-02) while simultaneously recording the 2D XY Plot offscreen as an.mp4-named RLE frame stream at a configurable frame rate (1..30 FPS, default10 FPS). The stream is not H.264 and standard players cannot open it (T-01). - Whenever either the
.sdflogfile or the.mp4video reaches the configured split threshold (default500 MBinβ Settings), both rotate in lockstep toPART002.sdfandPART002.mp4while preserving the original recording-start UTC timestamp.
- Switch the top bar from
π’ Livetoπ Replayto load a single.sdffile or an entire multi-part recording (PART001.sdf,PART002.sdf, ...) in chronological order. - Full playback transport bar with
βΆ Play/βΈ Pause,β Stop, Speed selector (0.25Γ,0.5Γ,1Γ,2Γ,5Γ,10Γ,max), and a continuous Time Slider with 5-second pre-roll seeking that drives the 2D Live Plot, Numerical, Time Plot, and XCP Info tabs identically to a live target.
- Numerical Tab (
Ctrl+2): Filterable expandable C/C++ structure tree displaying physical values,COMPU_VTABenum labels, array summaries, units, raw values, and a 1.0-second visual highlight on updated signals. - Time Plot Tab (
Ctrl+3): Filterable signal picker (up to 12 signals) paired with a 2-column strip-chart grid featuring configurable time windows (10 s,20 s,60 s,120 s), pointer wheel time-zoom (1..120 s), double-click reset, andFreeze. - Calibration Tab (
Ctrl+4): Searchable A2LCHARACTERISTICfinder and active Calibration Content watch-list table with strict data-type and[LowerLimit, UpperLimit]validation, transmitting updates to target memory onEnterconcurrently during DAQ streaming/recording. - XCP Info Tab (
Ctrl+5): Displays XCP connection metadata, A2L summary, and a live per-EVENTDAQ cycle-time telemetry table (Configured Cyclems, Measured Mean/Max Cyclems, Sample Count, Latest UTC Timestamp, Agems).
Executables for Windows (open_xcp_client.exe) and Linux (open_xcp_client) are compiled automatically by the Build & Release Binaries workflow. No ffmpeg or HDF5 library is required; the Linux binary links the system OpenGL / X11 / Wayland libraries dynamically. Only the Linux build is exercised by CI (T-19).
- Rust stable toolchain (
1.87+,rust-versioninCargo.toml) - On Linux (Ubuntu/Debian), install standard X11/Wayland/OpenGL development headers:
sudo apt-get update sudo apt-get install -y pkg-config libxkbcommon-dev libwayland-dev libx11-dev libxcursor-dev libxrandr-dev libxi-dev libgl1-mesa-dev
cargo build --releaseThe optimized executable is produced at target/release/open_xcp_client (or target\release\open_xcp_client.exe on Windows).
# Launch the desktop GUI (default)
./target/release/open_xcp_client
# Render one UI frame headlessly against the current settings (no A2L parsing or recording)
./target/release/open_xcp_client --headless-self-check
# Print version information
./target/release/open_xcp_client --version- Configure Target, Ego Vehicle & Recording Parameters (
β Settings):- Click
β Settingsin the top-right navigation bar. - Set Target IP Address, Target XCP Port (default
5555), and Transport Protocol (UDPorTCP). - Adjust Logfile / Video Split Size (MB) (default
500 MB), Video Frame Rate (FPS) (default10 FPS), and Ego Vehicle Geometry (Length,Width,Rear-Axle to Center,ISO 8855 Axes). - (Optional) Enable Built-in Mock XCPlite Server to test live streaming, plotting, video recording, and calibration locally without hardware.
- Click
πΎ Save Settings to JSON.
- Click
- Connect & Visualize Live Streams:
- Click
Connectin the top bar. Live DAQ streaming starts immediately across all 5 tabs (Ctrl+1..Ctrl+5). - In
π 2D Live Plot, filter A2L signals in the left sidebar, pair anyXandYscalar or vector signals, choose a draw style (Scatter,Connected Line,History Trail, or4-Corner Polygon), and clickβ Add (X, Y) Layer to 2D Plot.
- Click
- Record Synchronized
.sdf+.mp4Files:- Verify the output Folder, Name Prefix, and 2D Video (
.mp4) FPS in the top bar, then clickβΊ Start Recording (Ctrl+R). - Click
βΉ Stop Recording (Ctrl+R)when finished.
- Verify the output Folder, Name Prefix, and 2D Video (
- Replay
.sdfRecordings Offline:- Switch the top bar to
π Replay, enter a path to one or more.sdfpart files (or a directory containing.sdfparts), and clickπ Load .sdf. - Use
βΆ Play/βΈ Pause, Speed (0.25Γ..10Γ,max), and the Time Slider to scrub through the recording across all tabs.
- Switch the top bar to
Runtime settings are stored in ./config/settings.json (seeded from ./config/settings.default.json).
| JSON Path | Type | Default | Description |
|---|---|---|---|
connection.target_ip |
string |
"127.0.0.1" |
IPv4 address of the target running xcplite |
connection.target_port |
u16 |
5555 |
UDP/TCP port of the xcplite server |
connection.transport |
"Udp" | "Tcp" |
"Udp" |
XCP-on-Ethernet transport layer protocol |
connection.connect_timeout_ms |
u64 |
2000 |
Command response timeout in milliseconds |
connection.local_a2l_fallback_path |
string |
"" |
Optional local .a2l path, read only when the target upload fails or is empty |
recording.default_log_folder |
string |
"./logfile" |
Output directory for recorded .sdf and .mp4 files |
recording.default_file_prefix |
string |
"Measurement" |
Prefix used for <Prefix>_<UTC>_PARTxxx.{sdf,mp4} |
recording.max_logfile_size_mb |
u64 |
500 |
Maximum size per .sdf or .mp4 part file in megabytes |
recording.prefer_target_utc_clock |
bool |
true |
Prefer target real-time UTC clock (GET_DAQ_CLOCK) over host clock |
recording.record_video_mp4 |
bool |
true |
Record the offscreen 2D XY plot as an .mp4-named RLE frame stream alongside .sdf (not H.264, T-01) |
recording.video_fps |
u32 |
10 |
Video frame rate in Hz (1..=30) |
recording.video_encoder |
string |
"libx264" |
Reserved; stored but not used by the current recorder (T-01) |
visualization.ego.length_m |
f64 |
4.85 |
Ego vehicle length in meters |
visualization.ego.width_m |
f64 |
1.90 |
Ego vehicle width in meters |
visualization.ego.rear_axle_to_center_m |
f64 |
1.425 |
Longitudinal offset (+x) from rear axle (0, 0) to vehicle center (m) |
visualization.ego.show_ego |
bool |
true |
Render ego vehicle outline and rear-axle crosshair |
visualization.ego.iso8855_axes |
bool |
true |
Use ISO 8855 axes (+x up, +y left) |
visualization.xy_layers |
array |
[] |
Saved 2D (X, Y) signal pair layer configurations |
visualization.time_plot_signals |
string[] |
[] |
Selected signals in the Time Plot strip-chart grid |
visualization.time_plot_window_s |
f64 |
20.0 |
Rolling time window (1..120 s) for Time Plot strip charts |
calibration.watch_list |
string[] |
[] |
Saved list of CHARACTERISTIC names in Calibration Content |
calibration.verify_readback |
bool |
true |
Verify every calibration write via immediate SHORT_UPLOAD readback |
calibration.active_cal_page |
u8 |
0 |
Active ECU/XCP calibration page (0 = Reference, 1 = Working) |
ui.dark_mode |
bool |
true |
Enable dark engineering theme |
ui.enable_mock_server |
bool |
false |
Spawn built-in simulated QNX ADAS xcplite server on Connect |
active_profile |
string |
"" |
Name of the plot profile in ./config/profiles/ to re-apply on startup |
A plot profile stores one complete measurement view β the 2D (X, Y) layers, the Time Plot
selection and window, the Ego geometry, the 2D viewport framing and the calibration watch-list β
as a single JSON file in ./config/profiles/<Name>.json. Define a view once, reload it in the
next test session, or hand the file to a colleague.
The Plot Profiles section appears in β Settings and, as a collapsed π Plot Profiles
header, at the top of the 2D Live Plot and Time Plot sidebars:
πΎ Save Current View As Profileβ write the current view under a name you typeπ Load/π Update/π Deleteβ apply, overwrite or remove the selected profile‡ Import/‴ Exportβ read or write a profile at any path, for sharing
The last profile applied is remembered as active_profile in settings.json and re-applied
automatically on the next start. Profiles reference signals by A2L name only, so loading one
against a target whose A2L lacks some of those signals applies it anyway and flags the unresolved
names with β β they are never silently dropped.
Profile files are user data and are gitignored, so no project-specific view ships with the client.
See the Plot Profiles guide and
config/profiles/README.md for the full schema.
- Filename Patterns:
<Prefix>_<YYYY-MM-DD_HH-MM-SSZ>_PART<NNN>.sdf<Prefix>_<YYYY-MM-DD_HH-MM-SSZ>_PART<NNN>.mp4
- Internal
.sdfdataset paths (HDF5-style names resolved through the embeddedSDFIDX02JSON index; seedocs/sdf_file_format.md):/Events/<EventName>/time_utc_sβfloat64UTC epoch timestamp vector in seconds ([N])/Events/<EventName>/time_utc_nsβint64UTC epoch timestamp vector in nanoseconds ([N])/Measurements/<StructGroup>/<SubStruct>/<Field>βfloat64physical value dataset ([N]for scalars,[N, D...]for arrays).
Each source file in ./src/ is scoped to a single, well-defined responsibility:
| Module / Path | Scope & Responsibility |
|---|---|
src/main.rs |
Native eframe application bootstrap and --headless-self-check CLI entry point |
src/lib.rs |
Library root exporting all core subsystems |
src/config_store.rs |
JSON configuration persistence (./config/settings.json), Ego vehicle geometry, and XY layer schema |
src/plot_profile.rs |
Named, reusable plot profiles (./config/profiles/<Name>.json), atomic writes, and unresolved-signal detection |
src/app_state.rs |
Application state controller, rolling time-series buffers, and UI |
src/a2l/lexer.rs |
Zero-copy tokenizer for ASAM MCD-2 MC (A2L) files |
src/a2l/parser.rs |
Parser for EVENT, MEASUREMENT, CHARACTERISTIC, RECORD_LAYOUT, and TYPEDEF_* blocks |
src/a2l/struct_resolver.rs |
Recursive C/C++ structure (TYPEDEF_STRUCTURE / INSTANCE) and path tree builder |
src/a2l/compu_method.rs |
Physical IDENTICAL, LINEAR, RAT_FUNC, TAB_VERB) |
src/xcp/packet.rs |
XCP-on-Ethernet 4-byte header codec, CTO command builders, and DTO decoders |
src/xcp/transport.rs |
Async UDP/TCP socket multiplexer separating CTO responses from DAQ DTO streams |
src/xcp/daq_planner.rs |
Per-event DAQ list/ODT packer (respecting the 255-entry and 255-ODT u8 limits) and ODT-0-anchored DTO cycle assembler that discards torn samples |
src/xcp/link_stats.rs |
16-bit CTR continuity tracking: gap, reorder, duplicate and queue-overflow accounting |
src/xcp/clock_sync.rs |
Target GET_DAQ_CLOCK + 32-bit DTO timestamp rollover tracker and UTC correlator |
src/xcp/client.rs |
High-level XCP Master client (connect, A2L upload, DAQ control, concurrent calibration) |
src/recording/file_namer.rs |
UTC timestamp formatter and sequential .sdf / .mp4 part filename generator |
src/recording/size_splitter.rs |
Byte-budget tracker enforcing the configurable max_logfile_size_mb split threshold |
src/recording/sdf_writer.rs |
.sdf container writer (HDF5 signature + superblock, Jenkins lookup3 checksums, embedded JSON index) and the matching reader |
src/recording/video_recorder.rs |
Offscreen 2D XY plot rasterizer, (X, Y) signal pairing, and .mp4-named RLE frame-stream writer (not H.264, T-01) |
src/replay/mod.rs |
Multi-part .sdf recording replay engine with speed scaling and 5-second pre-roll seeking |
src/calibration/validator.rs |
Strict data-type syntax parser, A2L [LowerLimit, UpperLimit] checker, and raw byte encoder |
src/calibration/manager.rs |
Calibration Content watch-list state machine and Enter-key submission handler |
src/ui/axis_ticks.rs |
Zoom-adaptive 1-2-5 metric grid step and tick formatter |
src/ui/top_bar.rs |
Top navigation bar with Live/Replay switch, 5-tab selector, recording/replay bar, and β Settings button |
src/ui/settings_menu.rs |
Modal settings dialog for plot profiles, target endpoint, split size (MB), video options, and Ego vehicle dimensions |
src/ui/profile_panel.rs |
Reusable Plot Profiles selector (load/update/delete/save-as/import/export) and unresolved-signal warning |
src/ui/plane_plot_tab.rs |
Interactive 2D Live Plot canvas and filterable (X, Y) signal pair layer builder |
src/ui/numerical_tab.rs |
Filterable hierarchical numerical signal inspector with 1.0-second change highlighting |
src/ui/time_plot_tab.rs |
Filterable signal picker and 2-column rolling time-series strip-chart grid |
src/ui/calibration_tab.rs |
Calibration tab UI (parameter finder, active watch-list table, type-aware input fields) |
src/ui/xcp_info_tab.rs |
XCP target/A2L metadata and per-event DAQ cycle-time telemetry table |
src/mock_server/ |
Built-in Mock xcplite 2.2.2 UDP/TCP server and sample ADAS A2L generator |
tools/xcp_devtool/ |
Developer CLI and MCP server: A2L/SDF inspection, DAQ plan dry-run, mock server, target probe, project and invariant checks (see AGENTS.md) |
Detailed engineering documentation is located in ./docs/:
- Documentation Portal & Index
- System Architecture & Performance Optimization
- XCP on Ethernet Protocol & Vector
xcplite2.2.2 Integration - A2L Parsing & Complex C/C++ Structure Mapping
.sdfContainer &.mp4Frame-Stream Recording with Size Splitting- Calibration Guide & Data-Type Validation
- UI / UX Operator Manual (5 Tabs, 2D Plot & Replay)
- Plot Profiles β Predefined, Reusable Measurement Views
- CI/CD Pipelines, Release Packaging & Test Coverage
- Honest Assessment & Prioritised Backlog (
TODO.md)
Run formatting checks, static analysis, and the complete integration test suite:
# Check formatting
cargo fmt --all -- --check
# Run Clippy linter with warnings denied (whole workspace)
cargo clippy --workspace --all-targets -- -D warnings
# Run all integration tests (product crate) and the devtool tests
cargo test --workspace
# Repository invariants and a DAQ plan dry-run on the built-in sample A2L
cargo run -q -p xcp_devtool -- invariants-check
cargo run -q -p xcp_devtool -- daq-plan-dryrun --builtin adas_sample --max-dto 256Agent-assisted development is described in AGENTS.md.