For a quick start of the full application and simulator, refer to the scripts directory contents.
Consult the scripts/README.md and consider using the scripts/setup_and_launch --dev convenience tool,
or bash scripts/run_sim_stack --frontend-mode dev --frontend-port 5173 for a simulator build and browser
app pair.
In general, you can shut down your simulator instances with bash ./scripts/stop_sim_stack.
Make sure you stop your running instances once you're done testing and playing, but if you're connected
to an actual instrument be cautious with which tool you use and how.
A lot of this is still in "beta" afterall.
StoneLab is built to be right-to-repair friendly control software: usable by students and programmers, but also practical for operators and owners who want control over their own machines (even when a vendor has stopped supporting them).
What sets StoneLab apart:
-
Local-first, offline-capable
- Runs on a laptop, shop PC, or edge box; no cloud dependency.
- Projects stay portable (you own your configs, schemas, and recordings).
-
Protocol-as-code, UI derived from schema
DeviceGraph.json+ComponentSchema.json+ parts libraries are the canonical spec.- The UI (Set dialogs, plots, and tooling) derives from what devices advertise.
-
Built-in simulator / digital twin
- Same device IDs, same controls, same UI — swap between real and simulated.
- Deterministic, seeded-noise simulation for reproducible debugging and demos.
-
Macro Wizard that round-trips to code
- Import/export scripts that stay readable, reviewable, and diff-able.
- Designed for workflows beyond classic tag edits: methods, procedures, and experiments.
-
Automation without UI coupling (BE macro jobs + scheduler)
- Run macros in backend orchestration mode so they continue through refresh/reconnect.
- Schedule macros to run at a specific time or on a fixed interval (persistent across restarts).
- Enables practical multi-instrument workflows: switching between instruments in the same browser doesn’t stop in-flight automation.
-
Diagnostics, events, and alarms with nested causes
- Errors/alarms can carry
caused_bychains for root-cause visibility. - Core catalogs + toolkit-scoped catalogs keep messages consistent and discoverable.
- Errors/alarms can carry
-
Recording + replay for debugging and validation
- “Flight recorder” runs: actions + measurements + UI state can be replayed.
- Overlay comparisons to spot drift and regressions between runs.
-
Network-aware visualization (flowlines and beyond)
- Edges can carry semantics: fluid flow, electrical current, etc.
- Server-side derived edge state keeps toolkits consistent and extensible.
-
Composite mode (multi-instrument “backend-as-device”)
- A “middleman” backend can proxy multiple instrument backends into one schematic.
- Optional signal routing rules can drive one instrument from another.
-
External drivers (process adapter)
- Load devices from external driver processes (
--drivers) without embedding large protocol stacks. - Example driver included; config supports namespacing via
id_prefix.
- Load devices from external driver processes (
-
Launch ergonomics (path robustness)
- Backend normalizes config paths (
--graph,--composite,--drivers) andSTONELAB_PROTOCOL_CONFIGto absolute paths at startup. - Reduces “changed working directory” surprises in scripts and automation.
- Backend normalizes config paths (
-
Safety and governance without lock-in
- Units/ranges, safe-state defaults, and audit-friendly action logging.
- Supports serious instrument-control use cases without forcing vendor ecosystems.
-
Schema-driven control surfaces
- The backend advertises writable controls per device (derived from the active protocol schema), so toolkit devices populate the UI Set dialog without hardcoded frontend mappings.
-
Network-aware visualization
- Server-side flowline computation supports both fluid networks (flow rate) and circuits (current) so edges can animate consistently across domains.
-
StoneFluid toolkit primitives
- Reservoir volume/capacity primitives with
empty/overfilledflags andoverflow_ml, plus Macro Wizard templates for fill/drain and loop demos. - See:
toolkits/StoneFluid/tools/macro_wizard/
- Reservoir volume/capacity primitives with
-
StoneCircuits toolkit primitives
- A shared RC transient simulator (Vs/R/C/switch) plus Macro Wizard templates and notebooks that drive the sim via WebSocket RPC.
- See:
toolkits/StoneCircuits/tools/macro_wizard/andtoolkits/StoneCircuits/notebooks/
-
Shared simulator utilities
- A reusable core
NoiseModelerused by toolkit simulators for consistent, deterministic noise.
- A reusable core
-
Composite mode (multi-backend)
- Run a composite backend that proxies multiple StoneLab backends as namespaced devices (
A::device_id). - Optional routing rules (“signal router”) can forward measurements → actions with rate limiting.
- Run a composite backend that proxies multiple StoneLab backends as namespaced devices (
-
Toolkit modularity
- Toolkits can provide protocol assets, macro templates, notebooks, and optional plugins.
- Protocol selection is persisted via
shared/config/protocol.json(restart required).
-
Release bundles and run wrappers
- Installer bundles include a single entrypoint runner (
./bin/stonelab-run) with--sim,--composite, and--driversmodes. - Dev scripts support launching composite backends (see
scripts/run_sim_stack --help).
- Installer bundles include a single entrypoint runner (
-
External drivers (process adapter)
- Backend can spawn one or more external driver processes via
--drivers <config.json>and register their devices. - Example driver config is provided in
shared/config/drivers.example.json.
- Backend can spawn one or more external driver processes via
-
End-to-end diagnostics improvements
- Nested error reporting (
caused_by) is carried through backend → UI and rendered for operators.
- Nested error reporting (
-
Near-term (0–3 months)
- “Bring-up mode” for unknown hardware: safe probing tools, signal labeling, and schema generation.
- Composite mode usability: route-firing events, health/latency summaries, and safer policy tooling.
- Multi-instrument schematics UX: clearer namespacing, grouping, and cross-backend navigation.
- Project bundles: export/import a single artifact containing protocol/schema/overrides/macros/recordings.
- Alarms/events polish: hysteresis, ack workflows, routing, and audit views.
-
Mid-term (3–6 months)
- Driver adapters for common transports (serial, Modbus, CAN, MQTT, OPC-UA client) built on the external driver process framework.
- Driver protocol evolution: streaming/subscribe, reconnect/backoff, and richer metadata (units/ranges) from drivers.
- Protocol CI: headless macro runner + invariants in simulation.
- Optional persistence/historian path (recording queries, retention, export).
-
Longer-term (6–12 months)
- Method execution and reporting (instrument-control workflows with provenance and calibration records).
- Richer edge semantics (thermal/material/signal flow) and derived network analytics.
- Continuous/data-plane wiring between instruments (beyond discrete routing rules)
-
Provide a working, well-structured skeleton codebase that implements subsystems for monitoring and controlling lab instrumentation:
- Backend [
c++]: diagnostics, results, reception, demo/simulator, state cache; - Frontend [
vite/React]: transmission and reception of instructions for backend determined from user interactions, diagnostics UI, display of apparatus components in an editable schematic.
- Backend [
-
Provide users with ability to customize as much as possible.
-
Provide sample toolkits and utilities for getting started with "Simulational Integrity" as a top priority.
-
Enable multi-instrument schematics by treating backends as devices (composite mode).
-
Provide explicit “signal router” rules between instruments (policy/audit UX still evolving).
backend/ C++ backend (simulator, device registry, WebSocket server, composite mode)
docs/ Project documentation (source-of-truth; synced into frontend)
frontend/ React + Vite web UI
scripts/ Convenience scripts (build, run stacks, docs sync)
shared/ Protocol assets + configs (DeviceGraph.json, ComponentSchema.json, errors/alarms)
toolkits/ Optional toolkits (protocol assets, plugins, notebooks, utilities)
tools/ Dev tools (SDK generators, installer/bundler, toolbox clients)
sdk/ Generated SDK outputs (Python, TS, etc.)
release/ Bundle outputs
StoneLab is commonly deployed across two machines:
- Instrument backend: the machine running the C++ server in
backend/(often the instrument host: embedded Linux / a nearby control PC). - Browser UI (frontend): the machine where you open the web app built from
frontend/(often an operator workstation).
These do not need to be the same machine. The UI connects to the instrument backend over WebSocket (default path /status).
Notes:
- When this README says “backend”, it refers to the process running on the instrument backend host.
- When it says “frontend/UI”, it refers to the web app running in the operator’s browser (or a static web server).
When using the convenience scripts, think in terms of roles:
-
Role:
backend(instrument backend host)- Runs the C++ server (often
--simfor demos, or real drivers for hardware). - Owns runtime state/log files (events, alarms state, audit log, historian log).
- Runs the C++ server (often
-
Role:
ui(operator workstation)- Runs the web UI dev server or preview server.
- Connects to the backend over WebSocket (default path
/status). - Stores lightweight operator identity locally in the browser (localStorage).
-
Role:
all(single machine dev)- Runs both backend + UI on the same host.
Convenience script examples:
# Single machine (developer laptop): backend + UI
bash scripts/run_sim_stack --role all
# Two machines:
# 1) On the instrument backend host
bash scripts/run_sim_stack --role backend --port 8080
# 2) On the operator workstation (point UI at the instrument backend)
bash scripts/run_sim_stack --role ui --backend-ws ws://<instrument-host>:8080/status --frontend-mode dev --frontend-port 5173- C++20 compiler (GCC 10+, Clang 11+, or MSVC 2019+)
- CMake 3.16+
- nlohmann json development package (optional):
nlohmann-json3-dev(lets CMake findnlohmann_jsontarget)- nlohmann/json (header-only, included)
- Node.js 20+ (for backend-sim and frontend)
- pnpm (or npm/yarn) for frontend
- Python 3.10+ (recommended)
- Used by developer tools (SDK generation, notebooks) and the
stonelab-toolboxCLI. tools/toolbox_pythondepends onwebsockets>=12.0.
- Used by developer tools (SDK generation, notebooks) and the
cd backend
mkdir -p build && cd build
cmake ..
cmake --build . -- -j$(nproc)./StoneLab
# or specify port: ./StoneLab 9001./StoneLab --sim
# or, run in background
nohup ./backend/build/StoneLab --sim > /tmp/StoneLab.log 2>&1 &Notes:
- Use
./StoneLab --helpto see available options (--sim,--port, etc.). - The backend starts a small stdin-based control thread only when stdin is a TTY. When you run the server detached (e.g.
nohup,systemd, or redirecting stdin), the stdin control thread is skipped automatically to avoid the process being stopped by the shell.
Simulator mode can load its protocol assets (DeviceGraph + ComponentSchema) from either:
- the core protocol under
shared/protocol/, or - a toolkit-provided protocol under
toolkits/<ToolkitName>/....
Selection is persisted in shared/config/protocol.json and is restart-required (no hot-apply yet).
Common workflows:
# Use core protocol (next startup)
python3 tools/toolbox_python/stonegate_toolbox_client.py --ws ws://localhost:8080/status protocol.set core
# Use StoneQC toolkit protocol (next startup)
python3 tools/toolbox_python/stonegate_toolbox_client.py --ws ws://localhost:8080/status protocol.set StoneQC
# Preferred (rebranded) entrypoint (wrapper around the same client):
# python3 tools/toolbox_python/stonelab_toolbox_client.py --ws ws://localhost:8080/status protocol.set coreThen restart the backend (./StoneLab --sim).
Note: this repo also ships bundled example toolkits (if built with STONELAB_BUILD_TOOLKITS=ON) including StoneCircuits and StoneFluid. See docs/Toolkits.md.
For a compact terminal view of flowlines plus key device measurements:
python -m tools.visualization.monitor --ws ws://localhost:8080/status --auto-watchSee tools/visualization/README.md for details and manual --watch usage.
./test_simulator --seed 42
# Optionally specify a custom device graph:
# ./test_simulator --graph ../../shared/protocol/DeviceGraph.json --seed 123This prints the loaded device descriptors and a single measurement poll for all simulated devices. Use a fixed seed for predictable results.
cd frontend
pnpm install # or npm install
pnpm dev # or npm run devUI notes:
- The Tools menu includes Diagnostics, Events, Trends, and Help.
- Help shows the frontend version, git commit, and build time (injected at build time).
Operator identity (local, lightweight):
- The Tools menu includes an Operator field.
- This value is attached to WebSocket RPC requests as
userand is used by the backend to attribute acknowledgements and audit records.
Deployment note:
- The browser UI can run on a different machine than the instrument backend. In that case, set the UI endpoint to the instrument backend host, e.g.
ws://<instrument-host>:8080/status.
Note: StoneLab includes a separate bundle installer flow (CLI wizard + scripts) for distribution and deployment. See the "Distribution / Installer" section.
For common one-command workflows (generate docs/SDKs, build + launch sim backend + frontend), see scripts/README.md.
Toolkit docs:
- docs/Toolkits.md (how to create/install toolkits; protocol selection; using toolkits outside StoneLab)
If you want to send someone a self-installable build (without requiring them to compile), you can create a "bundle" that includes:
- the backend executable (
StoneLab) - the built frontend static assets (
frontend/dist) - a small runner + installer with multiple install modes
Create a tarball on your dev machine:
./tools/installer/stonegate-bundle.sh
# Preferred (rebranded) entrypoint:
# ./tools/installer/stonelab-bundle.shThen on the target machine:
tar -xzf stonegate-<version>.tar.gz
cd stonegate
./bin/install.sh --helpGuided setup (recommended):
./bin/stonegate-wizardThe installer can set defaults for the built UI (backend host/port, build-mode defaults) via frontend/dist/stonegate-config.js.
Docker option (build+run inside containers) is available if you create the bundle with --include-source.
backend/— C++ backend server, simulation, and device registrybackend-sim/— Node.js simulator (optional, for frontend demo)frontend/— React frontendshared/protocol/— Device graph and component schemasshared/config/— Runtime config (toolkit enablement, active protocol selection)toolkits/— Installable toolkits (manifests + optional backend plugins + protocol assets)
Toolkit deployment note:
- Toolkits (and any backend plugins they ship) must be present on the instrument backend host (or otherwise accessible to the backend process). The browser UI does not load toolkit files directly.
- Run
./test_simulator --seed 42to verify that simulated devices are loaded and produce deterministic measurements. - Extend with more tests as needed for device logic and protocol.
stonelab/
├── README.md
├── backend/
│ ├── CMakeLists.txt
│ ├── include/
│ │ ├── Device.hpp
│ │ ├── DeviceRegistry.hpp
│ │ └── WebSocketServer.hpp
│ ├── src/
│ │ ├── main.cpp
│ │ ├── Backend.cpp
│ │ ├── DeviceRegistry.cpp
│ │ ├── WebSocketServer.cpp
│ │ └── core/
│ │ ├── PhysicsEngine.cpp
│ │ └── simulator/
│ └── tests/
├── backend-sim/
├── docs/
├── frontend/
│ ├── package.json
│ └── src/
│ ├── main.tsx
│ └── components/
│ └── SchematicCanvas/
├── shared/
│ ├── protocol/
│ │ ├── DeviceGraph.json
│ │ └── ComponentSchema.json
│ └── config/
├── tools/
└── LICENSE
Below is a small bash function you can add to your shell aliases (e.g., in ~/.bashrc) to print a
compact project tree similar to the block above.
It uses Python's stdlib so it doesn't require tree to be installed:
treeproj() {
python3 - <<'PY'
import os
def tree(path, prefix=''):
try:
entries = sorted([e for e in os.listdir(path) if not e.startswith('.')])
except PermissionError:
return
for i, name in enumerate(entries):
p = os.path.join(path, name)
connector = '└── ' if i == len(entries)-1 else '├── '
print(prefix + connector + name)
if os.path.isdir(p):
extension = ' ' if i == len(entries)-1 else '│ '
tree(p, prefix + extension)
print('.')
tree('.')
PY
}
# Example usage:
# cd /path/to/project && treeproj- Backend (C++): modular libraries separated into
diagnostic,results,reception,demo.
Each subsystem exposes abstract interfaces (IDevice,IMeasurementSource,IReceiver) so hardware-specific drivers can be plugged in. - State cache: thread-safe in-memory cache containing latest measurements, device metadata (tolerances, baseline), operation state, and logs.
- Networking: lightweight WebSocket server to communicate with browser frontend.
Protocol uses JSON messages (well-typed) and supports streaming telemetry and command/response semantics. - Frontend (React + TypeScript):
UI components for:- Transmission (send actions/scripts),
- Reception (receive backend state),
- Diagnostics (show sensors, tolerances, logs).
- Demo subsystem: software-only simulator to generate semi-realistic device telemetry and sensor noise to exercise the full pipeline.
Requires: C++17/C++20 compiler (GCC 10+/Clang 11+/MSVC 2019+), CMake >= 3.16, and a websocket library (the codebase references WebSocket++ or Boost.Beast; the provided skeleton uses a lightweight ASIO-based placeholder).
Below are step-by-step instructions for common developer and operator flows.
-
Start backend in Simulator Mode (recommended for frontend/dev)
cd backend mkdir -p build && cd build cmake .. -DCMAKE_BUILD_TYPE=Debug cmake --build . -- -j$(nproc) # start in simulator mode (auto-loads shared/protocol/DeviceGraph.json) ./StoneLab --sim
Notes:
- By default, simulator mode loads
shared/protocol/DeviceGraph.jsonandshared/protocol/ComponentSchema.json. You can switch to a toolkit-provided protocol by settingshared/config/protocol.json(restart required). - The
PhysicsEnginecomputes derived properties (temperature, noise coeff) from controller states;
SimulatedDeviceconsults the engine when producing measurements. - To produce deterministic outputs for debugging, use the
test_simulatorbinary with a fixed seed (see "Unit tests" below).
Switch protocol (next startup):
# core protocol python3 ../tools/toolbox_python/stonegate_toolbox_client.py --ws ws://localhost:8080/status protocol.set core # StoneQC protocol python3 ../tools/toolbox_python/stonegate_toolbox_client.py --ws ws://localhost:8080/status protocol.set StoneQC # Preferred (rebranded) entrypoint (wrapper around the same client): # python3 ../tools/toolbox_python/stonelab_toolbox_client.py --ws ws://localhost:8080/status protocol.set core
- By default, simulator mode loads
-
Start backend against real instruments (hardware mode).
Prerequisites:- Install required device drivers / vendor SDKs and verify hardware visibility (lsusb, ip link, etc.).
- Edit
shared/protocol/DeviceGraph.jsonso nodes map to real device identifiers and parts inPartsLibrary.jsonorshared/protocol/user_parts.json. - Ensure
backendprocess can read/writeshared/protocol(for device overrides and user parts persistence). Start the backend in hardware mode:
cd backend/build ./StoneLab # or with explicit port: ./StoneLab 9001
Notes:
- In hardware mode the backend will attempt to instantiate real device driver classes (registered in
main.cpp).
If a driver initialization fails, check system permissions, device paths, and driver logs. - Use the frontend Manual Control dialog (or the stdin control hook in
main.cppduring development) to send control messages.
-
Unit tests and CI-less tests
Build and run the CI-less tests (recommended; no GoogleTest dependency required):
cd backend && mkdir -p build && cd build cmake .. -DCMAKE_BUILD_TYPE=Debug cmake --build . -- -j$(nproc) ./phys_engine_citest ./devices_citest ./simulator_citest
Notes on GoogleTest:
- To enable GoogleTest-based tests, configure
cmakewith-DBUILD_TESTS=ONand ensure a compatible GTest build is available. - If you see undefined references to a prebuilt
libgtest, prefer building GTest from source for ABI compatibility.
- To enable GoogleTest-based tests, configure
cd frontend
pnpm install # or npm install
pnpm dev # or npm run devOpen the URL printed by Vite (typically http://localhost:5173). The frontend will connect to ws://localhost:8080/status by default.
Notes:
- The frontend WebSocket default is
ws://localhost:8080/status(matches backend--sim). If you run the backend in hardware/default mode (port 9001), setVITE_BACKEND_WS_URL='ws://localhost:9001/status'before starting the frontend. If you change the endpoint in the UI, it is persisted inlocalStorageunderstonegate.ws_url; use the Connection Panel Reset/Default button to clear the override and return to the build default.
To add a new device (real or simulated):
- Backend:
- Create a new class inheriting from
Device(seePhotonicDetectorDevicefor an example). - Implement all required methods:
id(),type(),descriptor(),read_measurement(),perform_action(). - Register your device in
main.cppor via theSimulatorloader. - For simulation, add your type and properties to
shared/protocol/ComponentSchema.json. - For hardware, implement a driver class and call it from your device.
- Create a new class inheriting from
Action shape (UI + scripts):
- The UI and generated scripts use a generic action payload:
{ "set": { "metric": value, ... } }. - Backend-side, map those generic
setkeys to your device'sperform_action()keys, or accept{set:{...}}directly.
-
Simulator:
- Add your device type and properties to
ComponentSchema.json. - The simulator will auto-load and generate measurements for all properties.
- For custom simulation logic, extend
SimulatedDevice::read_measurement().
- Add your device type and properties to
-
Frontend:
- Update UI components if you want custom display/controls for your device type.
- The default schematic and device panels will show all properties and allow actions defined in the schema.
StoneLab exposes control operations via JSON-RPC over WebSocket.
- Backend (add an RPC method)
- Implement the RPC handler in the backend WebSocket RPC router (see
backend/src/WebSocketServer.cpp). - Choose a stable method name (example:
"devices.list","record.start"). - Return JSON results (and structured errors) consistently.
- Python (add a helper wrapper)
- Prefer adding a small wrapper in
tools/sdk_sources/stonegate_api.py, then regenerate the installable SDK viapython3 tools/generate_stonegate_sdk.py:- Use
await sg.rpc("your.method", params)for raw calls. - Add a typed helper like
async def your_method(...): ...for ergonomics.
- Use
- C++ (add a helper wrapper)
- Prefer adding a method on
stonegate::Clientintools/sdk_sources/stonegate_api.hpp, or callclient.rpc("your.method", params)directly. Then regenerate the SDK headers viapython3 tools/generate_stonegate_sdk.py.
- Device actions (no new RPC needed)
- If it is a per-device control, prefer using the existing
device.actionRPC and send{ "set": {...} }. - Python:
await sg.device_action("device_id", {"set": {...}}) - C++:
client.device_action("device_id", json{{"set", json{{...}}}})
- Testing:
- Add a test in
test_simulator.cppto verify your device loads and produces expected output.
- Add a test in
See Device.hpp and SimulatedDevice.cpp for more documentation and extension points.
More precisely described in docs/Software_Specifications.md. This is just to serve as a quick reference.
We support a "build mode" concept and a parts-library driven simulation so users can swap parts and see realistic physical coupling (e.g., LN2 flow -> temperature -> noise).
How it works (high level):
shared/protocol/PartsLibrary.jsoncontains parts and their specs (thermal conductance, noise coefficients, nominal values).shared/protocol/DeviceGraph.jsonnodes may optionally include apartfield which names an entry in the parts library; otherwise the simulator picks a default part matching the nodetype.- The
Simulatornow registers devices and aPhysicsEnginethat computes derived values (temperature, noise coefficients) from controller states (e.g.,flow_rate_Lmin). SimulatedDevice::read_measurement()will be extended to consult the physics engine and apply controller-influenced properties when available.
Build mode UX suggestions (to implement in frontend):
- Enter build mode from the schematic to add/remove parts, drag/drop part versions onto nodes, and wire connections.
- When editing a default (built-in) part, the frontend should prompt to "Save as new part" to avoid overwriting stock parts.
- Allow mapping of readings to controls and derived metrics (e.g., map thermocouple temperature -> LN2 setpoint control loop).
- Allow specifying capture windows, tolerances, and sampling rates per device;
store these as per-device overrides in the
DeviceGraphor a separateUserOverrides.json.
Persistence & safety:
- Default parts (in
PartsLibrary.json) are read-only. User-created or modified parts get saved to a user library (e.g.,parts/user_parts.json). - Device instances in the
DeviceGraphmay includeoverridesthat are persisted separately so the canonical graph remains intact.
Next steps to complete this feature:
- Extend
SimulatedDeviceto accept aPhysicsEngine&and query per-node computed properties each measurement. - Add a small IPC or shared-memory bridge if you want a separate physics worker process (later).
- Build frontend build-mode UI: part browser (from
PartsLibrary+ user parts), drag/drop, wiring to signals/controls. - Add persistence endpoints or file-based saves for user parts and overrides.
Controllers (such as liquid nitrogen cooling) are supported just like devices.
See LN2CoolingControllerDevice for a C++ example.
Add your controller to ComponentSchema.json and register it in main.cpp or via the simulator loader.
The simulator and frontend will auto-detect new controllers and expose their properties and actions.
There is a concise developer quickstart in docs/DEVELOPER.md that shows the expected WebSocket message shapes,
how the frontend hooks (onSelectNode, onOpenDialog) connect to the SchematicCanvas,
and quick steps to run the backend in simulator mode.
This is left as a decision-engine module (frontend/src/errordecision.ts) with pluggable rules —
the codebase includes a small example function with a few heuristics.
IDiagnosticProvider::pollOnce()— implement drivers that read from hardware SDKs or DAQ libraries (NI-DAQmx, serial, Modbus, gRPC bridges, etc.).- WebsocketServer — replace minimal hook with a real server (Boost.Beast, WebSocket++, uWebSockets) that accepts clients and routes JSON messages.
IScriptRunner::runInstruction()— implement concrete runners that call hardware control code (moving probes, toggling relays, scheduling pulse sequences to an AWG or FPGA).- DemoSimulator — extend to simulate additional device behaviors and fault modes
(e.g., integrate with Eigen for linear algebra).
For larger workloads, consider integrating C++ libraries like
qppor linking to Python simulators via IPC. - Error correction logic — real ECC selection depends heavily on available codes (surface code, repetition code, Bacon-Shor). Plug in libraries or proprietary implementations behind an interface.
N/A