Commit Graph
34 Commits
Author SHA1 Message Date
Torlando 9591d8074c fix: make install-marker renewal ownership-checked
Greptile round 9 remediation:

The round-8 heartbeat rewrote the marker unconditionally. If
installer A stalled on a single tile operation for longer than the
marker TTL, installer B could legitimately reclaim the expired
marker, and A's next heartbeat then overwrote B's live claim --
stealing the card out from under a running install.

The renewal now reads the marker before rewriting and only
proceeds when it still carries OUR owner (the same owner comparison
used by release and commit-time verification). A reclaimed,
deleted, or corrupt marker means the claim is void: the install
aborts with a clear "wait for the other installer to finish and
retry" error, leaving the foreign claim intact. The partially
published pack stays device-harmless (no record names it) and the
user retries once the other installer finishes.

- CLI: _renew_install_marker() checks owner before rewriting;
  PackError aborts the install (the existing cleanup paths remove
  the staged temp pack and release the marker as a no-op).
- Flasher: renewInstallMarker() checks owner before rewriting;
  fail() aborts the install (the existing cleanup paths remove the
  owned pack and release the marker as a no-op).
- Tests: CLI 88 (renewal refuses to steal a reclaimed/missing/
  corrupt claim; same-owner renewal still advances the epoch);
  flasher 26 (same contract).
2026-08-29 19:17:08 +00:00
Torlando b3c9b4d1db fix: renew the install marker during long map publications
Greptile round 8 remediation:

The install marker was written once at install start. A publication
longer than the 15-minute TTL (a full world pack on slow SD storage)
aged out while its installer was still live; a second producer then
reclaimed the marker and both producers passed commit-time
revalidation against the same activation state.

Both producers now renew the marker's epoch during tile publication
(every 25 tiles plus one final renewal), keeping the claim live for
arbitrarily long installs while a crashed installer (no renewals) is
still reclaimed after the TTL. Release and commit-time marker checks
compare the owner, not the full token, so a renewed marker is still
recognized as ours and a foreign owner is never deleted by mistake.

Adds regression tests on both sides: CLI renewal count + owner-based
release, CLI crashed-marker still reclaimable, and the flasher
renewal contract (epoch advances, owner preserved).

CLI: 87 passed. Flasher: 25 passed.
2026-08-29 18:33:36 +00:00
Torlando affd5566ab fix: coordinate CLI and flasher map installs with a shared marker
Greptile round 7 remediation:

The CLI's advisory flock and the web flasher's Web Locks name live in
incompatible lock namespaces, so a CLI install and a browser install
on the same card could each hold "their" lock, both pass preflight on
identical slot state, and clobber each other's records (orphaning a
pack, or writing the same generation into two slots).

Both producers now share two symmetric layers:

1. An on-disk install marker (.pyxis-installing in pyxis-map/,
   token "PYXI 1 <owner> <epoch_ms>") claimed at install start via an
   atomic exclusive create, with ownership verified by read-back. A
   fresh foreign marker refuses the install before any mutation; a
   stale one (30-minute TTL; a future epoch counts as fresh under
   clock skew) is reclaimed. Release only deletes the releasee's own
   token.
2. Commit-time revalidation: activate_map_set / activateMapSet
   snapshot the raw slot and style bytes at derivation, re-read them
   immediately before the record writes, and abort if the activation
   state moved or a fresh foreign marker is present. The published
   pack is kept (device-harmless: the firmware only reads packs named
   by an active selection) and the existing retry/resume path
   converges it.

Regression tests on both producers: marker refusal before any
publication, stale-marker reclamation and release, and
commit-time-race abort with retry convergence. The in-memory flasher
FS now models getFileHandle({exclusive:true}) -> FileExistsError.

CLI: 85 passed. Flasher: 24 passed.
2026-08-29 17:54:27 +00:00
Torlando 30c0d73565 fix(flasher): fully validate PNG tiles before publish 2026-08-20 05:00:06 +00:00
Torlando ca5d582588 fix(flasher): install indexless map archives 2026-08-20 04:53:01 +00:00
torlando-agent[bot] 78300b00ee Merge origin/main into feat/map-style-picker 2026-08-12 18:22:33 +00:00
torlando-agent[bot] 9b7ab160ad fix: keep stable firmware as flasher default 2026-08-12 17:40:55 +00:00
torlando-agent[bot] 6627c9ccbb fix: improve flasher release selector contrast 2026-08-12 17:30:18 +00:00
torlando-agent[bot] acfddc4c54 fix: show prereleases in web flasher 2026-08-12 17:13:42 +00:00
torlando-agent[bot] c1a27fdf08 fix: version local map installer module 2026-08-08 16:21:18 +00:00
torlando-agent[bot] 06f477e771 fix: refresh map installer archive identity 2026-08-08 16:19:13 +00:00
torlando-agent[bot] 66f551515f feat: add offline map style switcher 2026-08-08 15:21:42 +00:00
torlando-agent[bot] 62509e0be8 docs: add guided offline map install steps 2026-08-07 21:27:15 +00:00
torlando-agent[bot] 924d24f10b fix: serialize map installs across browser tabs 2026-08-07 20:04:53 +00:00
torlando-agent[bot] c0abc5758c fix: preserve concurrent empty map directories 2026-08-07 17:19:09 +00:00
torlando-agent[bot] 49fa03ba68 feat: add composable offline map packs 2026-08-07 16:58:14 +00:00
torlando-agent[bot] 117d3894bd feat: make maps SD-pack only 2026-08-07 05:26:34 +00:00
torlando-agent[bot] 525ab5022d [verified] feat: build secure offline map packs 2026-08-07 03:27:18 +00:00
torlando-agent[bot] 299fd4af02 fix: align telemetry with pinned field semantics 2026-08-07 01:23:08 +00:00
torlando-agent[bot] 1c5c887e57 docs: plan map and location sharing v2 2026-08-07 01:23:08 +00:00
Torlando e6ee0a57e5 fix: close recovery and file-selection races 2026-08-02 23:30:40 +00:00
Torlando 9c0997befa fix: make firmware updates persistence-safe 2026-08-02 23:06:44 +00:00
torlando-agent[bot] 86325ff178 docs: clarify ULBW-only call profile 2026-08-02 02:42:38 +00:00
torlando-agent[bot] c2c6ae5641 fix(voice): synchronize call termination and TCP announces 2026-08-01 21:32:01 +00:00
torlando-tech 48382b2f9f feat: T:SCREENSHOT + T:SHOW serial commands + host-side capture
New testing/docs surface for grabbing the active LVGL screen as a
PNG over USB-CDC. Useful both for documentation (round-trip capture
of every public screen via T:SHOW <name> + T:SCREENSHOT) and
automated UI regression tests.

On-device:
  - lib/lv_conf.h — enable LV_USE_SNAPSHOT (~5 KB code; uses PSRAM
    via the existing hybrid allocator so internal RAM is unaffected)
  - src/main.cpp — T:SCREENSHOT handler takes an lv_snapshot_take()
    of lv_scr_act() under LVGL_LOCK(), dumps a delimited base64
    stream over CDC. Inlines a tiny base64 encoder (no new dep).
  - src/main.cpp — T:SHOW <name> dispatches to UIManager::show_*()
    for the six publicly-navigable screens (conversation_list,
    compose, announces, status, settings, propagation_nodes).

Wire format:
  T:SCREENSHOT BEGIN W=320 H=240 FMT=rgb565<be|le> BYTES=153600
  <base64 line, 76 chars>
  ...
  T:SCREENSHOT END

Host side:
  - screenshot.py — auto-detects the pyxis port via T:ID probe,
    sends T:SCREENSHOT, reads until END, filters out interleaved
    log lines (heap heartbeats / BLE stats can splice in
    mid-dump), validates byte count matches header, decodes RGB565
    with the documented byte order, expands channels via 5→8 / 6→8
    high-bit replication, saves PNG. Pillow + pyserial.

Catalog:
  - docs/serial_commands.md — full reference for all T:* commands
    accumulated so far (identity/paths/send/receive, propagation,
    voice, BLE, UI). New commands should land here when added.

Throughput: ~205 KB base64 over CDC at 115200 → ~18 s/shot. Fine
for docs and automated tests, not video. Bumping baud or zlib-
compressing on-device is queued in the doc as future work.
2026-05-10 15:23:39 -04:00
torlando-techandClaude Opus 4.6 ee87edef7a Fix web flasher versioned releases failing with CORS error
GitHub release download URLs redirect to release-assets.githubusercontent.com
which doesn't return Access-Control-Allow-Origin headers. The browser blocks
cross-origin fetches from the GitHub Pages flasher, causing "Failed to fetch"
for any versioned release while the latest dev build (same-origin) works fine.

Fix: Deploy versioned firmware binaries to GitHub Pages alongside the dev
build at firmware/releases/{tag}/, so all versions are fetched same-origin.
The CI workflow now downloads existing release assets and deploys them to
Pages with keep_files: true to preserve across deploys.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 20:57:38 -05:00
torlando-techandClaude Opus 4.6 fd6fb4bcda Add firmware version picker to web flasher
Lets users choose between the latest dev build and tagged GitHub releases.
The dropdown queries the GitHub Releases API on page load and swaps
firmware fetch paths between Pages-relative and release-asset URLs.
CI now attaches all 4 firmware files to releases (bootloader, partitions,
boot_app0, firmware) so full installs work from any release version.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 16:36:03 -05:00
torlando-techandClaude Opus 4.6 ea586112e3 CI: auto-build and deploy firmware to GitHub Pages on every push to main
Rewrite release-firmware.yml to build the tdeck (NimBLE) env on pushes to
main (versioned as dev-<sha>) and on v* tags. Remove checked-in firmware
binaries from git tracking — CI now generates and deploys them to Pages.
Release creation is conditional on v* tags only.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 10:57:14 -05:00
torlando-techandClaude Opus 4.6 dd361be825 fix(flasher): add esptool.js to repo for gh-pages deployment
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 23:31:45 -05:00
torlando-techandClaude Opus 4.6 e2a62e6701 fix(flasher): clarify full install is required for first-time installs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 23:00:22 -05:00
torlando-techandClaude Opus 4.6 1b2705d8fe fix(flasher): use esploader.hardReset() for reliable post-flash reset
Replace manual DTR toggle with esploader's built-in hardReset() which
uses RTS (EN pin) to properly reset the ESP32-S3 after flashing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 22:58:47 -05:00
torlando-techandClaude Opus 4.6 826c69695c fix(flasher): disable tracing and fix flash params to match rnode-flasher
Transport tracing and missing enableTracing flag caused timing issues
with ESP32-S3 USB-Serial/JTAG during bootloader sync. Also fixes
flashMode/flashFreq format, routes esptool output to on-page log,
and adds firmware binaries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 22:52:49 -05:00
torlando-techandClaude Opus 4.6 8c6a6d2ee5 fix(flasher): update footer links to pyxis repo
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 21:27:25 -05:00
torlando-techandClaude Opus 4.6 ac6ceca9f8 Initial commit: standalone Pyxis T-Deck firmware
Split T-Deck firmware from microReticulum examples/lxmf_tdeck/ into its
own repo. microReticulum is consumed as a git submodule dependency pinned
to feat/t-deck. All include paths updated from relative symlinks to bare
includes resolved via library build flags.

Both tdeck (NimBLE) and tdeck-bluedroid environments compile successfully.
Licensed under AGPLv3.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 19:48:33 -05:00