tools/panel_dump.py prints the display controller's own memory as ASCII or PNG for any firmware, with the four mappings, so two builds can be compared instead of glanced at. The panel model gained a bounded UVK5_PANEL_PROBE diagnostic along the way.
Measured: the 5.9.0.CN panel agrees with its own framebuffer 8188 of 8192 pixels with the data untouched, and the fetched 6.0.0 build renders identically. Both program the same geometry registers, which is why the mapping is a driver convention and cannot be derived from the controller: it has to be measured.
Noted, not yet fixed: the display start line (0x40|n) is ignored, and the model stores pixels at col-4 with the column counter wrapping at 128 instead of the controller's 132 columns.
The probe scripts, run.sh, trace_run.sh, webui.py and two emulator tests each named the same hardcoded firmware from a source tree that is not in this repository. They now resolve QEMU and the firmware the way tools/uvk5_testenv.py does -- environment, then PATH, then whatever the checkout has -- and skip with a reason when there is nothing.
webui.py's --qemu and --elf lost their author defaults too: a bare qemu-system-arm through PATH, and no firmware until one is uploaded, which the page already reports.
tools/run_tests.sh defaults QEMU_SRC to a sibling of the checkout, which is where setup_qemu.sh puts it; the two defaults disagreed, so a fresh clone rebuilt nothing and reported a build that was not there. The interpreter list was also reading an empty $PY.
tools/test_bk4819_readback.sh was the last test with the author's paths, and the only one that could not run elsewhere. It now takes QEMU, GDB and ELF from the environment or PATH like the python tests, skips with a reason when one is missing, and says so on a platform whose QEMU cannot make the unix socket it uses.
tools/check_docs.py points UVK5_FW_DIR at a sibling and skips the file:line checks, with a message, when there is no firmware tree -- a fresh clone used to see thirteen failures it could do nothing about.
Added .github/workflows/unit.yml (the fast half of run_tests.sh on every push and PR), requirements-dev.txt for the one pip dependency, and a Dockerfile. Flask is not always installed, so test_webui now skips through setUpModule rather than erroring.
The bootloader's DFU handler is reachable only when SRAM[0x20000020] is 3, which only a program that then resets can write. The application's 0x05DD takes that path only with ENABLE_OVERLAY; this build resets straight back into the application instead. Ruled out by measurement: PTT alone, PTT+SIDE1/SIDE2, MENU, a host byte in the boot window including 0x0530, and 0x05DD.
boot-key now reads a + separated list, because the firmware's own BOOT_GetMode() needs PTT and a matrix key together for every special boot mode. Tested against all four documented combinations.
flash controller: store ACR/OPTKEYR instead of swallowing them, which is what stopped the factory bootloader from starting
slots over the firmware's own serial protocol (0x0720 family); uvk5_socket/uvk5_testenv so a fresh checkout skips instead of failing; web UI slot table and Multiboot button; quick start, CONTRIBUTING, and stop tracking firmware images and radio dumps
Translating everything into Chinese found four claims that had already drifted, and
none of them were caught by reading -- they were caught by comparing against source.
Proofreading does not find rot, so do the comparison mechanically and keep doing it.
tools/check_docs.py verifies that every tool a README names exists, that every test in
run_tests.sh is documented in both languages, that internal .md links resolve, that the
translation pairs have matching heading structure, that memory-map addresses match the
model's #defines, and that documented firmware file:line references still point at what
the prose claims. It runs in the quick tier of run_tests.sh, needing no emulator.
Confirmed it can actually fail, because a checker that cannot is worthless: renaming a
documented tool and deleting a heading from the Chinese side each produce one named
failure and exit 1, and reverting returns it to clean.
One thing it deliberately does not check. An early version compared firmware constants
with a regex that took the first number on a line, so `key_debounce_10ms = 20 / 10` read
as 20 and it declared the docs wrong for saying 2. The docs were right and the checker
was broken. A checker that cries wolf gets ignored, so claims it cannot verify
unambiguously are left out rather than guessed at.
Current state: 16 file:line references all accurate, 7 memory-map addresses all match,
zero broken links, all three translation pairs structurally aligned.
Full translations rather than summaries, section-for-section with the English:
README (13 sections), AGENTS.md (21), and docs/reverse-proxy.md. Each pair
cross-links to the other and says the two are kept in step, since documentation
that has silently diverged is worse than documentation that does not exist.
Verified rather than eyeballed: heading counts and order match in both pairs,
every internal .md link resolves, every tool named in either README exists, and
every test in run_tests.sh appears in both.
Translating turned up four things that were already stale in the English, which
is the honest argument for having done it this way -- a summary would not have
touched them:
- the endpoint table was missing /api/ptt, /api/power/<action> and
/api/logs, and did not mention the speaker field on /api/status
- the modelled-peripheral list omitted TIM2
- the audit table still called TIM a stub, unchanged since fdcbe80 modelled
TIM2
- neither README listed uvk5_logs.py, uvk5_stream.py, uvk5_supervisor.py or
test_kill_emulator.sh, which are part of the repo rather than scratch
The ad-hoc probe scripts are now acknowledged in one line instead of being
silently absent, and described as what they are: quick to reach for, not
polished.
Unit tests: 89 passed.