Commit Graph
8 Commits
Author SHA1 Message Date
Jean-Pierre MartineauandClaude Fable 5 84caae53f8 P3 rework: the PicoCalc visual language, done properly
The first P3 (a84abf3) ran on the wrong model and its palette never
reached the TUI: MESH_THEME_16 was written in 256-colour cube indices
instead of the 16 VT slots, and the platform theme pick was wired into
the scripted-CLI console while the real rasterizer stayed hardcoded to
truecolor. Replace it end to end:

- theme._VT_SLOTS: the canonical slot->RGB design (conventional hue
  families kept; slots 5/6 become the track/faint slates), MESH_THEME_16
  rewritten against color(0..15) with the VT's bold-as-brightness and
  dim-bank-background rules pinned by tests. /etc/vtrgb + a boot oneshot
  install it (console-font script), OSC fallback when kbd is absent.
- platforms.on_platform: set_platform now re-runs registered bindings,
  so theme, rasterizer and widgets swap implementations once per switch
  and hot paths read module globals - no per-call get_platform().
- The render-boundary fold (theme.fold_text): one str.translate pass
  (NFKD accent folds - the Terminus base has no accented Latin - plus
  symbol stand-ins and the width-padded emoji map), an embedded-SGR
  quantizer for canvas truecolor, and a ?-at-own-width catch-all that
  makes the no-wide-glyph short-circuit true by construction. Applied at
  the only two places every visible byte passes: render_to_ansi and
  MapCanvas.to_ansi_lines.
- ui/fontset.py freezes the installed font's inventory (dumped live);
  the gallery now asserts rendered picocalc ANSI carries no truecolor/
  256-colour SGR and no character outside it - the parity gate the
  first attempt faked by asserting a dataclass field.
- Font build: nine new 6x12 marks (ellipsis, warn, backspace, shift,
  gear, refresh, clock, crosshair, padlock) drawn into donor slots, with
  donor misses now fatal and a keeper canary (donating pi once erased
  Cyrillic pe - shared slot). Table re-dumped on-device: identical to
  fontset.py, 519 = 519.
- Type-based name colouring: registry moved to core/nodetypes (services
  no longer import ui), fed from monitor observations, heard_nodes and
  merge_contacts. Heat gradient quantizes to heat.* steps on picocalc.
- ui/marks.py: the P2-deferred constant relocation - widgets no longer
  drags map_render/mapcanvas/pathgraph for tuples and aliases.
- meshterm specimen: the visual language on one card through the real
  funnels - the on-device acceptance screen (JP's request).
- tools/chat: delivered/no-ack state uses the standard check/query
  marks, not the banned emoji pair.

Verified on the Lyra: font+palette installed, specimen framebuffer
captures in .claude/plans/. 1259 tests green, 13 xfailed (P6 list).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-01 12:48:07 -04:00
Jean-Pierre MartineauandClaude Haiku 4.5 66d728a3b3 Untracked: planning and work-in-progress notes
- .claude/plans/picocalc-platform.md: master plan for dual-platform work (P0–P7)
- .claude/housekeeping.md: parking lot for deferred tasks
- scripts/calculinux-radio-bridge.sh: WIP UART bridge setup (P0 blocker on pinmux)

Keep these checked in so context persists across work sessions.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-08-01 11:37:51 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 077742868a scripts/xiao-radio: PicoCalc XIAO nRF52840 UART radio setup
Complete, reproducible bring-up for giving a PicoCalc (Luckfox Lyra, Calculinux) a
MeshCore radio via a Seeed XIAO nRF52840 + Wio-SX1262 on the Lyra's hardware UART1:

  - README.md    -- parts, wiring, build -> flash -> setup, the why, troubleshooting
  - build-firmware.sh  -- clone + patch MeshCore, build the _usb env, emit the .uf2
  - flash.py           -- flash the .uf2 via the XIAO UF2 bootloader (Win/Linux/Mac)
  - lyra-setup.sh      -- boot-persistent UART1->GP4/GP5 mux service, dialout, profile
  - uart1-mux.py       -- the RK3506 matrix-IO register poke that routes UART1
  - meshcore-uart1.patch -- the two firmware edits (Serial1 bind; I2C off D6/D7)

The two firmware edits are both required: bind the companion to hardware UART1
(Serial1 = D6/D7) instead of USB, and move I2C off D6/D7 (MeshCore maps it there and
sensors.begin() would otherwise seize the UART pins). Also documented in the top-level
scripts/README.md alongside the Calculinux and uConsole-SPI targets.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-31 02:02:48 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 2f75bb597c Add Calculinux one-time setup script
Sequences the full Lyra/PicoCalc bring-up: opkg python packages, the
rtl8xxxu Wi-Fi boot-scan kick (installed verbatim from the working device),
the deploy user, the read-only SSH clone, the venv + editable install with
TMPDIR off the RAM tmpfs, the login PATH, and the console font. Idempotent;
secrets (deploy key, Wi-Fi PSK) are checked for or read from the environment,
never embedded. README documents both scripts and their run order.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 02:18:13 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 b11027ec3d Add Calculinux console-font setup script
Builds, applies, and persists the 512-glyph "meshterm" PSF: Terminus base
+ 256 braille + node/status marks and the list cursor in donor slots +
rounded panel corners aliased onto the square corners. Idempotent; runs
on-device as root against the stock ter-u12n font.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-26 02:17:12 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 e4d0b5d964 Bridge: persist the node's contacts across restarts
pymc_core's ContactStore is memory-only, so every bridge restart forgot
every contact and DMs failed with ERR_CODE_NOT_FOUND until the peer was
heard advertising again. Snapshot the store to contacts.json after every
mutation and reload it at startup, alongside the identity the bridge
already persists.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 22:18:26 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 1b8c84f2dd Bridge: accept modern MeshCore ACKs with extra bytes after the CRC
Newer MeshCore firmware sends discrete ACK payloads longer than 4 bytes
(4-byte CRC first, then extras). pymc_core's AckHandler requires exactly
4 bytes and silently drops them, so DMs sent through the SPI bridge never
show delivery confirmation. Patch process_discrete_ack at bridge startup
to take the leading 4 bytes as the CRC, matching pymc_core's own
path-bundled ACK parsing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 22:07:25 -04:00
Jean-Pierre MartineauandClaude Opus 4.8 22f85e3d51 scripts: add the SPI-radio bridge helper
Expose an SPI-attached MeshCore radio (uConsole AIO, Waveshare HATs) to
MeshTerm over the companion protocol on local TCP. A single stdlib-only
file that is both a plain-text setup menu and the bridge process: it finds
the pymc_core runtime and re-execs the bridge under it, offers run-now /
install-as-a-service / uninstall, and can add a [profiles.bridge] block so
the endpoint shows up in MeshTerm's device picker.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-24 03:32:31 -04:00