Skip to content
vheinitzPublic

About

Workbench for laboratory instrument interfaces (CLSI LIS01-A2 / LIS02-A2, formerly ASTM E1381/E1394): simulate, monitor, bridge, map, fault-inject. Hobby project.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

lisbench

Tools for developing and testing laboratory instrument interfaces that speak CLSI LIS01-A2 (formerly ASTM E1381, the low-level protocol with ENQ/ACK, frames and checksums) and CLSI LIS02-A2 (formerly ASTM E1394, the record format H/P/O/R/C/Q/L).

lisbench is a workbench for the people who build and integrate these interfaces. It is not middleware for clinical operation and must not be used to route patient results in production.

Status: v0.8, protocol core, command line tool, simulator, monitor, bridges, database mapper and instrument simulators for Arduino/ESP32; first instrument profile (Cepheid GeneXpert, from the public specification); conformance test suite; web UI. The Raspberry Pi package is next; see docs/spec/features.md. A spare-time project.

What works now

  • LIS01-A2 framing: split records into frames of at most 240 text bytes, frame numbers modulo 8, checksum, ETB/ETX; decoding with exact error reasons.
  • LIS01-A2 link state machine without I/O: establishment, contention (instrument has priority), busy NAK, retransmission (six attempts), timeouts (15 s / 30 s), receiver interrupt (EOT instead of ACK), disconnect, cancel. Every submitted message gets exactly one result, on every path.
  • LIS02-A2 records: delimiters from the header, fields/repeats/components, escapes &F& &S& &R& &E& &Xhh&, all field names of H, P, O, R, C, Q, L, S in one table.
  • Character sets: Latin-1 or UTF-8 on the wire; non-ASCII as &Xhh& (7-bit), raw 8-bit, or transliterated to ASCII with a report of dropped characters.
  • Validation of record order, hierarchy and sequence numbers; a builder that refuses records that do not fit instead of dropping them.
  • Reassembly of records from a raw one-direction capture.
  • Simulator for an instrument or a LIS over TCP (client or server) or a serial port: scenarios in YAML (send, expect, wait), automatic answers to queries, and fault injection on the wire (refuse, corrupt, drop or delay ACK, NAK, ENQ, EOT or frames). See examples/.
  • Monitor between instrument and LIS (TCP or serial, or a passive tap on two receive lines): decodes both directions, flags bad and repeated frames, NAKs, slow replies and transfers without L record, evaluates watch expressions on field values (R.value > 100, O.universal_test_id.4 == TSH) and triggers on them (R.value > 400 => exec ./alarm.sh, => mark, => stop), saves the raw traffic and replays it offline.
  • Conformance test suite (lisbench conform) for a LIS or an instrument: 14 test cases on LIS01-A2 (wrong checksum and frame number must be refused, repeated frames, six attempts, timeouts, busy wait, contention, receiver interrupt, frame format), each with a verdict pass / fail / inconclusive; an instrument profile serves as PICS. Terms after ISO/IEC 9646.
  • Sessions: LIS and instrument simulators as saved session files, several at once, with an order book (specimens, tests from a shared catalogue, item states, order-result matching, unsolicited results by policy) and host-query or unsolicited instruments; lisbench run or the web UI.
  • Web UI (lisbench serve): monitor, captures, conformance test and simulator in the browser, live; one binary with the pages built in, made for a Raspberry Pi next to the instrument.
  • Bridges without decoding: serial ↔ TCP, TCP client ↔ server (role swap), and recording of one endpoint to a capture or raw file.
  • Mapper from an SQLite database to messages, described in YAML: nested queries with their own scopes, bound parameters, escaping of every value, records that do not fit the hierarchy are errors, write-back after sending, output to TCP, serial or files. See examples/mapper/.
  • Instruments on microcontrollers: an Arduino library and sketches for an Uno (USB serial) and an ESP32 (Wi-Fi) that send results to a LIS. See devsim/.

Build

Requires CMake ≥ 3.25 and a C++23 compiler (GCC ≥ 13, Clang ≥ 19 or MSVC 2022). Dependencies (asio, yaml-cpp, SQLite, CLI11, nlohmann/json, Catch2) are fetched at configure time.

cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build
ctest --test-dir build

Raspberry Pi and Debian package

Every release carries Debian packages built on Debian 13 (the base of current Raspberry Pi OS): arm64 for a Pi 3B+ or newer with the 64-bit system, armhf for the 32-bit system (ARMv7, so not for a Pi Zero or Pi 1), and amd64 for a PC.

sudo apt install ./lisbench_0.7.0_arm64.deb
lisbench --version
sudo nano /etc/default/lisbench          # address of the web UI, data directory
sudo systemctl enable --now lisbench     # web UI on port 8080

The package installs /usr/bin/lisbench, the instrument profiles under /usr/share/lisbench/devices (so --profile cepheid-genexpert works without a path), examples under /usr/share/doc/lisbench/examples, and a systemd service that runs lisbench serve as user lisbench (member of dialout for serial ports, data in /var/lib/lisbench). The service is not enabled on install: it makes a web UI without authentication reachable on the network, which should be a deliberate step. To build a package yourself: cmake --build build && (cd build && cpack -G DEB).

Command line

lisbench frame   FILE [--raw]       records (one per line) -> frames ENQ ... EOT
lisbench deframe FILE               raw capture -> records, checks every frame
lisbench decode  FILE [--json]      records or capture -> fields by name
lisbench validate FILE              order, hierarchy, sequence numbers
lisbench sim SCENARIO.yaml          run a simulator scenario
lisbench sim --endpoint URI ...     the same from options (--send, --receive,
                                    --answer-queries, --fault, --trace, --fast-timing)
lisbench monitor --a URI --b URI    pass traffic through and show it decoded
                                    (--watch, --trigger, --save, --decode, --verbose, --tap)
lisbench monitor --replay FILE      the same for a saved capture
lisbench serve [--http ADDR:PORT] [--captures DIR]   web UI (default 127.0.0.1:8080)
lisbench run DIR/sessions/NAME.yaml ...  run session files without the UI
lisbench conform --iut ROLE --endpoint URI   conformance test suite (--only, --profile, --json)
lisbench bridge --a URI --b URI     join two endpoints, bytes unchanged (--serve, --save)
lisbench record --from URI --to F   write what an endpoint sends to a file (--raw)
lisbench map MAPPING.yaml --db DB   messages from a database (--each, --arg, --to)

Endpoints: tcp://host:port, tcp-listen://:port, serial:/dev/ttyUSB0?baud=9600&data=8&parity=none&stop=1 (serial:COM3?... on Windows). The low-level protocol is LIS01-A2 unless the URI says otherwise: tcp://host:port?low-level=none (records with CR, the message ends with L) or ?low-level=mllp (HL7 MLLP block); serial ports take &low-level=....

decode and validate take --charset latin1|utf8, --non-ascii ascii-hex|raw|transliterate and --strict. Example:

$ lisbench frame tests/corpus/valid_host_query.astm
<ENQ>
<STX>1H|\^&|||lisbench-sim|||||LIS||P|LIS2-A2|20261025120500<CR><ETX>1F<CR><LF>
<STX>2Q|1|^S-1002||ALL||||||||O<CR><ETX>5D<CR><LF>
<STX>3L|1|N<CR><ETX>06<CR><LF>
<EOT>

Tests

Unit tests, a property test over all record lengths 0–2000, a lossy-wire simulation (drops and bit errors, 200 seeds) for the link, an exhaustive character test U+0000–U+00FF in every mode, randomised round-trip tests, simulator-against-simulator tests over TCP and over a pseudo-terminal null modem with injected faults, and libFuzzer targets in fuzz/. CI builds with GCC 13/14, Clang 19 and MSVC, runs ASan/UBSan, clang-tidy and the fuzzers. Details in docs/spec/tests.md.

Related projects

python-astm (Python library), OpenELIS analyzer bridge (delivery into OpenELIS), ser2net (serial over TCP), Mirth Connect / Open Integration Engine (interface engines).

Licence

MIT, see LICENSE. The CLSI standards are not part of this repository; they are available from CLSI.

About

Workbench for laboratory instrument interfaces (CLSI LIS01-A2 / LIS02-A2, formerly ASTM E1381/E1394): simulate, monitor, bridge, map, fault-inject. Hobby project.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages