Files
Kaj SchittecatandClaude Opus 5.5 18279edac9 release: the CrowPanel Advanced 10.1 (P4) ships in betas and the web flasher
- p4-release.sh builds and verifies the three revisions (V1.2, V1.1, V1.0)
  from crowpanel_p4_101/ in the same loop as the T-Display P4 images, with
  the same OTA-name and tag checks.
- Self-update is on (CAP_OTA 1): each revision updates from its own
  wadamesh-crowpanel-p4-101-v1x.bin, so a V1.0 never takes a V1.2 image.
- gen-flasher-meta writes a manifest per revision; wadamesh.com gets a
  CrowPanel Advanced 10.1 card with a V1.2 / V1.1 / V1.0 picker, and the
  standalone flasher one card per revision. Both point at the beta feed,
  so nothing shows until the next beta publishes the images.
- README, DEVICES.md and the site's board count (15).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 21:02:37 +02:00

171 lines
8.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# Build every T-Display P4 release image and verify each one is what it claims.
#
# The P4 is not a PlatformIO env, so release.sh cannot build it: its bins are
# produced here and injected into the release tree afterwards. That used to be a
# handful of ad-hoc commands, which stopped being safe at EIGHT variants:
#
# panel AMOLED (RM69A10, default) or LCD (HI8561, WADA_P4_LCD=1)
# radio SX1262 (default) or LR2021 (WADA_P4_LR2021=1)
# C6 stack esp-hosted (default) or ESP-AT (WADA_P4_LEGACY_AT=1)
#
# The C6 axis is the dangerous one. Current V1 units ship the C6 with esp-hosted
# firmware; older units still carry the factory ESP-AT. Flash the wrong one and
# the C6 is unreachable -- which before b52c71f boot-looped the board, and still
# means no Wi-Fi and no BLE. The two builds are otherwise identical, so NOTHING
# about the binary tells you which it is except the artifact name it carries.
#
# TWO traps this script exists to close, both hit on 2026-10-05:
#
# 1. The CMake cache. Each variant has its own build dir, but a dir reused with
# different env vars keeps the OLD selection: a build asked for as hosted came
# out as ESP-AT, flag silently ignored. The cache is cleared per variant here.
# 2. Collecting from the wrong directory. build/tdisplay_p4 is only the AMOLED
# SX1262 variant; the others live in build/tdisplay_p4_lcd and friends.
# Copying the first one four times produces four identical "variants" that
# all look fine until someone flashes one.
#
# So every image is verified against the OTA name baked into it before it is
# accepted. That is the same string the device builds its self-update URL from,
# so if it disagrees with the filename the artifact is wrong in the way that
# matters -- a device would fetch the other variant's firmware. The T-Deck Max
# shipped exactly that bug (a Max self-updating to Pro firmware) and this table
# has been wrong three times. The check is cheap; a mismatch aborts the release.
#
# The Elecrow CrowPanel Advanced 10.1" (ESP32-P4, experimental since beta_97) is a
# separate IDF project (crowpanel_p4_101/) with one image per board revision; it is
# built and verified here in the same loop, from its own directory.
#
# Usage:
# scripts/build/p4-release.sh beta_88 [outdir]
set -euo pipefail
TAG="${1:?usage: p4-release.sh <tag> [outdir]}"
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
OUT="${2:-$ROOT/out/p4_$TAG}"
P4="$ROOT/tdisplay_p4"
# esptool with ESP32-P4 support: the IDF env's, not whatever is on PATH.
IDFPY="$ROOT/tanmatsu/esp-idf-tools/python_env/idf5.5_py3.9_env/bin/python"
[ -x "$IDFPY" ] || { echo "ABORT: IDF python not found at $IDFPY" >&2; exit 1; }
mkdir -p "$OUT"
# name | build dir | env assignments ("-" = none) [| project dir, default tdisplay_p4]
VARIANTS=(
"wadamesh-tdisplay-p4|tdisplay_p4|-"
"wadamesh-tdisplay-p4-lr2021|tdisplay_p4_lr2021|WADA_P4_LR2021=1"
"wadamesh-tdisplay-p4-lcd|tdisplay_p4_lcd|WADA_P4_LCD=1"
"wadamesh-tdisplay-p4-lcd-lr2021|tdisplay_p4_lcd_lr2021|WADA_P4_LCD=1 WADA_P4_LR2021=1"
"wadamesh-tdisplay-p4-at|tdisplay_p4|WADA_P4_LEGACY_AT=1"
"wadamesh-tdisplay-p4-lr2021-at|tdisplay_p4_lr2021|WADA_P4_LR2021=1 WADA_P4_LEGACY_AT=1"
"wadamesh-tdisplay-p4-lcd-at|tdisplay_p4_lcd|WADA_P4_LCD=1 WADA_P4_LEGACY_AT=1"
"wadamesh-tdisplay-p4-lcd-lr2021-at|tdisplay_p4_lcd_lr2021|WADA_P4_LCD=1 WADA_P4_LR2021=1 WADA_P4_LEGACY_AT=1"
"wadamesh-crowpanel-p4-101-v12|crowpanel_p4_101_v12|WADA_CP_REV=1.2|crowpanel_p4_101"
"wadamesh-crowpanel-p4-101-v11|crowpanel_p4_101_v11|WADA_CP_REV=1.1|crowpanel_p4_101"
"wadamesh-crowpanel-p4-101-v10|crowpanel_p4_101_v10|WADA_CP_REV=1.0|crowpanel_p4_101"
)
fail=0
for v in "${VARIANTS[@]}"; do
name="${v%%|*}"; rest="${v#*|}"
dir="${rest%%|*}"; rest="${rest#*|}"
envs="${rest%%|*}"
proj="tdisplay_p4"; [ "$rest" != "$envs" ] && proj="${rest#*|}"
cd "$ROOT/$proj"
echo "=== $name ($proj/build/$dir)"
# Trap 1: never inherit another variant's selection. Two dirs are shared by an
# esp-hosted and an ESP-AT build (the C6 axis does not change the dir name), so
# the previous occupant has to be cleared -- but ONLY by a real clean. Deleting
# CMakeCache.txt alone leaves CMakeFiles/ behind and the next configure dies in
# CMakeDetermineCCompiler with "No such file or directory". build.sh fullclean
# removes the tree properly and keeps the patched managed_components.
# A marker records what this dir last built, so re-running the same variant
# stays incremental instead of paying for a full rebuild every time.
# Two of these dirs are shared by an esp-hosted and an ESP-AT build, because the
# C6 axis does not change the dir name. The backend is read from the
# ENVIRONMENT at CMake CONFIGURE time (if(DEFINED ENV{WADA_P4_LEGACY_AT}) in
# main/CMakeLists.txt), and CMake does not reconfigure just because an env var
# changed -- so an incremental build in a dir that was configured the other way
# silently produces the OTHER variant, with no configure output to show for it.
# That is what made the first two runs of this script ship mislabelled images.
#
# So: always start these from nothing, and VERIFY the dir is gone rather than
# assuming the clean worked. The first version suppressed fullclean's output
# and trusted it; it had not run, and the only evidence was a missing configure
# line buried in a build log. A full rebuild per variant is the right price for
# a script that runs once per release.
if [ -d "build/$dir" ]; then
if [ "$envs" = "-" ]; then
env -u WADA_P4_LCD -u WADA_P4_LR2021 -u WADA_P4_LEGACY_AT -u WADA_CP_REV ./build.sh fullclean >> "/tmp/p4rel_$name.clean.log" 2>&1 || true
else
env -u WADA_P4_LCD -u WADA_P4_LR2021 -u WADA_P4_LEGACY_AT -u WADA_CP_REV $envs ./build.sh fullclean >> "/tmp/p4rel_$name.clean.log" 2>&1 || true
fi
fi
if [ -d "build/$dir" ]; then
echo " FAIL: build/$dir still present after fullclean; refusing to build on a stale tree"
echo " (see /tmp/p4rel_$name.clean.log)"
fail=$((fail+1)); continue
fi
# `env -u` every switch, then set only this variant's: an exported var in the
# caller's shell would otherwise leak in and silently change the build.
rc=0
if [ "$envs" = "-" ]; then
env -u WADA_P4_LCD -u WADA_P4_LR2021 -u WADA_P4_LEGACY_AT -u WADA_CP_REV \
WADA_FW_TAG="$TAG" ./build.sh build > "/tmp/p4rel_$name.log" 2>&1 || rc=$?
else
env -u WADA_P4_LCD -u WADA_P4_LR2021 -u WADA_P4_LEGACY_AT -u WADA_CP_REV \
$envs WADA_FW_TAG="$TAG" ./build.sh build > "/tmp/p4rel_$name.log" 2>&1 || rc=$?
fi
B="build/$dir"
app="$B/application.bin" # trap 2: this variant's dir, not the default one
# Check the EXIT CODE, not the log text. A failed CMake configure prints
# "Configuring incomplete, errors occurred!" and no "error:" line at all, so a
# grep for compiler errors waved it through -- and because the previous build's
# application.bin was still sitting in the dir, the next step happily read that
# instead. Only the id check downstream caught it.
if [ "$rc" -ne 0 ]; then
echo " FAIL: build exited $rc (see /tmp/p4rel_$name.log)"; fail=$((fail+1)); continue
fi
if [ ! -f "$app" ]; then
echo " FAIL: no application.bin (see /tmp/p4rel_$name.log)"; fail=$((fail+1)); continue
fi
# The verification that matters: what does the image say it is?
# NOTE: no `grep -q` and no `head` in these pipelines. Both exit as soon as
# they have what they need, which SIGPIPEs `strings`, and under `set -o
# pipefail` that non-zero status reads as "check failed" on a perfectly good
# image. Read the whole stream and decide afterwards.
ids="$(strings -a "$app" | grep -oE 'wadamesh-(tdisplay-p4|crowpanel-p4-101)[a-z0-9-]*' | sort -u || true)"
got="$(printf '%s\n' "$ids" | sed -n '1p')"
if [ "$got" != "$name" ]; then
echo " FAIL: image identifies as '$got', expected '$name'"
echo " A device built from this would self-update to the WRONG variant."
fail=$((fail+1)); continue
fi
# And that it carries this release's tag, not a stale cached one.
tagged="$(strings -a "$app" | grep -cE "(^|[^0-9a-z])${TAG}([^0-9]|$)" || true)"
if [ "${tagged:-0}" = "0" ]; then
echo " FAIL: $TAG is not embedded (stale build dir?)"; fail=$((fail+1)); continue
fi
cp "$app" "$OUT/$name.bin"
"$IDFPY" -m esptool --chip esp32p4 merge_bin --flash_mode dio --flash_size 16MB --flash_freq 80m \
-o "$OUT/$name-merged.bin" \
0x2000 "$B/bootloader/bootloader.bin" \
0x8000 "$B/partition_table/partition-table.bin" \
0xf000 "$B/ota_data_initial.bin" \
0x20000 "$app" > /dev/null
echo " ok $(stat -f%z "$app") bytes id=$got"
done
echo
if [ "$fail" -ne 0 ]; then
echo "ABORT: $fail of ${#VARIANTS[@]} P4 variants failed. Nothing is safe to ship." >&2
exit 1
fi
echo "all ${#VARIANTS[@]} P4 variants built and verified -> $OUT"
echo "Copy both .bin and -merged.bin for each into releases/<CHANNEL>/$TAG/ AND latest[-beta]/."