Serial Studio — new I/O driver
Before writing anything, read core/Devices/IO/Drivers/BluetoothLE.h and BluetoothLE.cpp in
full. They are the canonical reference for the driver contract — match their structure,
signal/slot wiring, and driverProperties() shape rather than inventing a new layout. After
the read, restate the driver contract in chat in 2-3 sentences (pure virtuals, publish path,
timestamp-at-boundary) before scaffolding — a contract you've just named is one the new code
follows, not one it drifts from (doc/claude/j-space.md).
A driver subclasses IO::HAL_Driver (core/Core/IO/HAL_Driver.h) and must implement the pure
virtuals: close, isOpen, isReadable, isWritable, configurationOk, write, open,
driverProperties, and setDriverProperty. Also consider the non-pure virtuals with default
bodies — deviceIdentifier(), selectByIdentifier(), applyConnectionSettings() — which
drive device selection and reconnection. Received bytes are published via
publishReceivedData(...) — stamp the timestamp at the driver boundary (source owns time;
see [ss-hotpath]). Never re-stamp downstream.
Touch-points to wire (verify each against an existing driver)
core/Devices/IO/Drivers/<Name>.h / .cpp — the driver class, SPDX header, .h ordering rules.
core/Core/SerialStudio.h — add the value to the BusType enum (QML uses SerialStudio.BusType.*,
never integer literals).
core/Devices/IO/ConnectionManager.{h,cpp} — accessor (e.g. network() / uart() analogue)
plus signal forwarding; the bus lookups live in ConnectionManager/DriverUiRegistry.cpp
(forBusType()) and the live-instance switch in ConnectionManager/DriverFactory.cpp
(DriverFactory::create(), spec 0070). Update both.
core/Devices/CMakeLists.txt — add IO/Drivers/<Name>.cpp to the source list (sources are
listed explicitly, not globbed; commercial drivers go in the guarded
if(BUILD_COMMERCIAL) block).
- QML configuration UI — the driver panes are bespoke forms (only the Project Editor renders
driverProperties() generically; a row one mode does not use stays in the list and carries a
visibleWhen rule, never a conditional append, because the list is also what a project
persists): create
app/qml/MainWindow/Panes/SetupPanes/Drivers/<Name>.qml, add its Loader to the
StackLayout in SetupPanes/Hardware.qml at the bus's enum position (the layout
indexes by Cpp_IO_Manager.busType), and register the new .qml in the QML_SOURCES list
in app/CMakeLists.txt.
core/Core/EnumLabels.cpp — add the bus to the busTypeSlug() and busTypeLabel()
switches (the API's string names for the bus; commercial buses go inside the
#ifdef BUILD_COMMERCIAL block).
core/Ui/ProjectEditor/ProjectEditorIcons.h — add the bus to the busTypeIcon()
switch, and core/Ui/ProjectEditor/EditorForms.cpp — add it to the busTypes
combobox list in the source form model.
- Icon — add the driver SVG under
app/rcc/icons/devices/<tier>/ (16/24/32) and register it with a
<file> entry in app/rcc/rcc.qrc (busTypeIcon() returns its qrc:/ path).
- CLI (optional) — if it should be launchable headless, add options in
app/src/Misc/CLI.{h,cpp}
following the existing setupUartConnection / setupTcpConnection pattern.
tests/utils/api_client.py (optional) — add the bus to bus_map if integration tests should
reach it via io.setBusType (known drift: mqtt is missing from it today).
The list above drifts as the app grows. Before declaring done, grep a recently added bus value
(e.g. grep -rn "BusType::HidDevice" app/src core) and mirror every switch/list it appears in.
Rules
- This is a multi-file change (>3 files): state the plan and get confirmation before executing.
- Follow
doc/claude/code-style.md (header ordering, [[nodiscard]], no in-header member init,
Q_EMIT not emit, Christmas-tree ordering).
- Run
python scripts/code-verify.py --check on the new files before handoff.
- Do not build or run the app — leave compilation and runtime testing to the developer.
1---2name: ss-new-driver3description: Scaffold a new Serial Studio I/O driver (a new data source under core/Devices/IO/Drivers/). Use when adding support for a new bus/transport — e.g. "add a <X> driver", "support reading from <Y>", "new data source". Encodes the canonical driver pattern and every registration touch-point so the new driver actually shows up in the UI, CLI, and connection manager.4---56# Serial Studio — new I/O driver78**Before writing anything, read `core/Devices/IO/Drivers/BluetoothLE.h` and `BluetoothLE.cpp` in9full.** They are the canonical reference for the driver contract — match their structure,10signal/slot wiring, and `driverProperties()` shape rather than inventing a new layout. After11the read, restate the driver contract in chat in 2-3 sentences (pure virtuals, publish path,12timestamp-at-boundary) before scaffolding — a contract you've just named is one the new code13follows, not one it drifts from (`doc/claude/j-space.md`).1415A driver subclasses `IO::HAL_Driver` (`core/Core/IO/HAL_Driver.h`) and must implement the pure16virtuals: `close`, `isOpen`, `isReadable`, `isWritable`, `configurationOk`, `write`, `open`,17`driverProperties`, and `setDriverProperty`. Also consider the non-pure virtuals with default18bodies — `deviceIdentifier()`, `selectByIdentifier()`, `applyConnectionSettings()` — which19drive device selection and reconnection. Received bytes are published via20`publishReceivedData(...)` — **stamp the timestamp at the driver boundary** (source owns time;21see [ss-hotpath]). Never re-stamp downstream.2223## Touch-points to wire (verify each against an existing driver)24251. `core/Devices/IO/Drivers/<Name>.h` / `.cpp` — the driver class, SPDX header, `.h` ordering rules.262. `core/Core/SerialStudio.h` — add the value to the `BusType` enum (QML uses `SerialStudio.BusType.*`,27 never integer literals).283. `core/Devices/IO/ConnectionManager.{h,cpp}` — accessor (e.g. `network()` / `uart()` analogue)29 plus signal forwarding; the bus lookups live in `ConnectionManager/DriverUiRegistry.cpp`30 (`forBusType()`) and the live-instance switch in `ConnectionManager/DriverFactory.cpp`31 (`DriverFactory::create()`, spec 0070). Update both.324. `core/Devices/CMakeLists.txt` — add `IO/Drivers/<Name>.cpp` to the source list (sources are33 listed explicitly, not globbed; commercial drivers go in the guarded34 `if(BUILD_COMMERCIAL)` block).355. QML configuration UI — the driver panes are bespoke forms (only the Project Editor renders36 `driverProperties()` generically; a row one mode does not use stays in the list and carries a37 `visibleWhen` rule, never a conditional append, because the list is also what a project38 persists): create39 `app/qml/MainWindow/Panes/SetupPanes/Drivers/<Name>.qml`, add its `Loader` to the40 `StackLayout` in `SetupPanes/Hardware.qml` **at the bus's enum position** (the layout41 indexes by `Cpp_IO_Manager.busType`), and register the new .qml in the `QML_SOURCES` list42 in `app/CMakeLists.txt`.436. `core/Core/EnumLabels.cpp` — add the bus to the `busTypeSlug()` and `busTypeLabel()`44 switches (the API's string names for the bus; commercial buses go inside the45 `#ifdef BUILD_COMMERCIAL` block).467. `core/Ui/ProjectEditor/ProjectEditorIcons.h` — add the bus to the `busTypeIcon()`47 switch, and `core/Ui/ProjectEditor/EditorForms.cpp` — add it to the `busTypes`48 combobox list in the source form model.498. Icon — add the driver SVG under `app/rcc/icons/devices/<tier>/` (16/24/32) and register it with a50 `<file>` entry in `app/rcc/rcc.qrc` (`busTypeIcon()` returns its `qrc:/` path).519. CLI (optional) — if it should be launchable headless, add options in `app/src/Misc/CLI.{h,cpp}`52 following the existing `setupUartConnection` / `setupTcpConnection` pattern.5310. `tests/utils/api_client.py` (optional) — add the bus to `bus_map` if integration tests should54 reach it via `io.setBusType` (known drift: `mqtt` is missing from it today).5556The list above drifts as the app grows. Before declaring done, grep a recently added bus value57(e.g. `grep -rn "BusType::HidDevice" app/src core`) and mirror every switch/list it appears in.5859## Rules6061- This is a multi-file change (>3 files): state the plan and get confirmation before executing.62- Follow `doc/claude/code-style.md` (header ordering, `[[nodiscard]]`, no in-header member init,63 `Q_EMIT` not `emit`, Christmas-tree ordering).64- Run `python scripts/code-verify.py --check` on the new files before handoff.65- Do not build or run the app — leave compilation and runtime testing to the developer.