#!/bin/bash # build_signer.sh — reproducible build + optional flash for the Teensy 4.1 n_signer. # # Usage: # ./firmware/teensy41/build_signer.sh # compile only # ./firmware/teensy41/build_signer.sh --flash # compile + upload # ./firmware/teensy41/build_signer.sh --test # compile + upload + run test suite # # This script handles: # - Copying lv_conf.h to the Arduino libraries directory (where LVGL's # lv_conf_internal.h searches for it via ../../lv_conf.h). # - Passing the custom linker script (imxrt1062_t41_flashmem.ld) that routes # crypto code to FLASH instead of ITCM, freeing stack space. # - Printing the memory usage report. # - Optionally uploading to the first discovered Teensy port. # - Optionally running the hardware test suite. set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SIGNER_DIR="$SCRIPT_DIR/signer" FQBN="teensy:avr:teensy41" LV_CONF_SRC="$SIGNER_DIR/lv_conf.h" LV_CONF_DST="$HOME/Arduino/libraries/lv_conf.h" LINKER_SCRIPT="$SIGNER_DIR/imxrt1062_t41_flashmem.ld" # --- Step 1: Copy lv_conf.h to the Arduino libraries directory --- if [ -f "$LV_CONF_SRC" ]; then mkdir -p "$(dirname "$LV_CONF_DST")" cp "$LV_CONF_SRC" "$LV_CONF_DST" echo "[build] Copied lv_conf.h to $LV_CONF_DST" else echo "[build] WARNING: $LV_CONF_SRC not found — LVGL may use default config." fi # --- Step 2: Compile with the custom linker script --- echo "[build] Compiling..." LINKER_FLAG="-Wl,--gc-sections,--relax,--no-warn-rwx-segments -T${LINKER_SCRIPT}" if [ -f "$LINKER_SCRIPT" ]; then arduino-cli compile \ --fqbn "$FQBN" \ --build-property "build.flags.ld=${LINKER_FLAG}" \ "$SIGNER_DIR" || true # size-determination step may error with custom .ld else echo "[build] WARNING: Linker script not found at $LINKER_SCRIPT — using default." arduino-cli compile --fqbn "$FQBN" "$SIGNER_DIR" fi # --- Step 2b: FlexRAM stack gauge --- # arduino-cli's "Error while determining sketch size" with a custom linker # script is non-fatal (the ELF is produced), but it means we lose the built-in # memory report. Run our own gauge against the ELF to catch DTCM stack # overflows that the linker cannot detect (the ITCM/DTCM split is computed at # boot, not link time). ELF_FILE=$(find "$HOME/.cache/arduino/sketches" -name "signer.ino.elf" -newer "$LINKER_SCRIPT" 2>/dev/null | head -1) if [ -z "$ELF_FILE" ]; then ELF_FILE=$(find "$HOME/.cache/arduino/sketches" -name "signer.ino.elf" 2>/dev/null | head -1) fi if [ -n "$ELF_FILE" ] && [ -f "$ELF_FILE" ]; then echo "[build] Running FlexRAM stack gauge..." bash "$SCRIPT_DIR/check_stack.sh" "$ELF_FILE" 16384 || { echo "[build] ❌ Stack gauge FAILED — refusing to flash. See check_stack.sh output above." exit 1 } else echo "[build] WARNING: could not find signer.ino.elf for stack gauge — skipping." fi echo "[build] Compilation successful." # --- Step 3: Find the Teensy port --- find_teensy_port() { arduino-cli board list 2>/dev/null | grep 'teensy Teensy Ports' | awk '{print $1}' | head -1 } # --- Step 4: Flash (if --flash or --test) --- if [ "$1" = "--flash" ] || [ "$1" = "--test" ]; then PORT=$(find_teensy_port) if [ -z "$PORT" ]; then echo "[flash] No Teensy found. Press the PROGRAM button on the Teensy." exit 1 fi echo "[flash] Uploading to $PORT..." arduino-cli upload -p "$PORT" --fqbn "$FQBN" "$SIGNER_DIR" echo "[flash] Upload complete." fi # --- Step 5: Run test suite (if --test) --- if [ "$1" = "--test" ]; then echo "[test] Waiting for device to boot..." sleep 4 PORT_DEV=$(arduino-cli board list 2>/dev/null | grep 'ttyACM' | awk '{print $1}' | head -1) if [ -z "$PORT_DEV" ]; then PORT_DEV="/dev/ttyACM0" fi echo "[test] Running test suite on $PORT_DEV..." python3 "$SCRIPT_DIR/test_signer.py" --port "$PORT_DEV" || true fi