audit: the port's pass — the scan that could not walk, and the drift a generator ends
--scan's walk was unwalkable on POSIX: probe rates have no termios B-constant, so the first off-nominal probe raised out of the loop. The port speaks termios2 BOTHER now (red-proven on a pty at 9984 Bd), the probe's open lives inside the walk's error handling, an fd no longer leaks on an unmakeable rate, and the swallowed unknown-signature reply is named at timeout instead of reported as silence. CMakePresets.json's generator emits the submodule toolchain path it had drifted from — a hand edit on a generated file, exactly the class rule 10 exists for — and presets.generated gates the pair from here on (the marker CMake rejects at the presets root stayed out; the check is the guard). The over-slot image guard the tsb runner gained reaches the pureboot runner too; the GPIO bridge's delivery comment states the hardware truth (RXC at the stop bit's sampling point); the hardware suite gains the scan check — the one place the rate physics is real; and the libavr pin advances over both audit rounds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,11 +7,14 @@ port's TUs compile identically; the sims prove nothing new there) exist for
|
||||
libavr's reflect spot set only, mirroring its rule: the full reflect matrix
|
||||
is never built, one chip per hardware class and pack vintage is.
|
||||
|
||||
Run from the repo root: tools/make_presets.py
|
||||
Run from the repo root: tools/make_presets.py — or with --check, which
|
||||
verifies the committed file matches this generator and edits nothing (the
|
||||
ctest entry `presets.generated` runs that, so drift reds the gate).
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
CHIPS = [
|
||||
"attiny13", "attiny13a", "attiny25", "attiny45", "attiny85",
|
||||
@@ -41,7 +44,7 @@ def main():
|
||||
"hidden": True,
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/build/${presetName}",
|
||||
"toolchainFile": "$env{LIBAVR_ROOT}/cmake/avr-toolchain.cmake",
|
||||
"toolchainFile": "${sourceDir}/libavr/cmake/avr-toolchain.cmake",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
|
||||
@@ -72,6 +75,9 @@ def main():
|
||||
for chip in REFLECT_SPOT:
|
||||
add(chip, "reflect")
|
||||
|
||||
# CMake rejects unknown fields in the presets root, $comment included, so
|
||||
# the file cannot carry a generated-file marker; the --check ctest is the
|
||||
# whole of rule 10's guard here.
|
||||
presets = {
|
||||
"version": 8,
|
||||
"configurePresets": configure,
|
||||
@@ -79,12 +85,19 @@ def main():
|
||||
"testPresets": test,
|
||||
"workflowPresets": workflows,
|
||||
}
|
||||
rendered = json.dumps(presets, indent=1) + "\n"
|
||||
path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "CMakePresets.json")
|
||||
if "--check" in sys.argv[1:]:
|
||||
current = open(path).read() if os.path.exists(path) else ""
|
||||
if current != rendered:
|
||||
print("CMakePresets.json does not match its generator — run tools/make_presets.py")
|
||||
return 1
|
||||
return 0
|
||||
with open(path, "w") as f:
|
||||
json.dump(presets, f, indent=1)
|
||||
f.write("\n")
|
||||
f.write(rendered)
|
||||
print(f"{len(CHIPS)} chips, {len(REFLECT_SPOT)} reflect: {os.path.normpath(path)}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
sys.exit(main())
|
||||
|
||||
@@ -72,6 +72,35 @@ class Suite:
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def scan(self) -> None:
|
||||
"""The --scan walk against real termios and a real oscillator: every
|
||||
probe rate must open a port (the off-nominal rates exist only through
|
||||
termios2), and one probe must answer — the nominal on a healthy board,
|
||||
a neighbor on a drifted one. The rig injects the one reset per probe
|
||||
the operator supplies in the field; this is the rate physics the
|
||||
simulator cannot arbitrate (a pty carries bytes at any rate), pinned
|
||||
on silicon."""
|
||||
module = pbrig.load_pureboot(self.rig.d.pureboot)
|
||||
found = None
|
||||
for pct in module.scan_ratios():
|
||||
rate = module.scan_rate(self.rig.d.baud, pct)
|
||||
self.rig.reset()
|
||||
try:
|
||||
port = module.Port(self.rig.d.port, rate)
|
||||
except module.Error as error:
|
||||
self.check("scan opens every probe rate", False, f"{rate} Bd: {error}")
|
||||
return
|
||||
try:
|
||||
module.Loader(port).connect(min(self.rig.d.wait, 6.0))
|
||||
found = pct
|
||||
break
|
||||
except module.Error:
|
||||
continue
|
||||
finally:
|
||||
port.close()
|
||||
self.check("scan finds the board's rate", found is not None,
|
||||
"no probe answered" if found is None else f"{found:+d} % of {self.rig.d.baud} Bd")
|
||||
|
||||
def eeprom(self, info) -> None:
|
||||
size = info.eeprom_size
|
||||
if not size:
|
||||
@@ -161,6 +190,10 @@ class Suite:
|
||||
print("\nthe loader never answered; nothing below can be trusted")
|
||||
return 1
|
||||
|
||||
if not self.rig.d.autobaud:
|
||||
print("\nscan")
|
||||
self.scan()
|
||||
|
||||
print("\nEEPROM")
|
||||
self.eeprom(info)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user