mirror of
https://github.com/MCKero6423/uv-k5-v3-emulator.git
synced 2026-10-02 11:07:31 +00:00
The firmware has been printing all along and nothing was listening. USART1 has no
real model here -- it is one of the logging catch-all stubs -- so every byte went
into qemu_log_mask(LOG_UNIMP) and vanished.
Two things were needed, and the second was not in the plan:
1. Print USART1 DR writes (+0x04, per the vendor CMSIS header) as SERIAL lines.
2. Report TXE|TC in USART1 SR. This is the part I had missed. UART_Send() in
App/driver/uart.c spins on LL_USART_IsActiveFlag_TXE() with a bounded timeout
and *skips the byte* when the flag never sets. A stub returning 0 for SR meant
the firmware discarded its own output before it ever reached DR -- the only
write arriving was UART_Init()'s priming zero. So step 1 alone produced
nothing, which is why the first attempt looked like "the build has no logging".
Then a bug of my own: the priming byte is 0x00, I buffered it, and fprintf("%s")
stopped at that NUL and printed an empty line while all 46 bytes sat behind it.
NULs are now dropped, and a line flushes on CR as well as LF.
Verified: SERIAL UV-K5 Firmware, EGZUMER-F4HWN+NR7Y c91cec95
keypad_test.py still passes, which matters because this file is where removing
three fprintfs once silently deleted the keypad.
69 lines
2.2 KiB
Python
Executable File
69 lines
2.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Firmware serial output must reach the host.
|
|
|
|
App/main.c sends UART_Version over USART1 right after UART_Init(), and _putchar
|
|
routes every printf_ there too. The machine has no USART1 model -- it is one of the
|
|
logging catch-all stubs -- so without help those bytes vanish and the firmware
|
|
appears to print nothing at all.
|
|
|
|
Boots a real emulator on a private socket and checks the bytes come out of QEMU's
|
|
stderr as SERIAL lines.
|
|
|
|
Run: python3 tools/test_serial_capture.py
|
|
"""
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
SIM = os.path.dirname(HERE)
|
|
QEMU = os.path.expanduser("~/qemu-build/qemu-7.2+dfsg/build/qemu-system-arm")
|
|
ELF = os.path.expanduser("~/uvk5-port/uvk5-sat/build/CW/nr7y.cw.elf")
|
|
FLASH = os.path.join(SIM, "assets", "flash.img")
|
|
LOG = "/tmp/uvk5-serial-test.log"
|
|
QMP = "/tmp/uvk5-serial-test.sock"
|
|
|
|
|
|
def main():
|
|
for path, what in ((QEMU, "QEMU binary"), (ELF, "firmware ELF"),
|
|
(FLASH, "flash image")):
|
|
if not os.path.exists(path):
|
|
sys.exit(f"missing {what}: {path}")
|
|
if os.path.exists(QMP):
|
|
os.unlink(QMP)
|
|
|
|
with open(LOG, "wb") as fh:
|
|
proc = subprocess.Popen(
|
|
[QEMU, "-M", f"uv-k5-v3,flash-image={FLASH}", "-nographic",
|
|
"-monitor", "none", "-qmp", f"unix:{QMP},server=on,wait=off",
|
|
"-kernel", ELF],
|
|
stdout=subprocess.DEVNULL, stderr=fh)
|
|
try:
|
|
time.sleep(14)
|
|
finally:
|
|
proc.terminate()
|
|
try:
|
|
proc.wait(timeout=10)
|
|
except subprocess.TimeoutExpired:
|
|
proc.kill()
|
|
if os.path.exists(QMP):
|
|
os.unlink(QMP)
|
|
|
|
text = open(LOG, errors="replace").read()
|
|
lines = [l for l in text.splitlines() if l.startswith("SERIAL")]
|
|
print(f"captured {len(lines)} SERIAL line(s)")
|
|
for line in lines[:10]:
|
|
print(" ", line)
|
|
|
|
if not lines:
|
|
print("\nFAIL no SERIAL output; USART1 DR writes are still being dropped")
|
|
print(" (App/main.c:98 sends UART_Version, so something should appear)")
|
|
return 1
|
|
print("\nPASS firmware serial output reaches the host")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|