Files
uv-k5-v3-emulator/tools/panel_dump.py
T
mckero e1ffdf8fdd panel_dump: say why QMP is unreachable, and exit 2 for it
QMP takes a single client and the web UI holds it for its whole lifetime, so this is the normal outcome while the page is open rather than a broken emulator. Verified against a private instance: 128x64, 1819 pixels lit, 64 rows of ASCII.
2026-10-01 15:23:27 +08:00

72 lines
3.2 KiB
Python

#!/usr/bin/env python3
"""Render the display controller's own memory, for any firmware, without a browser.
The web page already does this; this is the same thing from a shell, which is what you
want when the question is "does *this* build render correctly" and the answer has to be
compared rather than glanced at. It prints ASCII at one character per LCD pixel, so two
builds can be diffed, and can also write a scaled PNG.
tools/panel_dump.py --qmp 127.0.0.1:4444 # ASCII, as the panel shows it
tools/panel_dump.py --qmp 127.0.0.1:4444 --mapping mirror-cols
tools/panel_dump.py --qmp 127.0.0.1:4444 --png work/screen.png
The --mapping option exists because which mapping is right is a property of the *driver*,
not of the controller. Two builds can program identical panel registers -- 0xA1 segment
reverse, 0xC0, 0xA6 -- and still arrive in different orders, because one compensates in
software and the other does not. Measured on the 5.9.0.CN build against its own
framebuffer: 8188 of 8192 pixels agree with the panel data untouched, 6954 with the
columns mirrored.
"""
import argparse
import sys
import uvk5_lcd
def main(argv=None):
ap = argparse.ArgumentParser(description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument("--qmp", default="127.0.0.1:4444",
help="the emulator's QMP endpoint (host:port or unix:path)")
ap.add_argument("--mapping", default="identity",
choices=["identity", "mirror-cols", "mirror-rows", "both"])
ap.add_argument("--png", help="write a scaled PNG here instead of ASCII")
ap.add_argument("--scale", type=int, default=4)
args = ap.parse_args(argv)
from uvk5_qmp import QmpClient
# The frame addresses are unused on this path: the controller has its own memory.
try:
client = QmpClient(args.qmp, timeout=20)
except Exception as exc:
# QMP takes one client, and the web UI holds it for its whole lifetime -- so this
# is the normal outcome while the page is open, not a broken emulator.
print('cannot reach QMP at %s: %s' % (args.qmp, str(exc).splitlines()[0]), file=sys.stderr)
print('if the web UI is running it is holding the one QMP client; stop it, or use',
file=sys.stderr)
print('--qmp with the endpoint of an emulator started by tools/run.sh instead.',
file=sys.stderr)
return 2
grab = uvk5_lcd.FrameGrabber(client, 0, 0)
pixels = grab.panel_pixels()
if args.mapping in ("mirror-cols", "both"):
pixels = [list(reversed(row)) for row in pixels]
if args.mapping in ("mirror-rows", "both"):
pixels = list(reversed(pixels))
if args.png:
with open(args.png, "wb") as fh:
fh.write(uvk5_lcd.encode_png(pixels, args.scale))
print("wrote %s (%d x %d)" % (args.png, len(pixels[0]), len(pixels)))
return 0
print("panel %d x %d, %d pixels lit, mapping %s"
% (len(pixels[0]), len(pixels), sum(sum(r) for r in pixels), args.mapping))
for row in pixels:
print("".join("#" if value else "." for value in row))
return 0
if __name__ == "__main__":
sys.exit(main())