memlnaut-nisps/scripts/build-firmware.sh

111 lines
2.9 KiB
Bash
Raw Permalink Normal View History

2026-04-15 17:32:32 +02:00
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=./firmware-common.sh
source "$SCRIPT_DIR/firmware-common.sh"
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
cat <<'EOF'
Usage:
scripts/build-firmware.sh [variant]
build(firmware): migrate to PlatformIO and vendor memllib (plan §5) One cut, no dual path. Closes ALIGNMENT defect 3 ("Arduino-CLI build machinery is actively hostile") and vision bullet 4. platformio.ini carries 16 [env:], one per variant, each passing -DMEMLNAUT_MODE_TYPE; selftest passes -DNISPS_SELFTEST=1 instead. The env list IS the registry now — the .ino comment-registry and the NISPS_ST_* token-paste table are deleted rather than migrated. L12 noted that table was already silently missing the currently-shipped SLPWorkshop variant, which is the whole argument against having a second list. Also deleted: the Python/sed machinery that rewrote the COMMITTED .ino on every build, the sketch symlink forest, the global TFT_eSPI User_Setup.h mutation (now -D flags — TFT_eSPI's own documented PlatformIO recipe), the UF2 boot-mount detection stack (upload_protocol=picotool talks to the bootloader directly), and build-firmware-arch.sh entirely. Scripts 683 -> 435 lines. memllib is vendored at lib/memllib/ from upstream e291192; no submodules remain. VENDORED.md records provenance and the re-sync procedure. S9: a firmware-build CI job compiles three representative envs against a cached toolchain and reports per-variant flash/RAM. Firmware is in an automated gate for the FIRST time. The old ci.yml comment justified excluding it as "low verification value" — an assessment that did not survive contact, since the SelfTest variant sat broken for an unknown period calling a DisplayDriver method that did not exist at the pinned memllib commit, and nothing noticed because nothing built it. Verified: all 16 envs build from an empty cache, each within ~520 bytes of the arduino-cli binary it replaces, flash and RAM. Measured as .text+.rodata / .data+.bss+vector+uninitialized — NOT PlatformIO's console line, which double-counts .data on this board. This does not prove the hardware boots; no flash+smoke test was possible and that stays an operator chokepoint. slpworkshop 248232/145028 pafsynth 256880/149716 selftest 216228/17960 (all 16 in the CI log format; none exceeds 2% of a 16 MB flash) Two traps recorded so nobody rediscovers them: vendoring memllib's subdirs without a src/ wrapper makes PlatformIO's library builder silently compile NOTHING while still linking; and project build_flags land BEFORE the framework's own -std=gnu++17 -Os, so build_unflags is required. CORRECTION carried in this commit: the firmware sizes in c19d846's message and the first version of the memllib recon doc were wrong — SLPWorkshop 145348, PAFSynth 145300, SelfTest 141840. They came from building variants in sequence through a SHARED incremental arduino-cli build directory, which reused stale objects and under-reported by ~75 KB. Clean-cache rebuilds of the identical commit give 216736/18492 for SelfTest. The real cost of the memllib upstream bump is +216 bytes flash, not +316. Never measure firmware size through a reused build dir. HISTORY NOTE: this commit and the docs commit before it were rebuilt (force-push, 2026-07-21) so that each contains only what its message describes. The first versions had the firmware deletions stranded in the docs commit by a shared-index race between concurrent agents; content is byte-identical to the originals. Gates: run-all-tests.sh ALL GREEN (nisps/ untouched by this change beyond include paths); 16/16 pio envs build.
2026-07-21 20:17:58 +02:00
scripts/build-firmware.sh --all
scripts/build-firmware.sh --variant VARIANT [extra `pio run` args...]
scripts/build-firmware.sh [variant] -- [extra `pio run` args...]
2026-04-15 17:32:32 +02:00
build(firmware): migrate to PlatformIO and vendor memllib (plan §5) One cut, no dual path. Closes ALIGNMENT defect 3 ("Arduino-CLI build machinery is actively hostile") and vision bullet 4. platformio.ini carries 16 [env:], one per variant, each passing -DMEMLNAUT_MODE_TYPE; selftest passes -DNISPS_SELFTEST=1 instead. The env list IS the registry now — the .ino comment-registry and the NISPS_ST_* token-paste table are deleted rather than migrated. L12 noted that table was already silently missing the currently-shipped SLPWorkshop variant, which is the whole argument against having a second list. Also deleted: the Python/sed machinery that rewrote the COMMITTED .ino on every build, the sketch symlink forest, the global TFT_eSPI User_Setup.h mutation (now -D flags — TFT_eSPI's own documented PlatformIO recipe), the UF2 boot-mount detection stack (upload_protocol=picotool talks to the bootloader directly), and build-firmware-arch.sh entirely. Scripts 683 -> 435 lines. memllib is vendored at lib/memllib/ from upstream e291192; no submodules remain. VENDORED.md records provenance and the re-sync procedure. S9: a firmware-build CI job compiles three representative envs against a cached toolchain and reports per-variant flash/RAM. Firmware is in an automated gate for the FIRST time. The old ci.yml comment justified excluding it as "low verification value" — an assessment that did not survive contact, since the SelfTest variant sat broken for an unknown period calling a DisplayDriver method that did not exist at the pinned memllib commit, and nothing noticed because nothing built it. Verified: all 16 envs build from an empty cache, each within ~520 bytes of the arduino-cli binary it replaces, flash and RAM. Measured as .text+.rodata / .data+.bss+vector+uninitialized — NOT PlatformIO's console line, which double-counts .data on this board. This does not prove the hardware boots; no flash+smoke test was possible and that stays an operator chokepoint. slpworkshop 248232/145028 pafsynth 256880/149716 selftest 216228/17960 (all 16 in the CI log format; none exceeds 2% of a 16 MB flash) Two traps recorded so nobody rediscovers them: vendoring memllib's subdirs without a src/ wrapper makes PlatformIO's library builder silently compile NOTHING while still linking; and project build_flags land BEFORE the framework's own -std=gnu++17 -Os, so build_unflags is required. CORRECTION carried in this commit: the firmware sizes in c19d846's message and the first version of the memllib recon doc were wrong — SLPWorkshop 145348, PAFSynth 145300, SelfTest 141840. They came from building variants in sequence through a SHARED incremental arduino-cli build directory, which reused stale objects and under-reported by ~75 KB. Clean-cache rebuilds of the identical commit give 216736/18492 for SelfTest. The real cost of the memllib upstream bump is +216 bytes flash, not +316. Never measure firmware size through a reused build dir. HISTORY NOTE: this commit and the docs commit before it were rebuilt (force-push, 2026-07-21) so that each contains only what its message describes. The first versions had the firmware deletions stranded in the docs commit by a shared-index race between concurrent agents; content is byte-identical to the originals. Gates: run-all-tests.sh ALL GREEN (nisps/ untouched by this change beyond include paths); 16/16 pio envs build.
2026-07-21 20:17:58 +02:00
Builds the MEMLNaut firmware via PlatformIO (firmware/MEMLNaut-NISPS/platformio.ini).
If no variant is provided and the script is run in a TTY, it prompts from the
[env:...] sections in platformio.ini. --all builds every variant in one
PlatformIO invocation.
Requires `pio` (PlatformIO Core) on PATH — see
scripts/setup-firmware-toolchain.sh, or run under:
nix-shell -p platformio-core --run 'scripts/build-firmware.sh ...'
2026-04-15 17:32:32 +02:00
EOF
exit 0
fi
build(firmware): migrate to PlatformIO and vendor memllib (plan §5) One cut, no dual path. Closes ALIGNMENT defect 3 ("Arduino-CLI build machinery is actively hostile") and vision bullet 4. platformio.ini carries 16 [env:], one per variant, each passing -DMEMLNAUT_MODE_TYPE; selftest passes -DNISPS_SELFTEST=1 instead. The env list IS the registry now — the .ino comment-registry and the NISPS_ST_* token-paste table are deleted rather than migrated. L12 noted that table was already silently missing the currently-shipped SLPWorkshop variant, which is the whole argument against having a second list. Also deleted: the Python/sed machinery that rewrote the COMMITTED .ino on every build, the sketch symlink forest, the global TFT_eSPI User_Setup.h mutation (now -D flags — TFT_eSPI's own documented PlatformIO recipe), the UF2 boot-mount detection stack (upload_protocol=picotool talks to the bootloader directly), and build-firmware-arch.sh entirely. Scripts 683 -> 435 lines. memllib is vendored at lib/memllib/ from upstream e291192; no submodules remain. VENDORED.md records provenance and the re-sync procedure. S9: a firmware-build CI job compiles three representative envs against a cached toolchain and reports per-variant flash/RAM. Firmware is in an automated gate for the FIRST time. The old ci.yml comment justified excluding it as "low verification value" — an assessment that did not survive contact, since the SelfTest variant sat broken for an unknown period calling a DisplayDriver method that did not exist at the pinned memllib commit, and nothing noticed because nothing built it. Verified: all 16 envs build from an empty cache, each within ~520 bytes of the arduino-cli binary it replaces, flash and RAM. Measured as .text+.rodata / .data+.bss+vector+uninitialized — NOT PlatformIO's console line, which double-counts .data on this board. This does not prove the hardware boots; no flash+smoke test was possible and that stays an operator chokepoint. slpworkshop 248232/145028 pafsynth 256880/149716 selftest 216228/17960 (all 16 in the CI log format; none exceeds 2% of a 16 MB flash) Two traps recorded so nobody rediscovers them: vendoring memllib's subdirs without a src/ wrapper makes PlatformIO's library builder silently compile NOTHING while still linking; and project build_flags land BEFORE the framework's own -std=gnu++17 -Os, so build_unflags is required. CORRECTION carried in this commit: the firmware sizes in c19d846's message and the first version of the memllib recon doc were wrong — SLPWorkshop 145348, PAFSynth 145300, SelfTest 141840. They came from building variants in sequence through a SHARED incremental arduino-cli build directory, which reused stale objects and under-reported by ~75 KB. Clean-cache rebuilds of the identical commit give 216736/18492 for SelfTest. The real cost of the memllib upstream bump is +216 bytes flash, not +316. Never measure firmware size through a reused build dir. HISTORY NOTE: this commit and the docs commit before it were rebuilt (force-push, 2026-07-21) so that each contains only what its message describes. The first versions had the firmware deletions stranded in the docs commit by a shared-index race between concurrent agents; content is byte-identical to the originals. Gates: run-all-tests.sh ALL GREEN (nisps/ untouched by this change beyond include paths); 16/16 pio envs build.
2026-07-21 20:17:58 +02:00
ensure_pio
2026-04-15 17:32:32 +02:00
variant_arg="${MEMLNAUT_FIRMWARE_VARIANT:-}"
build(firmware): migrate to PlatformIO and vendor memllib (plan §5) One cut, no dual path. Closes ALIGNMENT defect 3 ("Arduino-CLI build machinery is actively hostile") and vision bullet 4. platformio.ini carries 16 [env:], one per variant, each passing -DMEMLNAUT_MODE_TYPE; selftest passes -DNISPS_SELFTEST=1 instead. The env list IS the registry now — the .ino comment-registry and the NISPS_ST_* token-paste table are deleted rather than migrated. L12 noted that table was already silently missing the currently-shipped SLPWorkshop variant, which is the whole argument against having a second list. Also deleted: the Python/sed machinery that rewrote the COMMITTED .ino on every build, the sketch symlink forest, the global TFT_eSPI User_Setup.h mutation (now -D flags — TFT_eSPI's own documented PlatformIO recipe), the UF2 boot-mount detection stack (upload_protocol=picotool talks to the bootloader directly), and build-firmware-arch.sh entirely. Scripts 683 -> 435 lines. memllib is vendored at lib/memllib/ from upstream e291192; no submodules remain. VENDORED.md records provenance and the re-sync procedure. S9: a firmware-build CI job compiles three representative envs against a cached toolchain and reports per-variant flash/RAM. Firmware is in an automated gate for the FIRST time. The old ci.yml comment justified excluding it as "low verification value" — an assessment that did not survive contact, since the SelfTest variant sat broken for an unknown period calling a DisplayDriver method that did not exist at the pinned memllib commit, and nothing noticed because nothing built it. Verified: all 16 envs build from an empty cache, each within ~520 bytes of the arduino-cli binary it replaces, flash and RAM. Measured as .text+.rodata / .data+.bss+vector+uninitialized — NOT PlatformIO's console line, which double-counts .data on this board. This does not prove the hardware boots; no flash+smoke test was possible and that stays an operator chokepoint. slpworkshop 248232/145028 pafsynth 256880/149716 selftest 216228/17960 (all 16 in the CI log format; none exceeds 2% of a 16 MB flash) Two traps recorded so nobody rediscovers them: vendoring memllib's subdirs without a src/ wrapper makes PlatformIO's library builder silently compile NOTHING while still linking; and project build_flags land BEFORE the framework's own -std=gnu++17 -Os, so build_unflags is required. CORRECTION carried in this commit: the firmware sizes in c19d846's message and the first version of the memllib recon doc were wrong — SLPWorkshop 145348, PAFSynth 145300, SelfTest 141840. They came from building variants in sequence through a SHARED incremental arduino-cli build directory, which reused stale objects and under-reported by ~75 KB. Clean-cache rebuilds of the identical commit give 216736/18492 for SelfTest. The real cost of the memllib upstream bump is +216 bytes flash, not +316. Never measure firmware size through a reused build dir. HISTORY NOTE: this commit and the docs commit before it were rebuilt (force-push, 2026-07-21) so that each contains only what its message describes. The first versions had the firmware deletions stranded in the docs commit by a shared-index race between concurrent agents; content is byte-identical to the originals. Gates: run-all-tests.sh ALL GREEN (nisps/ untouched by this change beyond include paths); 16/16 pio envs build.
2026-07-21 20:17:58 +02:00
build_all=0
run_extra=()
load_firmware_variants
while [[ $# -gt 0 ]]; do
case "$1" in
build(firmware): migrate to PlatformIO and vendor memllib (plan §5) One cut, no dual path. Closes ALIGNMENT defect 3 ("Arduino-CLI build machinery is actively hostile") and vision bullet 4. platformio.ini carries 16 [env:], one per variant, each passing -DMEMLNAUT_MODE_TYPE; selftest passes -DNISPS_SELFTEST=1 instead. The env list IS the registry now — the .ino comment-registry and the NISPS_ST_* token-paste table are deleted rather than migrated. L12 noted that table was already silently missing the currently-shipped SLPWorkshop variant, which is the whole argument against having a second list. Also deleted: the Python/sed machinery that rewrote the COMMITTED .ino on every build, the sketch symlink forest, the global TFT_eSPI User_Setup.h mutation (now -D flags — TFT_eSPI's own documented PlatformIO recipe), the UF2 boot-mount detection stack (upload_protocol=picotool talks to the bootloader directly), and build-firmware-arch.sh entirely. Scripts 683 -> 435 lines. memllib is vendored at lib/memllib/ from upstream e291192; no submodules remain. VENDORED.md records provenance and the re-sync procedure. S9: a firmware-build CI job compiles three representative envs against a cached toolchain and reports per-variant flash/RAM. Firmware is in an automated gate for the FIRST time. The old ci.yml comment justified excluding it as "low verification value" — an assessment that did not survive contact, since the SelfTest variant sat broken for an unknown period calling a DisplayDriver method that did not exist at the pinned memllib commit, and nothing noticed because nothing built it. Verified: all 16 envs build from an empty cache, each within ~520 bytes of the arduino-cli binary it replaces, flash and RAM. Measured as .text+.rodata / .data+.bss+vector+uninitialized — NOT PlatformIO's console line, which double-counts .data on this board. This does not prove the hardware boots; no flash+smoke test was possible and that stays an operator chokepoint. slpworkshop 248232/145028 pafsynth 256880/149716 selftest 216228/17960 (all 16 in the CI log format; none exceeds 2% of a 16 MB flash) Two traps recorded so nobody rediscovers them: vendoring memllib's subdirs without a src/ wrapper makes PlatformIO's library builder silently compile NOTHING while still linking; and project build_flags land BEFORE the framework's own -std=gnu++17 -Os, so build_unflags is required. CORRECTION carried in this commit: the firmware sizes in c19d846's message and the first version of the memllib recon doc were wrong — SLPWorkshop 145348, PAFSynth 145300, SelfTest 141840. They came from building variants in sequence through a SHARED incremental arduino-cli build directory, which reused stale objects and under-reported by ~75 KB. Clean-cache rebuilds of the identical commit give 216736/18492 for SelfTest. The real cost of the memllib upstream bump is +216 bytes flash, not +316. Never measure firmware size through a reused build dir. HISTORY NOTE: this commit and the docs commit before it were rebuilt (force-push, 2026-07-21) so that each contains only what its message describes. The first versions had the firmware deletions stranded in the docs commit by a shared-index race between concurrent agents; content is byte-identical to the originals. Gates: run-all-tests.sh ALL GREEN (nisps/ untouched by this change beyond include paths); 16/16 pio envs build.
2026-07-21 20:17:58 +02:00
--all)
build_all=1
shift
;;
--variant)
if [[ $# -lt 2 ]]; then
echo "error: --variant requires a value" >&2
exit 1
fi
variant_arg="$2"
shift 2
;;
--variant=*)
variant_arg="${1#*=}"
shift
;;
--)
shift
build(firmware): migrate to PlatformIO and vendor memllib (plan §5) One cut, no dual path. Closes ALIGNMENT defect 3 ("Arduino-CLI build machinery is actively hostile") and vision bullet 4. platformio.ini carries 16 [env:], one per variant, each passing -DMEMLNAUT_MODE_TYPE; selftest passes -DNISPS_SELFTEST=1 instead. The env list IS the registry now — the .ino comment-registry and the NISPS_ST_* token-paste table are deleted rather than migrated. L12 noted that table was already silently missing the currently-shipped SLPWorkshop variant, which is the whole argument against having a second list. Also deleted: the Python/sed machinery that rewrote the COMMITTED .ino on every build, the sketch symlink forest, the global TFT_eSPI User_Setup.h mutation (now -D flags — TFT_eSPI's own documented PlatformIO recipe), the UF2 boot-mount detection stack (upload_protocol=picotool talks to the bootloader directly), and build-firmware-arch.sh entirely. Scripts 683 -> 435 lines. memllib is vendored at lib/memllib/ from upstream e291192; no submodules remain. VENDORED.md records provenance and the re-sync procedure. S9: a firmware-build CI job compiles three representative envs against a cached toolchain and reports per-variant flash/RAM. Firmware is in an automated gate for the FIRST time. The old ci.yml comment justified excluding it as "low verification value" — an assessment that did not survive contact, since the SelfTest variant sat broken for an unknown period calling a DisplayDriver method that did not exist at the pinned memllib commit, and nothing noticed because nothing built it. Verified: all 16 envs build from an empty cache, each within ~520 bytes of the arduino-cli binary it replaces, flash and RAM. Measured as .text+.rodata / .data+.bss+vector+uninitialized — NOT PlatformIO's console line, which double-counts .data on this board. This does not prove the hardware boots; no flash+smoke test was possible and that stays an operator chokepoint. slpworkshop 248232/145028 pafsynth 256880/149716 selftest 216228/17960 (all 16 in the CI log format; none exceeds 2% of a 16 MB flash) Two traps recorded so nobody rediscovers them: vendoring memllib's subdirs without a src/ wrapper makes PlatformIO's library builder silently compile NOTHING while still linking; and project build_flags land BEFORE the framework's own -std=gnu++17 -Os, so build_unflags is required. CORRECTION carried in this commit: the firmware sizes in c19d846's message and the first version of the memllib recon doc were wrong — SLPWorkshop 145348, PAFSynth 145300, SelfTest 141840. They came from building variants in sequence through a SHARED incremental arduino-cli build directory, which reused stale objects and under-reported by ~75 KB. Clean-cache rebuilds of the identical commit give 216736/18492 for SelfTest. The real cost of the memllib upstream bump is +216 bytes flash, not +316. Never measure firmware size through a reused build dir. HISTORY NOTE: this commit and the docs commit before it were rebuilt (force-push, 2026-07-21) so that each contains only what its message describes. The first versions had the firmware deletions stranded in the docs commit by a shared-index race between concurrent agents; content is byte-identical to the originals. Gates: run-all-tests.sh ALL GREEN (nisps/ untouched by this change beyond include paths); 16/16 pio envs build.
2026-07-21 20:17:58 +02:00
run_extra+=("$@")
break
;;
build(firmware): migrate to PlatformIO and vendor memllib (plan §5) One cut, no dual path. Closes ALIGNMENT defect 3 ("Arduino-CLI build machinery is actively hostile") and vision bullet 4. platformio.ini carries 16 [env:], one per variant, each passing -DMEMLNAUT_MODE_TYPE; selftest passes -DNISPS_SELFTEST=1 instead. The env list IS the registry now — the .ino comment-registry and the NISPS_ST_* token-paste table are deleted rather than migrated. L12 noted that table was already silently missing the currently-shipped SLPWorkshop variant, which is the whole argument against having a second list. Also deleted: the Python/sed machinery that rewrote the COMMITTED .ino on every build, the sketch symlink forest, the global TFT_eSPI User_Setup.h mutation (now -D flags — TFT_eSPI's own documented PlatformIO recipe), the UF2 boot-mount detection stack (upload_protocol=picotool talks to the bootloader directly), and build-firmware-arch.sh entirely. Scripts 683 -> 435 lines. memllib is vendored at lib/memllib/ from upstream e291192; no submodules remain. VENDORED.md records provenance and the re-sync procedure. S9: a firmware-build CI job compiles three representative envs against a cached toolchain and reports per-variant flash/RAM. Firmware is in an automated gate for the FIRST time. The old ci.yml comment justified excluding it as "low verification value" — an assessment that did not survive contact, since the SelfTest variant sat broken for an unknown period calling a DisplayDriver method that did not exist at the pinned memllib commit, and nothing noticed because nothing built it. Verified: all 16 envs build from an empty cache, each within ~520 bytes of the arduino-cli binary it replaces, flash and RAM. Measured as .text+.rodata / .data+.bss+vector+uninitialized — NOT PlatformIO's console line, which double-counts .data on this board. This does not prove the hardware boots; no flash+smoke test was possible and that stays an operator chokepoint. slpworkshop 248232/145028 pafsynth 256880/149716 selftest 216228/17960 (all 16 in the CI log format; none exceeds 2% of a 16 MB flash) Two traps recorded so nobody rediscovers them: vendoring memllib's subdirs without a src/ wrapper makes PlatformIO's library builder silently compile NOTHING while still linking; and project build_flags land BEFORE the framework's own -std=gnu++17 -Os, so build_unflags is required. CORRECTION carried in this commit: the firmware sizes in c19d846's message and the first version of the memllib recon doc were wrong — SLPWorkshop 145348, PAFSynth 145300, SelfTest 141840. They came from building variants in sequence through a SHARED incremental arduino-cli build directory, which reused stale objects and under-reported by ~75 KB. Clean-cache rebuilds of the identical commit give 216736/18492 for SelfTest. The real cost of the memllib upstream bump is +216 bytes flash, not +316. Never measure firmware size through a reused build dir. HISTORY NOTE: this commit and the docs commit before it were rebuilt (force-push, 2026-07-21) so that each contains only what its message describes. The first versions had the firmware deletions stranded in the docs commit by a shared-index race between concurrent agents; content is byte-identical to the originals. Gates: run-all-tests.sh ALL GREEN (nisps/ untouched by this change beyond include paths); 16/16 pio envs build.
2026-07-21 20:17:58 +02:00
-*)
# Looks like a passthrough flag for `pio run` (e.g. -v), not a variant.
run_extra+=("$1")
shift
;;
*)
build(firmware): migrate to PlatformIO and vendor memllib (plan §5) One cut, no dual path. Closes ALIGNMENT defect 3 ("Arduino-CLI build machinery is actively hostile") and vision bullet 4. platformio.ini carries 16 [env:], one per variant, each passing -DMEMLNAUT_MODE_TYPE; selftest passes -DNISPS_SELFTEST=1 instead. The env list IS the registry now — the .ino comment-registry and the NISPS_ST_* token-paste table are deleted rather than migrated. L12 noted that table was already silently missing the currently-shipped SLPWorkshop variant, which is the whole argument against having a second list. Also deleted: the Python/sed machinery that rewrote the COMMITTED .ino on every build, the sketch symlink forest, the global TFT_eSPI User_Setup.h mutation (now -D flags — TFT_eSPI's own documented PlatformIO recipe), the UF2 boot-mount detection stack (upload_protocol=picotool talks to the bootloader directly), and build-firmware-arch.sh entirely. Scripts 683 -> 435 lines. memllib is vendored at lib/memllib/ from upstream e291192; no submodules remain. VENDORED.md records provenance and the re-sync procedure. S9: a firmware-build CI job compiles three representative envs against a cached toolchain and reports per-variant flash/RAM. Firmware is in an automated gate for the FIRST time. The old ci.yml comment justified excluding it as "low verification value" — an assessment that did not survive contact, since the SelfTest variant sat broken for an unknown period calling a DisplayDriver method that did not exist at the pinned memllib commit, and nothing noticed because nothing built it. Verified: all 16 envs build from an empty cache, each within ~520 bytes of the arduino-cli binary it replaces, flash and RAM. Measured as .text+.rodata / .data+.bss+vector+uninitialized — NOT PlatformIO's console line, which double-counts .data on this board. This does not prove the hardware boots; no flash+smoke test was possible and that stays an operator chokepoint. slpworkshop 248232/145028 pafsynth 256880/149716 selftest 216228/17960 (all 16 in the CI log format; none exceeds 2% of a 16 MB flash) Two traps recorded so nobody rediscovers them: vendoring memllib's subdirs without a src/ wrapper makes PlatformIO's library builder silently compile NOTHING while still linking; and project build_flags land BEFORE the framework's own -std=gnu++17 -Os, so build_unflags is required. CORRECTION carried in this commit: the firmware sizes in c19d846's message and the first version of the memllib recon doc were wrong — SLPWorkshop 145348, PAFSynth 145300, SelfTest 141840. They came from building variants in sequence through a SHARED incremental arduino-cli build directory, which reused stale objects and under-reported by ~75 KB. Clean-cache rebuilds of the identical commit give 216736/18492 for SelfTest. The real cost of the memllib upstream bump is +216 bytes flash, not +316. Never measure firmware size through a reused build dir. HISTORY NOTE: this commit and the docs commit before it were rebuilt (force-push, 2026-07-21) so that each contains only what its message describes. The first versions had the firmware deletions stranded in the docs commit by a shared-index race between concurrent agents; content is byte-identical to the originals. Gates: run-all-tests.sh ALL GREEN (nisps/ untouched by this change beyond include paths); 16/16 pio envs build.
2026-07-21 20:17:58 +02:00
# A bare word is an attempted variant name, not passthrough — resolve it
# now so a typo fails loudly instead of turning into a confusing
# "Got unexpected extra argument" error from `pio run` later.
if [[ -n "$variant_arg" ]]; then
echo "error: unexpected extra argument: $1 (variant already set to $variant_arg)" >&2
exit 1
fi
build(firmware): migrate to PlatformIO and vendor memllib (plan §5) One cut, no dual path. Closes ALIGNMENT defect 3 ("Arduino-CLI build machinery is actively hostile") and vision bullet 4. platformio.ini carries 16 [env:], one per variant, each passing -DMEMLNAUT_MODE_TYPE; selftest passes -DNISPS_SELFTEST=1 instead. The env list IS the registry now — the .ino comment-registry and the NISPS_ST_* token-paste table are deleted rather than migrated. L12 noted that table was already silently missing the currently-shipped SLPWorkshop variant, which is the whole argument against having a second list. Also deleted: the Python/sed machinery that rewrote the COMMITTED .ino on every build, the sketch symlink forest, the global TFT_eSPI User_Setup.h mutation (now -D flags — TFT_eSPI's own documented PlatformIO recipe), the UF2 boot-mount detection stack (upload_protocol=picotool talks to the bootloader directly), and build-firmware-arch.sh entirely. Scripts 683 -> 435 lines. memllib is vendored at lib/memllib/ from upstream e291192; no submodules remain. VENDORED.md records provenance and the re-sync procedure. S9: a firmware-build CI job compiles three representative envs against a cached toolchain and reports per-variant flash/RAM. Firmware is in an automated gate for the FIRST time. The old ci.yml comment justified excluding it as "low verification value" — an assessment that did not survive contact, since the SelfTest variant sat broken for an unknown period calling a DisplayDriver method that did not exist at the pinned memllib commit, and nothing noticed because nothing built it. Verified: all 16 envs build from an empty cache, each within ~520 bytes of the arduino-cli binary it replaces, flash and RAM. Measured as .text+.rodata / .data+.bss+vector+uninitialized — NOT PlatformIO's console line, which double-counts .data on this board. This does not prove the hardware boots; no flash+smoke test was possible and that stays an operator chokepoint. slpworkshop 248232/145028 pafsynth 256880/149716 selftest 216228/17960 (all 16 in the CI log format; none exceeds 2% of a 16 MB flash) Two traps recorded so nobody rediscovers them: vendoring memllib's subdirs without a src/ wrapper makes PlatformIO's library builder silently compile NOTHING while still linking; and project build_flags land BEFORE the framework's own -std=gnu++17 -Os, so build_unflags is required. CORRECTION carried in this commit: the firmware sizes in c19d846's message and the first version of the memllib recon doc were wrong — SLPWorkshop 145348, PAFSynth 145300, SelfTest 141840. They came from building variants in sequence through a SHARED incremental arduino-cli build directory, which reused stale objects and under-reported by ~75 KB. Clean-cache rebuilds of the identical commit give 216736/18492 for SelfTest. The real cost of the memllib upstream bump is +216 bytes flash, not +316. Never measure firmware size through a reused build dir. HISTORY NOTE: this commit and the docs commit before it were rebuilt (force-push, 2026-07-21) so that each contains only what its message describes. The first versions had the firmware deletions stranded in the docs commit by a shared-index race between concurrent agents; content is byte-identical to the originals. Gates: run-all-tests.sh ALL GREEN (nisps/ untouched by this change beyond include paths); 16/16 pio envs build.
2026-07-21 20:17:58 +02:00
variant_arg="$(resolve_firmware_variant "$1")" || {
echo "error: unknown firmware variant: $1" >&2
echo "available variants (from $PLATFORMIO_INI):" >&2
for v in "${FIRMWARE_VARIANTS[@]}"; do
echo " - $v" >&2
done
exit 1
}
shift
;;
esac
done
build(firmware): migrate to PlatformIO and vendor memllib (plan §5) One cut, no dual path. Closes ALIGNMENT defect 3 ("Arduino-CLI build machinery is actively hostile") and vision bullet 4. platformio.ini carries 16 [env:], one per variant, each passing -DMEMLNAUT_MODE_TYPE; selftest passes -DNISPS_SELFTEST=1 instead. The env list IS the registry now — the .ino comment-registry and the NISPS_ST_* token-paste table are deleted rather than migrated. L12 noted that table was already silently missing the currently-shipped SLPWorkshop variant, which is the whole argument against having a second list. Also deleted: the Python/sed machinery that rewrote the COMMITTED .ino on every build, the sketch symlink forest, the global TFT_eSPI User_Setup.h mutation (now -D flags — TFT_eSPI's own documented PlatformIO recipe), the UF2 boot-mount detection stack (upload_protocol=picotool talks to the bootloader directly), and build-firmware-arch.sh entirely. Scripts 683 -> 435 lines. memllib is vendored at lib/memllib/ from upstream e291192; no submodules remain. VENDORED.md records provenance and the re-sync procedure. S9: a firmware-build CI job compiles three representative envs against a cached toolchain and reports per-variant flash/RAM. Firmware is in an automated gate for the FIRST time. The old ci.yml comment justified excluding it as "low verification value" — an assessment that did not survive contact, since the SelfTest variant sat broken for an unknown period calling a DisplayDriver method that did not exist at the pinned memllib commit, and nothing noticed because nothing built it. Verified: all 16 envs build from an empty cache, each within ~520 bytes of the arduino-cli binary it replaces, flash and RAM. Measured as .text+.rodata / .data+.bss+vector+uninitialized — NOT PlatformIO's console line, which double-counts .data on this board. This does not prove the hardware boots; no flash+smoke test was possible and that stays an operator chokepoint. slpworkshop 248232/145028 pafsynth 256880/149716 selftest 216228/17960 (all 16 in the CI log format; none exceeds 2% of a 16 MB flash) Two traps recorded so nobody rediscovers them: vendoring memllib's subdirs without a src/ wrapper makes PlatformIO's library builder silently compile NOTHING while still linking; and project build_flags land BEFORE the framework's own -std=gnu++17 -Os, so build_unflags is required. CORRECTION carried in this commit: the firmware sizes in c19d846's message and the first version of the memllib recon doc were wrong — SLPWorkshop 145348, PAFSynth 145300, SelfTest 141840. They came from building variants in sequence through a SHARED incremental arduino-cli build directory, which reused stale objects and under-reported by ~75 KB. Clean-cache rebuilds of the identical commit give 216736/18492 for SelfTest. The real cost of the memllib upstream bump is +216 bytes flash, not +316. Never measure firmware size through a reused build dir. HISTORY NOTE: this commit and the docs commit before it were rebuilt (force-push, 2026-07-21) so that each contains only what its message describes. The first versions had the firmware deletions stranded in the docs commit by a shared-index race between concurrent agents; content is byte-identical to the originals. Gates: run-all-tests.sh ALL GREEN (nisps/ untouched by this change beyond include paths); 16/16 pio envs build.
2026-07-21 20:17:58 +02:00
if [[ "$build_all" -eq 1 ]]; then
echo "Building ALL firmware variants: ${FIRMWARE_VARIANTS[*]}"
env_args=()
for v in "${FIRMWARE_VARIANTS[@]}"; do
env_args+=(-e "$v")
done
run_pio run "${env_args[@]}" "${run_extra[@]}"
echo
echo "UF2s ready under:"
for v in "${FIRMWARE_VARIANTS[@]}"; do
echo " $FIRMWARE_PROJECT_DIR/.pio/build/$v/firmware.uf2"
done
exit 0
fi
2026-04-15 17:32:32 +02:00
build(firmware): migrate to PlatformIO and vendor memllib (plan §5) One cut, no dual path. Closes ALIGNMENT defect 3 ("Arduino-CLI build machinery is actively hostile") and vision bullet 4. platformio.ini carries 16 [env:], one per variant, each passing -DMEMLNAUT_MODE_TYPE; selftest passes -DNISPS_SELFTEST=1 instead. The env list IS the registry now — the .ino comment-registry and the NISPS_ST_* token-paste table are deleted rather than migrated. L12 noted that table was already silently missing the currently-shipped SLPWorkshop variant, which is the whole argument against having a second list. Also deleted: the Python/sed machinery that rewrote the COMMITTED .ino on every build, the sketch symlink forest, the global TFT_eSPI User_Setup.h mutation (now -D flags — TFT_eSPI's own documented PlatformIO recipe), the UF2 boot-mount detection stack (upload_protocol=picotool talks to the bootloader directly), and build-firmware-arch.sh entirely. Scripts 683 -> 435 lines. memllib is vendored at lib/memllib/ from upstream e291192; no submodules remain. VENDORED.md records provenance and the re-sync procedure. S9: a firmware-build CI job compiles three representative envs against a cached toolchain and reports per-variant flash/RAM. Firmware is in an automated gate for the FIRST time. The old ci.yml comment justified excluding it as "low verification value" — an assessment that did not survive contact, since the SelfTest variant sat broken for an unknown period calling a DisplayDriver method that did not exist at the pinned memllib commit, and nothing noticed because nothing built it. Verified: all 16 envs build from an empty cache, each within ~520 bytes of the arduino-cli binary it replaces, flash and RAM. Measured as .text+.rodata / .data+.bss+vector+uninitialized — NOT PlatformIO's console line, which double-counts .data on this board. This does not prove the hardware boots; no flash+smoke test was possible and that stays an operator chokepoint. slpworkshop 248232/145028 pafsynth 256880/149716 selftest 216228/17960 (all 16 in the CI log format; none exceeds 2% of a 16 MB flash) Two traps recorded so nobody rediscovers them: vendoring memllib's subdirs without a src/ wrapper makes PlatformIO's library builder silently compile NOTHING while still linking; and project build_flags land BEFORE the framework's own -std=gnu++17 -Os, so build_unflags is required. CORRECTION carried in this commit: the firmware sizes in c19d846's message and the first version of the memllib recon doc were wrong — SLPWorkshop 145348, PAFSynth 145300, SelfTest 141840. They came from building variants in sequence through a SHARED incremental arduino-cli build directory, which reused stale objects and under-reported by ~75 KB. Clean-cache rebuilds of the identical commit give 216736/18492 for SelfTest. The real cost of the memllib upstream bump is +216 bytes flash, not +316. Never measure firmware size through a reused build dir. HISTORY NOTE: this commit and the docs commit before it were rebuilt (force-push, 2026-07-21) so that each contains only what its message describes. The first versions had the firmware deletions stranded in the docs commit by a shared-index race between concurrent agents; content is byte-identical to the originals. Gates: run-all-tests.sh ALL GREEN (nisps/ untouched by this change beyond include paths); 16/16 pio envs build.
2026-07-21 20:17:58 +02:00
selected="$(choose_firmware_variant "$variant_arg")"
2026-04-15 17:32:32 +02:00
build(firmware): migrate to PlatformIO and vendor memllib (plan §5) One cut, no dual path. Closes ALIGNMENT defect 3 ("Arduino-CLI build machinery is actively hostile") and vision bullet 4. platformio.ini carries 16 [env:], one per variant, each passing -DMEMLNAUT_MODE_TYPE; selftest passes -DNISPS_SELFTEST=1 instead. The env list IS the registry now — the .ino comment-registry and the NISPS_ST_* token-paste table are deleted rather than migrated. L12 noted that table was already silently missing the currently-shipped SLPWorkshop variant, which is the whole argument against having a second list. Also deleted: the Python/sed machinery that rewrote the COMMITTED .ino on every build, the sketch symlink forest, the global TFT_eSPI User_Setup.h mutation (now -D flags — TFT_eSPI's own documented PlatformIO recipe), the UF2 boot-mount detection stack (upload_protocol=picotool talks to the bootloader directly), and build-firmware-arch.sh entirely. Scripts 683 -> 435 lines. memllib is vendored at lib/memllib/ from upstream e291192; no submodules remain. VENDORED.md records provenance and the re-sync procedure. S9: a firmware-build CI job compiles three representative envs against a cached toolchain and reports per-variant flash/RAM. Firmware is in an automated gate for the FIRST time. The old ci.yml comment justified excluding it as "low verification value" — an assessment that did not survive contact, since the SelfTest variant sat broken for an unknown period calling a DisplayDriver method that did not exist at the pinned memllib commit, and nothing noticed because nothing built it. Verified: all 16 envs build from an empty cache, each within ~520 bytes of the arduino-cli binary it replaces, flash and RAM. Measured as .text+.rodata / .data+.bss+vector+uninitialized — NOT PlatformIO's console line, which double-counts .data on this board. This does not prove the hardware boots; no flash+smoke test was possible and that stays an operator chokepoint. slpworkshop 248232/145028 pafsynth 256880/149716 selftest 216228/17960 (all 16 in the CI log format; none exceeds 2% of a 16 MB flash) Two traps recorded so nobody rediscovers them: vendoring memllib's subdirs without a src/ wrapper makes PlatformIO's library builder silently compile NOTHING while still linking; and project build_flags land BEFORE the framework's own -std=gnu++17 -Os, so build_unflags is required. CORRECTION carried in this commit: the firmware sizes in c19d846's message and the first version of the memllib recon doc were wrong — SLPWorkshop 145348, PAFSynth 145300, SelfTest 141840. They came from building variants in sequence through a SHARED incremental arduino-cli build directory, which reused stale objects and under-reported by ~75 KB. Clean-cache rebuilds of the identical commit give 216736/18492 for SelfTest. The real cost of the memllib upstream bump is +216 bytes flash, not +316. Never measure firmware size through a reused build dir. HISTORY NOTE: this commit and the docs commit before it were rebuilt (force-push, 2026-07-21) so that each contains only what its message describes. The first versions had the firmware deletions stranded in the docs commit by a shared-index race between concurrent agents; content is byte-identical to the originals. Gates: run-all-tests.sh ALL GREEN (nisps/ untouched by this change beyond include paths); 16/16 pio envs build.
2026-07-21 20:17:58 +02:00
echo "Building firmware:"
echo " project: $FIRMWARE_PROJECT_DIR"
echo " variant: $selected"
2026-04-15 17:32:32 +02:00
build(firmware): migrate to PlatformIO and vendor memllib (plan §5) One cut, no dual path. Closes ALIGNMENT defect 3 ("Arduino-CLI build machinery is actively hostile") and vision bullet 4. platformio.ini carries 16 [env:], one per variant, each passing -DMEMLNAUT_MODE_TYPE; selftest passes -DNISPS_SELFTEST=1 instead. The env list IS the registry now — the .ino comment-registry and the NISPS_ST_* token-paste table are deleted rather than migrated. L12 noted that table was already silently missing the currently-shipped SLPWorkshop variant, which is the whole argument against having a second list. Also deleted: the Python/sed machinery that rewrote the COMMITTED .ino on every build, the sketch symlink forest, the global TFT_eSPI User_Setup.h mutation (now -D flags — TFT_eSPI's own documented PlatformIO recipe), the UF2 boot-mount detection stack (upload_protocol=picotool talks to the bootloader directly), and build-firmware-arch.sh entirely. Scripts 683 -> 435 lines. memllib is vendored at lib/memllib/ from upstream e291192; no submodules remain. VENDORED.md records provenance and the re-sync procedure. S9: a firmware-build CI job compiles three representative envs against a cached toolchain and reports per-variant flash/RAM. Firmware is in an automated gate for the FIRST time. The old ci.yml comment justified excluding it as "low verification value" — an assessment that did not survive contact, since the SelfTest variant sat broken for an unknown period calling a DisplayDriver method that did not exist at the pinned memllib commit, and nothing noticed because nothing built it. Verified: all 16 envs build from an empty cache, each within ~520 bytes of the arduino-cli binary it replaces, flash and RAM. Measured as .text+.rodata / .data+.bss+vector+uninitialized — NOT PlatformIO's console line, which double-counts .data on this board. This does not prove the hardware boots; no flash+smoke test was possible and that stays an operator chokepoint. slpworkshop 248232/145028 pafsynth 256880/149716 selftest 216228/17960 (all 16 in the CI log format; none exceeds 2% of a 16 MB flash) Two traps recorded so nobody rediscovers them: vendoring memllib's subdirs without a src/ wrapper makes PlatformIO's library builder silently compile NOTHING while still linking; and project build_flags land BEFORE the framework's own -std=gnu++17 -Os, so build_unflags is required. CORRECTION carried in this commit: the firmware sizes in c19d846's message and the first version of the memllib recon doc were wrong — SLPWorkshop 145348, PAFSynth 145300, SelfTest 141840. They came from building variants in sequence through a SHARED incremental arduino-cli build directory, which reused stale objects and under-reported by ~75 KB. Clean-cache rebuilds of the identical commit give 216736/18492 for SelfTest. The real cost of the memllib upstream bump is +216 bytes flash, not +316. Never measure firmware size through a reused build dir. HISTORY NOTE: this commit and the docs commit before it were rebuilt (force-push, 2026-07-21) so that each contains only what its message describes. The first versions had the firmware deletions stranded in the docs commit by a shared-index race between concurrent agents; content is byte-identical to the originals. Gates: run-all-tests.sh ALL GREEN (nisps/ untouched by this change beyond include paths); 16/16 pio envs build.
2026-07-21 20:17:58 +02:00
run_pio run -e "$selected" "${run_extra[@]}"
2026-04-15 17:32:32 +02:00
echo
echo "UF2 ready at:"
build(firmware): migrate to PlatformIO and vendor memllib (plan §5) One cut, no dual path. Closes ALIGNMENT defect 3 ("Arduino-CLI build machinery is actively hostile") and vision bullet 4. platformio.ini carries 16 [env:], one per variant, each passing -DMEMLNAUT_MODE_TYPE; selftest passes -DNISPS_SELFTEST=1 instead. The env list IS the registry now — the .ino comment-registry and the NISPS_ST_* token-paste table are deleted rather than migrated. L12 noted that table was already silently missing the currently-shipped SLPWorkshop variant, which is the whole argument against having a second list. Also deleted: the Python/sed machinery that rewrote the COMMITTED .ino on every build, the sketch symlink forest, the global TFT_eSPI User_Setup.h mutation (now -D flags — TFT_eSPI's own documented PlatformIO recipe), the UF2 boot-mount detection stack (upload_protocol=picotool talks to the bootloader directly), and build-firmware-arch.sh entirely. Scripts 683 -> 435 lines. memllib is vendored at lib/memllib/ from upstream e291192; no submodules remain. VENDORED.md records provenance and the re-sync procedure. S9: a firmware-build CI job compiles three representative envs against a cached toolchain and reports per-variant flash/RAM. Firmware is in an automated gate for the FIRST time. The old ci.yml comment justified excluding it as "low verification value" — an assessment that did not survive contact, since the SelfTest variant sat broken for an unknown period calling a DisplayDriver method that did not exist at the pinned memllib commit, and nothing noticed because nothing built it. Verified: all 16 envs build from an empty cache, each within ~520 bytes of the arduino-cli binary it replaces, flash and RAM. Measured as .text+.rodata / .data+.bss+vector+uninitialized — NOT PlatformIO's console line, which double-counts .data on this board. This does not prove the hardware boots; no flash+smoke test was possible and that stays an operator chokepoint. slpworkshop 248232/145028 pafsynth 256880/149716 selftest 216228/17960 (all 16 in the CI log format; none exceeds 2% of a 16 MB flash) Two traps recorded so nobody rediscovers them: vendoring memllib's subdirs without a src/ wrapper makes PlatformIO's library builder silently compile NOTHING while still linking; and project build_flags land BEFORE the framework's own -std=gnu++17 -Os, so build_unflags is required. CORRECTION carried in this commit: the firmware sizes in c19d846's message and the first version of the memllib recon doc were wrong — SLPWorkshop 145348, PAFSynth 145300, SelfTest 141840. They came from building variants in sequence through a SHARED incremental arduino-cli build directory, which reused stale objects and under-reported by ~75 KB. Clean-cache rebuilds of the identical commit give 216736/18492 for SelfTest. The real cost of the memllib upstream bump is +216 bytes flash, not +316. Never measure firmware size through a reused build dir. HISTORY NOTE: this commit and the docs commit before it were rebuilt (force-push, 2026-07-21) so that each contains only what its message describes. The first versions had the firmware deletions stranded in the docs commit by a shared-index race between concurrent agents; content is byte-identical to the originals. Gates: run-all-tests.sh ALL GREEN (nisps/ untouched by this change beyond include paths); 16/16 pio envs build.
2026-07-21 20:17:58 +02:00
echo " $FIRMWARE_PROJECT_DIR/.pio/build/$selected/firmware.uf2"