mirror of
https://github.com/kbeckmann/game-and-watch-retro-go.git
synced 2025-12-16 13:15:55 +01:00
93 lines
2.7 KiB
Python
Executable File
93 lines
2.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import os
|
|
import v4l2
|
|
|
|
from elftools.elf.elffile import ELFFile
|
|
from fcntl import ioctl
|
|
from openocd import OpenOCD
|
|
|
|
# 1. Create a v4l2 loopback and find out the name (/dev/video0 etc):
|
|
# sudo modprobe v4l2loopback
|
|
# 2. Start openocd with a fast adapter speed separately:
|
|
# openocd -f interface/jlink.cfg -c "transport select swd;" -f target/stm32h7x.cfg -c "adapter speed 10000; init;"
|
|
# 3. python3 tools/screengrabber.py
|
|
|
|
def get_symbol_by_symbol_name(elffile, symbol_name):
|
|
return elffile.get_section_by_name('.symtab').get_symbol_by_name(symbol_name)[0]
|
|
|
|
def screengrabber(args):
|
|
# Find address of framebuffer
|
|
with open(args.elf, "rb") as f:
|
|
elffile = ELFFile(f)
|
|
fb_address = get_symbol_by_symbol_name(elffile, "framebuffer1").entry.st_value
|
|
|
|
# Open camera driver
|
|
fd = os.open(args.device, os.O_RDWR, 0)
|
|
|
|
cap = v4l2.v4l2_capability()
|
|
|
|
ioctl(fd, v4l2.VIDIOC_QUERYCAP, cap)
|
|
|
|
BUFTYPE = v4l2.V4L2_BUF_TYPE_VIDEO_OUTPUT
|
|
FRAME_FORMAT = v4l2.V4L2_PIX_FMT_RGB565
|
|
|
|
# Set format
|
|
width = args.width
|
|
height = args.height
|
|
sizeimage = width * height * 2
|
|
linewidth = width
|
|
|
|
fmt = v4l2.v4l2_format()
|
|
fmt.type = BUFTYPE
|
|
fmt.fmt.pix.width = width
|
|
fmt.fmt.pix.height = height
|
|
fmt.fmt.pix.pixelformat = FRAME_FORMAT
|
|
fmt.fmt.pix.sizeimage = sizeimage
|
|
fmt.fmt.pix.field = v4l2.V4L2_FIELD_NONE
|
|
fmt.fmt.pix.bytesperline = linewidth
|
|
fmt.fmt.pix.colorspace = v4l2.V4L2_COLORSPACE_SRGB
|
|
|
|
ret = ioctl(fd, v4l2.VIDIOC_S_FMT, fmt)
|
|
print("fcntl.ioctl(fd, v4l2.VIDIOC_S_FMT, fmt) = %d" % ret)
|
|
|
|
buffer_size = fmt.fmt.pix.sizeimage
|
|
|
|
with OpenOCD(host=args.host, port=args.port) as ocd:
|
|
while True:
|
|
fb = ocd.send(f"dump_image fb.bin {hex(fb_address)} {hex(buffer_size)}; exit")
|
|
with open("fb.bin", "rb") as f_in:
|
|
os.write(fd, f_in.read())
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser(description="Grabs the framebuffer and renders it to a video4l2 device")
|
|
parser.add_argument(
|
|
"--elf",
|
|
type=str,
|
|
default="build/gw_retro_go.elf",
|
|
help="Game and Watch Retro-Go ELF file",
|
|
)
|
|
parser.add_argument(
|
|
"--host",
|
|
type=str,
|
|
default="127.0.0.1",
|
|
help="OpenOCD TCL hostname",
|
|
)
|
|
parser.add_argument(
|
|
"--port",
|
|
type=int,
|
|
default=6666,
|
|
help="OpenOCD TCL port",
|
|
)
|
|
parser.add_argument(
|
|
"--device",
|
|
type=str,
|
|
default="/dev/video0",
|
|
help="video4l2 device",
|
|
)
|
|
parser.add_argument("--width", type=int, default=320)
|
|
parser.add_argument("--height", type=int, default=240)
|
|
|
|
screengrabber(parser.parse_args())
|