#!/usr/bin/env python3 """Scan mode for a few seconds while logging every place the scan button might show up (bridge reg 0xBC, HID report bit 7, record flags) plus colour statistics. Saves a colour frame every second to /. Mouse mode is restored on exit.""" import argparse import os import select import sys import time sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) sys.stderr = os.fdopen(os.dup(2), "w") os.dup2(os.open(os.devnull, os.O_WRONLY), 2) # silence libjpeg warnings import cv2 # noqa: E402 import numpy as np # noqa: E402 from myscan.frame import fix_and_extract # noqa: E402 from myscan.xu import XU # noqa: E402 def main(): ap = argparse.ArgumentParser() ap.add_argument("-d", "--duration", type=float, default=12) ap.add_argument("-o", "--out", default="btnprobe") ap.add_argument("--video", default="/dev/video4") ap.add_argument("--hid", default="/dev/hidraw8") a = ap.parse_args() os.makedirs(a.out, exist_ok=True) x = XU(a.video) hid = os.open(a.hid, os.O_RDONLY | os.O_NONBLOCK) log = open(os.path.join(a.out, "log.csv"), "w") log.write("t,src,value\n") try: if not (x.disable_mouse()[0] and x.mcu_write_verified(0x2D, 0x60) and x.mcu_write_verified(0xE7, 0x28) and x.mcu_write_verified(0xE6, 27) and x.start_scan()[0]): sys.exit("failed to enter scan mode") cap = cv2.VideoCapture(a.video, cv2.CAP_V4L2) cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*"MJPG")) cap.set(cv2.CAP_PROP_CONVERT_RGB, 0) print(f"scan mode for {a.duration:.0f}s: press and release the scan button a few times", flush=True) t0, n, last, state = time.time(), 0, -1.0, {} while time.time() - t0 < a.duration: ok, f = cap.read() t = time.time() - t0 while select.select([hid], [], [], 0)[0]: r = os.read(hid, 64) state["hid"] = r[0] >> 7 log.write(f"{t:.3f},hid,{r.hex()}\n") if not ok: continue clean, rec = fix_and_extract(f.tobytes()) im = cv2.imdecode(np.frombuffer(clean, np.uint8), cv2.IMREAD_COLOR) if im is None or rec is None: continue bc = x.bridge_read(0xBC) log.write(f"{t:.3f},bc,{bc}\n{t:.3f},flags,{rec.flags}\n{t:.3f},b16,{rec.b16}\n") changes = [k for k, v in (("bc", bc), ("flags", rec.flags), ("b16", rec.b16)) if state.get(k) != v] for k, v in (("bc", bc), ("flags", rec.flags), ("b16", rec.b16)): state[k] = v if changes: print(f"t={t:5.2f} " + " ".join(f"{k}={state.get(k)}" for k in ("bc", "flags", "b16", "hid")), flush=True) if t - last >= 1: m = im.reshape(-1, 3).mean(0) sat = cv2.cvtColor(im, cv2.COLOR_BGR2HSV)[..., 1].mean() print(f"t={t:5.2f} colour mean BGR={m.round(1)} saturation={sat:.1f}", flush=True) cv2.imwrite(f"{a.out}/c{n:03d}.png", im) last = t n += 1 cap.release() except KeyboardInterrupt: pass finally: print("restore mouse mode:", x.enable_mouse()[0]) log.close() if __name__ == "__main__": main()