Public Access
Every build now records at boot which version runs and, after a crash restart, which one crashed (even across a Rollback). The core dump summary (task, PC, reason, backtrace) is printed and raised as a Notification; `crash` shows it later. After 3 crash restarts in a row the firmware starts in Safe Mode: clock, Wi-Fi, Update Service and Debug Console only (SafeMode, 2 host tests). A normal restart or a minute up resets the count. The main loop is now on the task watchdog (enableLoopWDT): Arduino only watched core 0's idle task, so a stuck loop hung the device for good. The Update Service restarts into an installed update by itself if the main loop hasn't after 90 s. Debug Builds: `coredump get` and `reset` are answered by the console's own task; rdbg.py crash decodes the backtrace and rdbg.py coredump runs esp-coredump, against ELFs archived by version and digest in .pio/elves. The StorageService mutex is now made in the constructor: Safe Mode never starts that Service, and `info` crashed on the null mutex, 29 times in a row before the fix was pushed into Safe Mode over Wi-Fi. Verified on the device: crash report and full core dump decoded over Wi-Fi; Safe Mode at exactly 3 crashes, left by `reboot`; a hung loop caught by the watchdog in 5 s; `reset` from the console task. ADR 0005. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
34 lines
1.1 KiB
Python
34 lines
1.1 KiB
Python
# Injects the firmware version from `git describe` (semver tags like v0.1.0).
|
|
import subprocess
|
|
|
|
Import("env") # noqa: F821 (provided by PlatformIO)
|
|
|
|
try:
|
|
version = subprocess.check_output(
|
|
["git", "describe", "--tags", "--always", "--dirty"], text=True
|
|
).strip()
|
|
except Exception:
|
|
version = "unknown"
|
|
|
|
if env["PIOENV"].endswith("-debug"): # noqa: F821
|
|
version += "+debug" # a Debug Build says so wherever the version shows
|
|
|
|
env.Append(CPPDEFINES=[("RORO_VERSION", '\\"%s\\"' % version)]) # noqa: F821
|
|
|
|
|
|
# Keep every build's ELF, named by version and the first 16 hex digits of its SHA-256 (the core dump
|
|
# names the crashed firmware by the same digest), so a crash can be decoded after later builds.
|
|
def archive_elf(source, target, env):
|
|
import hashlib
|
|
import os
|
|
import shutil
|
|
|
|
elf = str(target[0])
|
|
digest = hashlib.sha256(open(elf, "rb").read()).hexdigest()[:16]
|
|
folder = os.path.join(env.subst("$PROJECT_DIR"), ".pio", "elves")
|
|
os.makedirs(folder, exist_ok=True)
|
|
shutil.copy(elf, os.path.join(folder, "%s.%s.elf" % (version, digest)))
|
|
|
|
|
|
env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", archive_elf) # noqa: F821
|