Skip to content

About

Run and test embedded Linux applications on your host as if GPIO, SPI, I2C, UART, QSPI, and Ethernet devices were physically connected.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

144 Commits

Folders and files

Repository files navigation

Virtual Device Simulator for Embedded (VDS4E)

Build and Test Debian Release

Run Embedded Linux applications against virtual SPI, I²C, GPIO and UART devices without the physical target board.

VDS4E is a hardwareless integration-testing environment for Embedded Linux software. It exposes virtual peripherals through normal Linux userspace interfaces such as /dev/spidevX.Y, /dev/i2c-N, /dev/gpiochipN and PTYs, allowing native x86_64 builds of production applications and standard Linux tools to exercise stateful device models on a development workstation.

VDS4E is not a CPU or board emulator. It focuses on the boundary between an Embedded Linux application and the device interfaces it already uses.

See VDS4E

Website · Watch the product film · GitHub Releases

VDS4E includes a browser-based engineering workbench for live device bring-up, adapter configuration, register inspection, transaction tracing, logic analysis, scenario execution and fault diagnosis. The UI runs with the packaged server; no separate Web server is required for release installations.

Why VDS4E?

Traditional mocks often replace application code paths. Full-system emulators model much more of the machine than many application-level tests need. VDS4E sits between those approaches:

  • No VDS-specific API in the application. Production code continues to use the Linux device ABI.
  • Kernel-visible interfaces. SPI, I²C and GPIO can be exercised through normal device nodes; UART uses a standard PTY.
  • Stateful peripherals. Device packages can model registers, bitfields, memory, state machines, timed operations, faults and reset behavior.
  • Declarative models. Peripheral behavior lives in versioned device packages rather than application-side test doubles.
  • Cross-device topology. Public device signals can drive GPIO lines, enabling flows such as sensor DRDY → GPIO edge → bus read.
  • Observable execution. Transactions, registers, state, faults, scenarios and telemetry are available through the control plane.
  • Automation friendly. Headless scenarios can produce JSON and JUnit results for integration and CI workflows.

Architecture

┌──────────────────────────────────────────────────────────────────────┐
│ Embedded Linux application / standard Linux tool                    │
│ spidev_test · i2c-tools · libgpiod tools · normal application code  │
└───────────────────────────────┬──────────────────────────────────────┘
                                │ normal Linux userspace ABI
                                ▼
┌──────────────────────────────────────────────────────────────────────┐
│ VDS4E host adapters                                                  │
│ SPI CUSE · I²C CUSE · gpio-sim · UART PTY                           │
└───────────────────────────────┬──────────────────────────────────────┘
                                │ framed Protobuf / Unix socket
                                ▼
┌──────────────────────────────────────────────────────────────────────┐
│ VDS4E runtime                                                        │
│ device registry · registers · behavior · virtual time · topology     │
└───────────────────────────────┬──────────────────────────────────────┘
                                │
                                ▼
┌──────────────────────────────────────────────────────────────────────┐
│ Declarative device packages                                         │
│ model · flows · scenarios · fixtures · docs · assets                 │
└──────────────────────────────────────────────────────────────────────┘

Control & observability: REST API · WebSocket events · React Web UI

The detailed design and architectural boundaries are documented in VDS4E_ARCHITECTURE.md.

Supported interfaces

Interface Linux-facing endpoint Runtime support Typical clients
SPI / spidev /dev/spidevX.Y via CUSE generic-spi-command production spidev applications, upstream spidev_test
I²C / i2c-dev /dev/i2c-N via CUSE generic-i2c-register, AT24C EEPROM i2cdetect, i2cget, i2cset, i2ctransfer, libi2c applications
GPIO real /dev/gpiochipN via kernel gpio-sim generic-gpio-bank gpiodetect, gpioinfo, gpioget, gpioset, gpiomon, libgpiod applications
UART / TTY kernel-assigned /dev/pts/N generic-uart-responder applications using open/read/write and termios
QSPI multi-lane / DTR native VDS4E transaction path SPI wire-setting validation VDS4E native clients
Ethernet / CAN / USB — not implemented —

SPI and I²C CUSE adapters and the GPIO gpio-sim integration require appropriate host-kernel support and privileges. UART PTY operation is unprivileged.

What's available on main

Capability What you can do
Bring-up-first Overview Follow the Linux device node → adapter → virtual peripheral path, inspect live traffic, runtime state, problem diagnostics, scenario progress and bus activity.
Register and device workbench Inspect registers, bitfields, state, commands, fault controls, configuration and transaction history for each device.
Transaction and logic analysis Examine bus requests/responses, protocol data, failures, virtual signals and capture timelines; filter failed transactions and deep-link to a capture.
Declarative device modeling Build versioned SPI, I²C, GPIO and UART device packages with registers, command behavior, state transitions, time-dependent operations and fault injection.
Board-level signal topology Route a modeled sensor's DRDY/IRQ output to a kernel-visible GPIO line; inspect connections, current signal levels and pending delayed deliveries in the UI or GET /api/v1/topology.
Device Tree import Draft SPI/I²C/GPIO packages from a DTS file, plus a reviewed board summary and a GPIO-interrupt topology.yaml draft where supported.
Scenario coverage See which declared commands, registers, states, transitions and faults a run actually exercised. Export machine-readable JSON and JUnit properties.
Real Linux application examples Run sample C applications against SPI flash, I²C EEPROM, GPIO (libgpiod) and UART (PTY), using ordinary Linux interfaces rather than VDS4E-specific mocks.

These are source-tree capabilities, not a promise that every feature above is included in the latest published .deb. See the changelog for changes made after the latest tagged release. DTS import produces editable drafts, not validated device-specific behavior extracted automatically from a hardware description.

Quick start

Install a release package

Tagged releases publish an amd64 Debian package and SHA-256 checksum. The latest published package is v0.1.2; newer capabilities described above may require a build from the current main branch.

Download the package from GitHub Releases, then install it:

sudo apt install ./vds4e_0.1.2_amd64.deb

Validate the installed configuration:

vds4e --check-config

Start VDS4E:

vds4e

Then open http://127.0.0.1:8080/. The same process serves the Web UI, REST API, WebSocket event stream, and Unix-socket transaction data plane.

To run it as a system service instead:

sudo systemctl enable --now vds4e

The package installs the unit but does not enable or start it automatically.

The package installs:

  • vds4e, vds-server and vds-cli
  • SPI, I²C, GPIO and UART host adapters
  • the built Web UI assets
  • schemas and bundled example device models
  • example Embedded Linux tools
  • /etc/vds4e/vds-server.yaml

Package installation intentionally does not load privileged kernel modules automatically.

Run from source

Building or running from source requires Rust (rustup / cargo), Node.js/npm, and system build tools. See Getting started: Prerequisites for one-step installation instructions.

For development:

git clone https://github.com/haknkayaa/VirtualDeviceSimulatorForEmbedded.git
cd VirtualDeviceSimulatorForEmbedded
./run.sh

The development launcher starts the Web UI, control API and transaction data plane. See Getting started for privilege details.

For the staged production-style build:

./configure
./build.sh
sudo ./install

Device packages

A device is a self-contained, versionable package:

my-device/
├── device-package.yaml
├── model/
│   └── device.yaml
├── flows/
│   └── behavior.yaml
├── scenarios/
├── fixtures/
├── docs/
└── assets/

Create and validate a package:

vds-cli device-package new ./my-sensor \
  --id my-sensor \
  --name "My Sensor" \
  --bus i2c

vds-cli device-package validate ./my-sensor

The bundled examples include generic SPI/I²C/GPIO/UART devices, AT24C EEPROM models and a Micron MT25QL256 flash model.

Example applications

The repository includes standalone Embedded Linux examples that exercise the same interfaces as ordinary production applications:

Example Linux interface What it exercises
Micron MT25QL256 SPI /dev/spidevX.Y flash identification and command transactions
Atmel AT24C256 I²C /dev/i2c-N EEPROM address and data transactions
Generic GPIO tool libgpiod /dev/gpiochipN line inspection, input/output and edge monitoring
UART ping PTY /dev/pts/N serial request/response

From a source checkout with prerequisites installed:

./examples/run_all.sh --build-only

Start VDS4E and load the relevant adapters and device bindings before running the examples. ./examples/run_all.sh also attempts to exercise discovered device nodes; it may need host privileges for the kernel-backed interfaces. The actual gpiochipN and PTY numbers depend on the host.

See the Device Package SDK, behavior-flow reference, and package/model schemas under schemas/.

Cross-device signals

Device models can expose public boolean output signals and connect them to device-driven GPIO lines through a board topology.

A typical flow is:

sensor schedules conversion completion
        ↓
sensor.drdy becomes high
        ↓
VDS4E topology routes the signal
        ↓
virtual GPIO line changes
        ↓
/dev/gpiochipN reports an edge
        ↓
application reads the sensor over SPI/I²C
        ↓
read-clear status deasserts DRDY

This allows application behavior based on interrupts/data-ready lines to be exercised without adding simulator-specific code to the application.

The workbench and GET /api/v1/topology also expose a read-only view of the attached connections, last sampled source levels and delayed deliveries.

See Topology.

Scenarios and deterministic device behavior

Headless scenarios use a manual virtual clock. Device-model operations such as state transitions, delayed actions, faults and timed write/erase behavior can therefore be reproduced independently of host CPU speed.

Example:

vds-cli scenario run \
  device-models/examples/micron-mt25ql256aba8esf-0sit/scenarios/01-read-jedec-id.yaml \
  --config config/vds-server.yaml \
  --json-output /tmp/result.json \
  --junit-output /tmp/result.xml

The live server uses a real-time-backed simulator clock. Live runs therefore retain deterministic device-model semantics but are still subject to normal operating-system scheduling jitter. VDS4E does not claim whole-system or bit-for-bit determinism for live native processes.

Scenario coverage

Scenario results can report model-level coverage, so a passing test does not silently imply that every declared behavior was exercised. Coverage tracks:

  • commands sent to a modeled device;
  • registers reached through normal device operations;
  • entered/exited states and observed state transitions;
  • triggered fault definitions.

You can inspect coverage in the CLI output, scenario JSON results, JUnit properties, the Visual Scenario Editor and the Overview's latest-run panel. Coverage is informational; it does not automatically fail CI when a threshold is missed.

Read the coverage reference and ADR 0013 for the exact counting rules and current SPI-scenario scope.

Control and observability

The server provides:

  • REST control API
  • WebSocket event stream with bounded replay
  • optional SQLite event persistence
  • transaction and register inspection
  • device state and fault control
  • scenario execution
  • adapter management
  • React Web UI

High-frequency hardware transactions do not travel over REST. Native adapters use the framed Protobuf Unix-socket data plane.

Default development endpoints:

Control API:  http://127.0.0.1:8080/api/v1
Web UI:       http://127.0.0.1:4174
Data plane:   /tmp/vds4e.sock

Hardware-description import

The vds-importer crate can draft declarative models from:

  • CMSIS-SVD register descriptions
  • Device Tree source

Importer output is intentionally a starting point rather than a finished behavioral model. Device-specific semantics still need to be reviewed and completed by the model author.

Draft device packages for enabled SPI, I²C and GPIO peripherals in a board's Device Tree (available on main):

vds-cli import dts board.dts --output drafts/

When a peripheral's interrupt-parent is a GPIO controller of the board, the import also drafts that controller as a GPIO bank and writes drafts/topology.yaml, connecting the peripheral's new irq output (driven by bit 0 of a placeholder IRQ_STATE register) to the line its interrupts names. Every draft, and the topology, is loaded the way the server loads them before the command succeeds. drafts/board.md lists each package with its bus controller, endpoint (SPI chip select or I2C address), compatible strings and interrupts, the nodes that were skipped (disabled, or a bus without a VDS4E runtime), and the device_packages entries to add to vds-server.yaml. Pass --include-disabled to draft status = "disabled" nodes too.

What VDS4E does not simulate

VDS4E provides functional peripheral simulation. It does not currently model:

  • CPU instruction execution
  • a complete SoC or board boot
  • electrical characteristics or signal integrity
  • controller DMA/IRQ timing
  • analog behavior
  • Ethernet, CAN or USB runtime devices
  • full-system checkpoint/restore or record/replay

Use QEMU, Renode or another full-system platform when CPU/SoC emulation is the requirement. Use hardware-in-the-loop and real-target testing for electrical, timing and hardware-integration validation.

For recorded, unprivileged device replay, umockdev may be a lighter fit. VDS4E is aimed at cases where stateful modeled behavior, kernel-visible interfaces, shared device state and cross-device interaction matter.

Verification

The regular CI validates the Rust workspace, Web UI, native adapters and example applications.

Equivalent local checks include:

cargo fmt --all -- --check
cargo clippy --workspace --all-targets --locked -- -D warnings
cargo test --workspace --locked

npm --prefix apps/vds-web ci
npm --prefix apps/vds-web run lint
npm --prefix apps/vds-web run typecheck
npm --prefix apps/vds-web run test:run
npm --prefix apps/vds-web run build

A real Linux ABI E2E harness is available under tests/e2e/ for privileged integration testing with standard Linux tools and kernel-backed interfaces.

Documentation

Document Purpose
Documentation index map of user, contributor and architecture documentation
Getting started prerequisites, development workspace, staged build and installation
First virtual device create an I²C model and exercise it through a real /dev/i2c-N endpoint
Control-plane API REST resources, error contract and replayable WebSocket events
Architecture authoritative system architecture and boundaries
Testing local checks, native adapters, real Linux ABI E2E and CI scope
Releases version/tag rules and Debian release workflow
Troubleshooting common CUSE, gpio-sim, permissions, PTY and configuration issues
SPI / I²C / GPIO / UART Linux host-interface guides and examples
Topology guide cross-device signal routing
Device Package SDK package contract and author workflow
Scenario coverage coverage accounting for commands, registers, states, transitions and faults
C example applications hardware-facing sample tools and run-all script
ADRs architecture decisions
Roadmap planned capabilities
Contributing development and contribution guidance
Security security policy

Project boundaries

The project intentionally keeps these responsibilities separate:

  • the server owns authoritative virtual-device state;
  • host adapters translate Linux ABIs and do not contain device semantics;
  • the Web UI is a control and observability client, not a device runtime;
  • high-frequency transactions use the native Unix-socket data plane;
  • behavior comes from declarative device packages;
  • privileged kernel integration is isolated from the core runtime.

These boundaries are part of the product design, not just implementation details.

License

Licensed under the Apache License 2.0.

Maintainer

Hakan Kaya (@haknkayaa)

VDS4E is currently developed independently by Hakan Kaya. The open-source core is available under Apache 2.0.

Contact: hakan@vds4e.dev · Project website

About

Run and test embedded Linux applications on your host as if GPIO, SPI, I2C, UART, QSPI, and Ethernet devices were physically connected.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages