Files
ESP32_ZACUS/scripts/flash_monitor_audit.sh
T
2026-03-11 00:03:58 +01:00

182 lines
5.1 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
ENV_NAME="${ZACUS_ENV:-freenove_esp32s3_full_with_ui}"
MONITOR_SECONDS="${ZACUS_MONITOR_SECONDS:-90}"
DEFAULT_PORT="/dev/cu.usbmodem5AB90753301"
if [ -x "$ROOT_DIR/.venv/bin/python" ]; then
PYTHON_BIN="$ROOT_DIR/.venv/bin/python"
else
PYTHON_BIN="${PYTHON_BIN:-python3}"
fi
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
BUILD_ARTIFACT_DIR="$ROOT_DIR/artifacts/build"
MONITOR_ARTIFACT_DIR="$ROOT_DIR/artifacts/monitor"
AUDIT_ARTIFACT_DIR="$ROOT_DIR/artifacts/audit"
TEST_ARTIFACT_DIR="$ROOT_DIR/artifacts/tests"
SUMMARY_FILE="$AUDIT_ARTIFACT_DIR/${TIMESTAMP}_summary.txt"
MONITOR_LOG="$MONITOR_ARTIFACT_DIR/${TIMESTAMP}_boot.log"
ESPTOOL_LOG="$AUDIT_ARTIFACT_DIR/${TIMESTAMP}_esptool.log"
mkdir -p "$BUILD_ARTIFACT_DIR" "$MONITOR_ARTIFACT_DIR" "$AUDIT_ARTIFACT_DIR" "$TEST_ARTIFACT_DIR"
log() {
printf '[CHAIN] %s\n' "$1"
}
detect_port() {
if [ -n "${ZACUS_SERIAL_PORT:-}" ] && [ -e "${ZACUS_SERIAL_PORT}" ]; then
printf '%s\n' "${ZACUS_SERIAL_PORT}"
return 0
fi
if [ -e "$DEFAULT_PORT" ]; then
printf '%s\n' "$DEFAULT_PORT"
return 0
fi
mapfile -t ports < <(find /dev -maxdepth 1 -name 'cu.usbmodem*' | sort)
if [ "${#ports[@]}" -eq 1 ]; then
printf '%s\n' "${ports[0]}"
return 0
fi
return 1
}
run_stage() {
local stage="$1"
shift
local logfile="$BUILD_ARTIFACT_DIR/${TIMESTAMP}_${stage}.log"
log "stage=$stage"
if "$@" 2>&1 | tee "$logfile"; then
return 0
fi
return 1
}
write_blocked_summary() {
local build_ok="$1"
local upload_ok="$2"
"$PYTHON_BIN" "$ROOT_DIR/scripts/audit_boot_log.py" \
--summary "$SUMMARY_FILE" \
--build-ok "$build_ok" \
--upload-ok "$upload_ok" >/dev/null
}
run_upload_target() {
local target="$1"
local port="$2"
run_stage "$target" "$PYTHON_BIN" -m platformio run -e "$ENV_NAME" -t "$target" --upload-port "$port"
}
run_upload_with_retry() {
local result_var="$1"
local target="$2"
local port="$3"
if run_upload_target "$target" "$port"; then
printf -v "$result_var" '%s' "$port"
return 0
fi
log "retry stage=$target port=$port"
if [ -e "$port" ] && run_upload_target "$target" "$port"; then
printf -v "$result_var" '%s' "$port"
return 0
fi
local fallback_port
fallback_port="$(detect_port)" || return 1
if [ "$fallback_port" != "$port" ] && run_upload_target "$target" "$fallback_port"; then
printf -v "$result_var" '%s' "$fallback_port"
return 0
fi
return 1
}
run_test() {
local name="$1"
shift
local logfile="$TEST_ARTIFACT_DIR/${TIMESTAMP}_${name}.log"
log "test=$name"
"$@" 2>&1 | tee "$logfile"
}
main() {
cd "$ROOT_DIR"
local port
port="$(detect_port)" || {
printf 'state=hardware_unreachable\nreason=no_serial_port\n' >"$SUMMARY_FILE"
log "no serial port detected"
return 40
}
export ZACUS_SERIAL_PORT="$port"
if ! run_stage build "$PYTHON_BIN" -m platformio run -e "$ENV_NAME"; then
write_blocked_summary 0 0
return 20
fi
if ! run_stage buildfs "$PYTHON_BIN" -m platformio run -e "$ENV_NAME" -t buildfs; then
write_blocked_summary 0 0
return 20
fi
if ! run_upload_with_retry port uploadfs "$port"; then
write_blocked_summary 1 0
return 20
fi
export ZACUS_SERIAL_PORT="$port"
if ! run_upload_with_retry port upload "$port"; then
write_blocked_summary 1 0
return 20
fi
export ZACUS_SERIAL_PORT="$port"
if ! "$PYTHON_BIN" "$ROOT_DIR/scripts/serial_boot_capture.py" \
--port "$port" \
--baud 115200 \
--seconds "$MONITOR_SECONDS" \
--log "$MONITOR_LOG"; then
printf 'state=hardware_unreachable\nreason=serial_capture_failed\nport=%s\nlog=%s\n' "$port" "$MONITOR_LOG" >"$SUMMARY_FILE"
return 40
fi
local audit_state
set +e
audit_state="$("$PYTHON_BIN" "$ROOT_DIR/scripts/audit_boot_log.py" \
--log "$MONITOR_LOG" \
--summary "$SUMMARY_FILE" \
--build-ok 1 \
--upload-ok 1)"
local audit_rc=$?
set -e
if [ "$audit_state" = "safe_diagnostic_ok" ]; then
{
printf '[ESPTOOL] flash_id\n'
"$PYTHON_BIN" -m esptool --chip esp32s3 --port "$port" flash_id
printf '\n[ESPTOOL] read_mac\n'
"$PYTHON_BIN" -m esptool --chip esp32s3 --port "$port" read_mac
} 2>&1 | tee "$ESPTOOL_LOG"
{
printf 'finding=containment_logic_ok_root_cause_probable_hardware_or_memory_config\n'
printf 'expected_board=FNK0102H/ESP32-S3-WROOM-1-N16R8\n'
printf 'esptool_log=%s\n' "$ESPTOOL_LOG"
} >>"$SUMMARY_FILE"
return "$audit_rc"
fi
if [ "$audit_state" = "normal_boot_ok" ]; then
run_test sprint1 "$PYTHON_BIN" "$ROOT_DIR/tests/sprint1_utility_contract.py" --mode serial --cycles 1 --port "$port"
run_test sprint2 "$PYTHON_BIN" "$ROOT_DIR/tests/sprint2_capture_contract.py" --mode serial --cycles 1 --port "$port"
run_test sprint3 "$PYTHON_BIN" "$ROOT_DIR/tests/sprint3_audio_contract.py" --mode serial --cycles 1 --port "$port"
run_test phase9 "$PYTHON_BIN" "$ROOT_DIR/tests/phase9_ui_validation.py" --port "$port"
printf 'tests=serial_smoke_pass\n' >>"$SUMMARY_FILE"
return 0
fi
return "$audit_rc"
}
main "$@"