# Salmanoff on Ubuntu Core — Plan (derived from Yocto work) ## Purpose of this document This plan is **not** a translation of an original Yocto design doc. It reflects **what we actually built and validated** in the Yocto path, reframed as goals for Ubuntu Core. Use it as primary context when scaffolding snaps, gadget/model, and dev VM workflow. When done, snap definitions and support files land in the SMO repo under: ``` smo/distro/ubuntuCore/ ``` (parallel to the existing `smo/distro/yocto/meta-salmanoff/`). --- ## What we proved in Yocto (facts, not aspirations) We shipped a **minimal headless image** that runs the Salmanoff (SMO) cognitive robotics runtime on **QEMU x86-64**, bridged onto a lab LAN, talking to a **Livox LiDAR** on a fixed IP. ### Lab network (canonical — carry forward unchanged) | Host | IP | Role | |---|---|---| | Laptop / gateway | `10.42.0.1` | Gateway + DNS | | RPi5 (production target) | `10.42.0.2` | Future production node | | **Dev guest (QEMU / UC VM)** | **`10.42.0.16`** | SMO dev runtime | | Livox Avia | `10.42.0.139` | LiDAR sensor | ### Runtime configuration we validated - **Body file**: `yocto-qemu-x86-headless.dapss` — Livox-only, headless (no win0/camera), `smo-ip=10.42.0.16`, includes `avia0.dapss`. - **SMO build profile** (CMake): - `RelWithDebInfo` - `ENABLE_LIB_lcameraDev=ON`, `ENABLE_STIMBUFFAPI_lcameraBuff=ON` (libcamera + OpenCL YUV path compiled in; no camera passthrough needed in QEMU) - `ENABLE_LIB_xcbXorg=OFF`, `COMPILE_PCL_TOOLS=OFF`, `ENABLE_TESTS=OFF`, `ENABLE_LCAMERADEV_TOOLS=OFF` - Git submodules required (`libspinscale`, etc.) - **Runtime command shape** (approximate): ```bash salmanoff -d /usr/share/salmanoff/devices/bodies/body_yocto_qemu_x86_headless.daps -p /usr/lib -v ``` (exact installed `.daps` filename follows DAPSS build output naming) ### Platform services / packages we pulled into the image | Need | What we used in Yocto | |---|---| | SMO runtime + libs | `salmanoff` recipe (`libspinscale`, `liblcameraDev`, `liblcameraBuff`, `liblivoxGen1`, …) | | Boost | Pinned **1.86** (shared `boost-system`; must stay **< 1.89**) | | liburing | Runtime dep | | libcamera + v4l-utils | Present on image; camera optional at runtime | | OpenCL | Mesa Rusticl via `opencl` distro feature; **needs `RUSTICL_ENABLE=llvmpipe`** or platform shows 0 devices | | OpenCL verify | `clinfo` (also discovered **256M RAM OOMs** OpenCL probe — use **≥ 2G** for dev VM) | | Network | Static `eth0`: `10.42.0.16/24`, gw `10.42.0.1` | | Dev access | SSH (openssh on Yocto image) | | Kernel probe | `rseqsliceprobe` + kernel config append for rseq slice extension | | QEMU dev | Host bridge `br-smo`, `runqemu` with `bridge=br-smo`, `nographic`, `-m 2048` | ### Repo / packaging decisions already made in SMO - Yocto layer vendored at `smo/distro/yocto/meta-salmanoff/` (committed on `clast`). - SMO source changes on `clast`: headless body, flex/bison repo-relative `#line` paths, etc. - Fetch uses private Gitea (`hayodea/salmanoff`, branch `clast`, submodules via `libspinscale` on separate SSH host alias). --- ## Conceptual goals (portable to Ubuntu Core) These are the **intent** items — independent of BitBake: 1. **Repeatable dev environment** — headless guest on `10.42.0.16`, reachable from laptop, Livox at `10.42.0.139`. 2. **SMO as first-class payload** — not “install deps manually”; runtime + `.daps` bodies + plugin `.so`s packaged and startable. 3. **Same CMake feature profile** as Yocto (lcamera + OpenCL enabled; xcb/PCL tools off). 4. **OpenCL that actually works headless** — Rusticl/llvmpipe with env var set before SMO starts. 5. **libcamera stack present** — libraries available even when no camera device is passed through (QEMU/UC dev). 6. **Boost version constraint honored** — do not silently pick Boost ≥ 1.89. 7. **Production path to RPi5** — same snap(s), different body/IP (`10.42.0.2`), gadget/kernel for Pi hardware. 8. **Distro metadata lives in SMO** — `distro/ubuntuCore/` committed back into SMO when stable (mirrors Yocto layout). --- ## Yocto → Ubuntu Core mapping | Yocto (what we did) | Ubuntu Core (target) | |---|---| | `meta-salmanoff/` layer | `distro/ubuntuCore/` — snaps, gadget, model, helper scripts | | `salmanoff-image.bb` | **Model assertion** + `core` + gadget snap + app snaps on seeded image | | `salmanoff.bb` recipe | **`salmanoff` snap** (`snapcraft.yaml`: cmake build, submodules, organize libs + daps) | | `IMAGE_INSTALL` | Snap `stage-packages` / parts / content snaps (`mesa`, libcamera deps) | | `salmanoff-rusticl-env` recipe | Snap `environment:` block or wrapper script: `RUSTICL_ENABLE=llvmpipe` | | `init-ifupdown` static IP | **Netplan** via gadget default config, `network-setup` snap, or `system-connections` on UC | | `runqemu-salmanoff-bridge` | **Dev VM script**: UC image in QEMU/LXD/multipass on `br-smo`, static `10.42.0.16`, 2G RAM | | `DISTRO_FEATURES += opencl` | Ensure Mesa/OpenCL ICD available to snap (layout + plugs or bundled libs) | | `DEPENDS` / `RDEPENDS` | Snapcraft `build-packages`, `stage-packages`, `slots`/`plugs`, `layout:` for `/usr/lib` ICD paths | | `gitsm://` + `SRCREV` | Snapcraft `source` + `source-submodules` or `override-pull` git submodule update | | `yocto-qemu-x86-headless.dapss` | Installed by salmanoff snap; UC-specific body can be `ubuntu-core-x86-headless.dapss` later | | `rseqsliceprobe` | Validate UC kernel/base; custom kernel snap only if probe fails on stock UC kernel | | SSH on image | UC: serial console, `ssh-keys` in model, or dedicated snap — **don’t assume openssh like Yocto** | | Boost 1.86 pin | Pin in snapcraft (`stage-packages` version) or build Boost part from source | | `RelWithDebInfo` + debug maps | Snapcraft `override-build` cmake flags; consider `debug` snap or stripped separate artifact | --- ## Proposed Ubuntu Core architecture ``` Host (10.42.0.1) └── bridge br-smo (10.42.0.0/24) └── UC dev VM / RPi5 (10.42.0.16 or .2) ├── snap: core (or core24) ├── snap: gadget- (boot, partitions, default netplan) ├── snap: salmanoff (daemon — main payload) └── optional: mesa-support / libcamera-support content snaps if not bundled ``` ### `salmanoff` snap (primary deliverable) **Type**: likely `daemon` (simple) or `daemon` (notify) once startup semantics are known. **Build** (mirror Yocto recipe intent): - Source: SMO repo `clast` (submodules!) - CMake options: same as Yocto `EXTRA_OECMAKE` block - Install: `salmanoff` binary, `lib*.so*`, `/usr/share/salmanoff/devices/**` - Apps: main daemon + optional `salmanoff.probe` for debugging **Runtime environment**: ```yaml environment: RUSTICL_ENABLE: llvmpipe ``` **Interfaces to evaluate early** (exact set TBD by confinement testing): - `network` / `network-bind` — Livox UDP/TCP to `10.42.0.139` - `hardware-observe` — may be needed for camera discovery on Pi - `camera` — for libcamera on production Pi - `opengl` — if Mesa GL stack needed beyond OpenCL ICD - `raw-usb` / `serial-port` — only if Livox path requires it on some platforms - `home` — usually **avoid**; use `$SNAP_DATA` for state **Layouts** (likely needed): - OpenCL ICD loader expects `/etc/OpenCL/vendors` or known `LD_LIBRARY_PATH` - May need `layout:` bind mounts for Mesa `libRusticlOpenCL.so` / gallium stack ### Platform snaps | Platform | Gadget | Notes | |---|---|---| | **QEMU x86 dev** | `pc` or custom gadget | Static IP `10.42.0.16`, 2G RAM, bridged NIC | | **RPi5 production** | `pi` gadget (22+ arm64) | Static IP `10.42.0.2`, libcamera, Livox | ### Bodies / config - **Dev (UC VM)**: start from Yocto body or add `ubuntu-core-x86-headless.dapss` with same Livox-only intent and `smo-ip=10.42.0.16`. - **Production (RPi5)**: reuse/adapt existing `rpi5-persys-headless.dapss` pattern with `smo-ip=10.42.0.2`. Body files stay in SMO `devices/bodies/`; snap selects default via config or snap config hook. --- ## Phased plan (recommended order) ### Phase 0 — Repo scaffold - [ ] New repo (or `distro/ubuntuCore/` in SMO) with `snapcraft.yaml` skeleton - [ ] Document lab IP table and bridge prerequisites (port `runqemu-salmanoff-bridge` concepts) - [ ] Link to SMO `clast` branch + submodule SSH host requirements ### Phase 1 — Build snap on host (no hardware) - [ ] `snapcraft` / `craft` builds SMO with same CMake profile as Yocto - [ ] Confirm submodule pull (`libspinscale`) in clean CI/local environment - [ ] Resolve Boost < 1.89 (stage-package pin or source part) - [ ] Package `.daps` + shared libs; verify `salmanoff -v` / dry-run in snap run environment ### Phase 2 — OpenCL + libcamera in confinement - [ ] Replicate Yocto OpenCL stack inside snap (bundled vs system Mesa) - [ ] Confirm `RUSTICL_ENABLE=llvmpipe` → `clinfo` shows ≥1 device **inside snap** - [ ] Confirm `liblcameraDev` / `liblcameraBuff` load; no crash without camera device - [ ] Document RAM requirement (≥ 2G for dev VM) ### Phase 3 — UC dev VM on lab LAN - [ ] Boot Ubuntu Core x86 VM bridged to `br-smo` - [ ] Static IP **10.42.0.16** (netplan/gadget) - [ ] Install seeded `salmanoff` snap (devmode first, then strict) - [ ] Ping gateway; reach Livox at `10.42.0.139` - [ ] Run headless body; validate Livox traffic / SMO logs ### Phase 4 — Production path (RPi5) - [ ] Model assertion for Pi5 + arm64 core - [ ] Gadget with `10.42.0.2` netplan - [ ] libcamera plug + Pi body file - [ ] OTA refresh via snap channels ### Phase 5 — Commit back to SMO - [ ] Move stable `distro/ubuntuCore/` into SMO repo - [ ] Commit on `clast` (or dedicated branch); do **not** block on unfinished WIP snaps --- ## Known constraints & pitfalls (from Yocto — expect repeats) 1. **OpenCL**: platform visible but **0 devices** until `RUSTICL_ENABLE=llvmpipe`. 2. **Memory**: 256M insufficient for Rusticl/`clinfo`; use **2G** for dev VM. 3. **Boost**: must stay **< 1.89** (shared `boost-system` linkage). 4. **Submodules**: `libspinscale` is mandatory; fetch must be recursive; separate SSH host alias on Gitea. 5. **lcamera without hardware**: compile and ship libs; no QEMU camera passthrough required for basic bring-up. 6. **PCL / xcb**: keep off unless explicitly needed (MPI/cmake pain in Yocto). 7. **Private git**: snapcraft build needs SSH keys / credentials for Gitea fetch (or vendored source tarball part). 8. **Strict confinement**: biggest unknown vs Yocto — plan devmode → strict iteration; interfaces will take multiple passes. 9. **rseq kernel feature**: validate on UC base; custom kernel snap is expensive — only if probe fails. --- ## Success criteria (match Yocto milestone) Minimum “we’re at parity” for UC dev: - [ ] UC VM at `10.42.0.16` on `10.42.0.0/24` via host bridge - [ ] `salmanoff` snap installed and daemon running (or manual `snap run` equivalent) - [ ] Headless Livox body loaded; SMO stable with Livox on `10.42.0.139` - [ ] OpenCL initialized (llvmpipe); lcamera libs present - [ ] Snap definitions committed under `smo/distro/ubuntuCore/` Stretch (production): - [ ] Same snap on RPi5 at `10.42.0.2` with Pi-appropriate body --- ## Explicit non-goals (for now) - Re-implement Yocto layer / BitBake in UC repo - Camera passthrough in QEMU/UC x86 dev - PCL tools / xcb window stack - lcameraDev probe tools (need test support libs — off in Yocto too) - Full OTA/signing production pipeline (Phase 4+) --- ## Reference: Yocto artifacts in SMO repo When unsure, read the working Yocto implementation: ``` smo/distro/yocto/meta-salmanoff/ conf/layer.conf conf/salmanoff-local.inc # opencl distro feature recipes-salmanoff/salmanoff/salmanoff.bb recipes-core/images/salmanoff-image.bb recipes-core/init-ifupdown/... # 10.42.0.16 static IP recipes-support/salmanoff-rusticl-env/ scripts/runqemu-salmanoff-bridge smo/devices/bodies/yocto-qemu-x86-headless.dapss ``` SMO branch: **`clast`** on `hayodea/salmanoff` (Gitea). --- ## Instructions for the LLM in the Ubuntu Core repo 1. **Treat Yocto work as validated reference**, not something to re-derive from scratch. 2. **Preserve lab IP plan and CMake profile** unless user says otherwise. 3. **Start with snapcraft build on host**, then UC VM, then strict confinement — same order we used (build → package QA → runtime). 4. **Plan for `distro/ubuntuCore/` in SMO** as the final home of snaps/gadget/model/scripts. 5. **Ask before** committing snaps into SMO; user will commit when done. 6. **Do not** assume UC has openssh or classic Ubuntu package management — everything is snaps + interfaces.