hilspy
HILS (hardware-in-the-loop simulation) I/O for Python on a Rust core. It is
built to be embedded in a scenario library (such as
autoware_carla_scenario),
where a simulator has to talk to real or simulated ECUs and sensors.
The first release covers:
| Module | What it does | Rust crate used |
|---|---|---|
hilspy.can |
CAN / CAN FD frames; buses on Linux SocketCAN (can0, vcan0) or an in-process virtual bus; receive filters; periodic (cyclic) transmission from a Rust thread |
socketcan |
hilspy.dbc |
DBC databases: encode physical signal values to payloads/frames and decode them back (scaling, value tables, signed/float signals, Intel and Motorola layouts, multiplexing, CAN FD messages) | can-dbc |
hilspy.sbf |
Septentrio Binary Format: a streaming decoder (resync, CRC check, typed fields for PVT/attitude/INS/covariance blocks) and encoders for PVTGeodetic/AttEuler so a simulator can stand in for a GNSS receiver | libsbf |
The Python package is a thin layer: everything above runs in Rust
(crates/hilspy-core) and is exposed through PyO3 (crates/hilspy-python).
Blocking calls release the GIL; a blocking recv stays interruptible with
Ctrl-C.
Install
Python 3.10+. One abi3 wheel per platform serves every Python version; wheels are built for Linux (x86_64, aarch64), macOS (arm64, x86_64) and Windows x64. SocketCAN is Linux-only; the virtual bus, DBC and SBF work everywhere.
pip install hilspy
uv add hilspy
pip install git+https://github.com/hakuturu583/hilspy # from source (needs Rust)
From a checkout:
uv sync # builds the extension with maturin
uv run pytest
Versions follow semver and are released by labelling the PR (bump patch /
bump minor / bump major); see docs/releasing.md.
CAN
from hilspy.can import Bus, Filter, Frame
with Bus("vcan0") as bus: # interface="socketcan" is the default
bus.send(Frame(0x123, b"\x01\x02\x03"))
frame = bus.recv(timeout=1.0) # Frame or None
for frame in bus: # until bus.shutdown()
...
Bus(channel, "virtual")joins an in-process bus: everyBusopened on the same channel name in the process receives the others' frames. No kernel interface or root needed, so it suits tests and simulated ECUs wired together in one process.fd=Trueopens a CAN FD socket;Frame(id, data, is_fd=True, bitrate_switch=True).filters=[Filter(0x100, 0x700), {"can_id": 0x18FF0001, "extended": True}](kernel filters on SocketCAN),receive_own_messages=True.bus.send_periodic(frame, period, duration=None)sends from a Rust thread with drift-free absolute deadlines;task.modify(frame)swaps the payload (counters, checksums),task.period = 0.02,task.stop().
A virtual CAN interface for local testing:
sudo modprobe vcan
sudo ip link add dev vcan0 type vcan
sudo ip link set vcan0 mtu 72 # CAN FD
sudo ip link set up vcan0
DBC
from hilspy import dbc
db = dbc.load_file("vehicle.dbc")
frame = db.encode_frame("VehicleSpeed", {"Speed": 42.0, "Accel": 0.5, "Gear": "D", "Counter": 3})
bus.send(frame)
values = db.decode_frame(bus.recv()) # {"Speed": 42.0, "Gear": "D", ...}
db.decode("VehicleSpeed", payload, decode_choices=False, scaling=False) # raw values
encode is strict by default: every signal must be given, values must lie in
the signal's [min|max], and names must exist. strict=False fills missing
signals with GenSigStartValue (or 0). Raw values that do not fit in the
signal's bits always fail. Message.cycle_time reads GenMsgCycleTime, and
Message.is_fd reads VFrameFormat (or a payload over 8 bytes).
SBF
from hilspy import sbf
decoder = sbf.Decoder()
for chunk in serial_or_socket_chunks:
for block in decoder.feed(chunk):
if block.name == "PVTGeodetic":
print(block["latitude"], block["longitude"], block["mode_name"])
blocks = sbf.read_file("capture.sbf")
# Simulated receiver output
wnc, tow = sbf.gps_time(time.time())
data = sbf.encode_pvt_geodetic(
tow=tow,
wnc=wnc,
mode=4,
latitude=lat_rad,
longitude=lon_rad,
height=40.0,
vn=1.0,
ve=0.0,
vu=0.0,
)
data += sbf.encode_att_euler(tow=tow, wnc=wnc, mode=4, heading=90.0, pitch=0.0, roll=0.0)
Every block keeps its raw bytes, number, revision, tow and wnc;
fields is a dict for the blocks with a field mapping (PVTGeodetic,
PVTCartesian, AttEuler, INSNavGeod, ReceiverTime, DOP, PosCovGeodetic,
VelCovGeodetic, EndOfPVT/Att/Meas) and None otherwise. Do-not-use values read
as None. sbf.frame_block(number, revision, body) frames any other block.
Examples
uv run python examples/virtual_ecu.py # cyclic DBC message on a virtual bus
uv run python examples/virtual_ecu.py --interface socketcan --channel vcan0
uv run python examples/gnss_simulator.py --file sim.sbf --seconds 5
uv run python examples/gnss_simulator.py --tcp 28784 # serve like a receiver's TCP port
uv run python examples/sbf_dump.py sim.sbf
Development
uv sync # build + dev dependencies (cantools for cross-checks)
cargo test -p hilspy-core # Rust unit tests
uv run pytest # Python tests
HILSPY_TEST_VCAN=vcan0 uv run pytest tests/test_socketcan.py # needs a vcan interface
uv run pre-commit run --all-files # ruff, mypy, cargo fmt, clippy
Design notes: docs/design.md.
License
Apache-2.0
Metadata
Release files for hilspy 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| hilspy-0.2.0.tar.gz | 55.0 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| hilspy-0.2.0-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| hilspy-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| hilspy-0.2.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ ARM64 | Details |
| hilspy-0.2.0-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
| hilspy-0.2.0-cp310-abi3-macosx_10_12_x86_64.whl | CPython 3.10 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 4.1 MB
Release files / hilspy-0.2.0.tar.gz
| Download URL | hilspy-0.2.0.tar.gz |
|---|---|
| Size | 55.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6fea07c0a71ef0de243e1219ebd45d4907e955e30206457f8d129b056043ed4b
|
|
BLAKE2b-256 checksum How to use checksums |
f847a6a9757dd9a0981d3fcd9b300774470c99bc7cdc16b04f7947033a1c569f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logRelease files / hilspy-0.2.0-cp310-abi3-win_amd64.whl
| Download URL | hilspy-0.2.0-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 731.5 kB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
a93a6eb33abc169856f64fcac2e2f860e46d49a6f7259de5fe389b0bf7d8a891
|
|
BLAKE2b-256 checksum How to use checksums |
ac37866320bcb52b1a1e1b7f647f5db5f5a4e9245d38cba760a2e7690f52afd6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logRelease files / hilspy-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | hilspy-0.2.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 858.9 kB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
cf3d5d7bd4f54023d5bbcaf626aebd888c71de4893d91baf26f5a28bb9425a59
|
|
BLAKE2b-256 checksum How to use checksums |
11faf33f2fb5d12cb6bffd9d09e496ad2de6cba40aac13ccd797579b6b01d627
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logRelease files / hilspy-0.2.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
| Download URL | hilspy-0.2.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl |
|---|---|
| Size | 849.8 kB |
| Tags | CPython 3.10 Linux glibc 2.17+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
3597b826ce3136b48a4a6e62884f930e0c4212ffca54fd4821e708f4e385eae1
|
|
BLAKE2b-256 checksum How to use checksums |
3f5759dcf0eb4ff34f8d25ff6d0aa17fea64b104f16199d30e69c12a28186615
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logRelease files / hilspy-0.2.0-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | hilspy-0.2.0-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 778.7 kB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
46dbe71ab5032e36eb2cd891f8291bef54fb6b80d74fd605b0a80cea5b3608e4
|
|
BLAKE2b-256 checksum How to use checksums |
66b91b60273ccba67a5334c81d5e66fcee036e38f2dcc66a11d87c56287afb0d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logRelease files / hilspy-0.2.0-cp310-abi3-macosx_10_12_x86_64.whl
| Download URL | hilspy-0.2.0-cp310-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 791.3 kB |
| Tags | CPython 3.10 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
c61ea4e972bf76f6e95477a4da8cdee0b622603dc28661c5495b24373f6aeaaf
|
|
BLAKE2b-256 checksum How to use checksums |
5c992804233772de928e4d6e428c8b221555b2c0878198fe1857390c345f0d97
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency log