NODEDC_MISSION_CORE/plugins/xgrids-k1/README.md

8.9 KiB
Raw Permalink Blame History

XGRIDS / LixelKity K1 plugin

This directory is the package boundary for the first Mission Core device plugin. It now owns the canonical v1alpha2 manifest plugin.manifest.json. The statically linked frontend contribution lives in frontend/ beside the manifest and profiles; its provisioning, acquisition/replay, diagnostics and metrics are separate plugin-owned components. The verified backend implementation is physically isolated in src/k1link/device_plugins/xgrids_k1/.

The v1alpha2 catalog can describe one or more independently profiled models. This manifest currently exposes only xgrids.lixelkity-k1, and the transitional runtime still owns one active model/session at a time. Concurrent model/session routing remains a later supervisor milestone.

The plugin owns:

  • the exact firmware/topology compatibility profiles under profiles/, with strict evidence flags and a fail-closed loader;
  • BLE discovery hints and K1 GATT metadata;
  • Bridge and Direct Connect through the reviewed firmware-3 BLE Wi-Fi provisioning frame, plus the reviewed Quick Connect AP-enable frame and one-shot host-profile association adapter;
  • read-only refresh of the selected K1's session-scoped DHCP address before a new LAN operation; address changes rotate the device session and IP is never treated as device identity;
  • subscribe-only data MQTT transport plus a separately bounded canonical application-control transport;
  • native .k1mqtt capture;
  • the read-only factory-calibration transport: one live DeviceInfo binding, command-5 reads of exactly camera.yaml and extrinsic_camera_lidar.yaml, and append-only private source snapshots; file write and arbitrary paths are unavailable;
  • safe exact-schema normalization of KB4 intrinsics, the main-camera 800x600 resize and explicit T_camera_N_from_lidar matrices, with firmware-verified sensor.camera.left -> camera_0 and sensor.camera.right -> camera_1 binding;
  • firmware-scoped protobuf/LZ4 and legacy codecs;
  • normalization of K1 point cloud and pose, plus raw-only preservation of the still-undecoded status and heartbeat channels;
  • exact-profile left/right RTSP producer selection, H.264 copy-remux preview and the handoff of acquisition-owned init/fMP4/index evidence to the host archive;
  • K1-specific operator instructions and compatibility tests.
  • the scoped React device.connection contribution and its BLE/Wi-Fi and acquisition pipeline UI.
  • the interactive canonical application-control session: one socket owner, one operator launch intent, response-gated workspace/project/START stages, a separate explicit STOP action, live status gates and no automatic retry.

The plugin does not own:

  • Mission Core navigation, fleet, missions, users, roles, or audit;
  • the generic spatial scene or Rerun Web Viewer;
  • the host observation catalog, RRD preparation/cache, recorded-camera player, workspace layout, platform storage, remote transport, or other devices.

The k1link distribution and CLI names remain compatibility names. All device-specific implementation behind them is plugin-owned, and every change must preserve replay and real-device acceptance.

Mission Core imports this plugin only from apps/control-station/src/composition/devicePlugins.ts. The generic shell never branches on this plugin ID or reads k1_ip, BLE candidates, MQTT topics, or other vendor state. The frontend contribution imports the host only through @mission-core/plugin-sdk; its CSS is scoped below .xgrids-k1-plugin.

Backend startup loads the reviewed factory declared by backendEntrypoint, then cross-checks the runtime-owned plugin ID, version, supported host API and exact action set against this manifest. The runtime must complete the versioned control-plane handshake and report ready before any action is admitted. Actions enter through the host dispatcher and the transitional facade src/k1link/device_plugins/xgrids_k1/facade.py. The old flat routes live in the plugin's legacy router; both paths now cross the same runtime transport and delegate to the proven XgridsK1CompatibilityService methods. Synchronous capture/runtime operations run outside the FastAPI event loop.

Model switching calls the plugin deactivation hook. It is rejected while the canonical K1 control socket is open, so navigation can never become an implicit device STOP. Operator-manual acquisition uses semantic acquisition.stop in capture-only mode; replay and pre-v1alpha2 sessions retain the legacy stream.stop shim. BLE, MQTT, codec, archive discovery and RRD export modules now live under the plugin package after replay parity and physical K1 regression. The current transport remains in-process and its health is lifecycle-only; process isolation, crash/restart containment and signed deployment remain later supervisor gates.

The compatibility profile is descriptive and cannot itself authorize a vendor write. The UI selects the exact firmware 3.0.2 local-network profile and an exact topology for Bridge, Quick Connect or Direct Connect; the canonical bootstrap then requires a correlated live DeviceInfo match for model LixelKity K1, platform type A4, activation and firmware before START. Validate the current exact-match profile without device I/O with:

uv run python plugins/xgrids-k1/profile_loader.py

Plugin v0.6.0 retains the physically accepted v0.5.0 control transport and adds the connection matrix behind the existing explicit network.provision action. Bridge remains the default. Direct Connect sends the same single reviewed 99-byte frame with credentials for an already-running controller hotspot. Quick Connect accepts no browser/API credential: it sends one reviewed fixed 100-byte AP-enable frame to the selected K1, waits up to 15 seconds for the canonical byte-51 AP-ready flag, and keeps that BLE session alive while the macOS adapter performs bounded exact-SSID CoreWLAN discovery and one association. Credentials are resolved by a preinstalled exact 3.0.2 firmware provider. Its optional laboratory importer validates the reviewed official archive, extracts the single AP declaration and installs firmware-scoped material in the OS secure store. The macOS helper then materializes the selected device profile entirely inside Keychain before any BLE write. The secret never enters the browser, API, argv, logs or evidence; the importer's short-lived mutable buffer is zeroized after the stdin handoff. There is no automatic BLE-write or association retry. A clean host cannot obtain the provider from BLE and the product does not download firmware during connection. Windows/Linux Quick Connect adapters are not planned while that bootstrap remains unresolved. Mission Core then uses the reviewed K1 AP data-plane address. The 99-byte station-provisioning payload and 100-byte AP-enable payload share 7f01 but remain distinct exact reviewed frames; neither is a credential-read command.

For retained laboratory reproduction only, an operator can install the reviewed source on a macOS host without displaying the credential:

uv run k1link authority import-k1-fw302-ap \
  --firmware /private/path/to/the-official-3.0.2-archive.tar \
  --confirm-reviewed-firmware

The 2026-07-20 UI run physically accepted the prepared-host path: one BLE discovery, one AP-enable write, AP-ready, one CoreWLAN association, control bootstrap and the normal acquisition lifecycle. It does not prove that the current build is portable to a clean Mac. Bridge/direct-LAN remains the default and continuing product route; Quick Connect stays available as laboratory functionality.

Plugin v0.5.0 installed the reviewed application-control transport behind explicit plugin actions. The normal UI accepts the project name and one explicit launch confirmation. It then performs operations 16, operation 7 and operations 810 only after the previous response barrier succeeds, prepares local reception, and emits one START carrying the project name. Local state polling controls only when the next reviewed action may be requested; it never schedules a device command by elapsed time. START waits for bound SCANNING + project + init_ready before operations 1314. STOP is separately permitted, never retried, and keeps the same socket until K1 reports unbound READY. That protocol state automatically completes local sealing; stable green is physical corroboration rather than a second UI gate. No physical command is emitted merely by loading the plugin, opening the page, navigating, polling state or running repository tests. The full v0.5.0 START/live/STOP/save path is physically accepted on the reviewed K1/A4/FW 3.0.2 unit.

The optional owner-controlled iPhone/LixelGO observation tool lives under lab/iphone-capture/. It pins pymobiledevice3 in a separate uv environment, writes only ignored evidence sessions, and remains a lab subprocess rather than a plugin/runtime dependency. The first capture is gated by ADR 0004 and ADR 0005.