""" device_server.py — deploy this on the target device (192.168.45.8) Provides: PUT /display {"state": "on"|"off"} — blank/unblank framebuffer GET /registers — read MIPI DSI PHY registers via memtool Add addresses to REGISTER_COMMANDS to capture more register ranges. """ import os import re import subprocess from flask import Flask, jsonify, request app = Flask(__name__) # --------------------------------------------------------------------------- # Register commands to execute on each GET /registers request. # Each entry is a complete memtool command string. # --------------------------------------------------------------------------- REGISTER_COMMANDS = [ "memtool md -l 0x32e100b4+0x0c", # DSIM_PHYTIMING / PHYTIMING1 / PHYTIMING2 ] # Known Samsung DSIM register names (base 0x32E10000, i.MX 8M Mini) _DSIM_NAMES = { 0x32e10004: "DSIM_STATUS", 0x32e10008: "DSIM_CLKCTRL", 0x32e1000c: "DSIM_TIMEOUT", 0x32e10010: "DSIM_CONFIG", 0x32e10014: "DSIM_ESCMODE", 0x32e100ac: "DSIM_PHYACCHR", 0x32e100b0: "DSIM_PHYACCHR1", 0x32e100b4: "DSIM_PHYTIMING", 0x32e100b8: "DSIM_PHYTIMING1", 0x32e100bc: "DSIM_PHYTIMING2", } def _parse_memtool_output(raw: str) -> list: """ Parse 'memtool md -l' output into a list of dicts. Handles both formats: 32e100b4: 00000001 12345678 ... 0x32e100b4: 0x00000001 0x12345678 ... """ registers = [] for line in raw.splitlines(): line = line.strip() if not line: continue m = re.match(r"(?:0x)?([0-9a-fA-F]+)\s*:\s*(.+)", line) if not m: continue base_addr = int(m.group(1), 16) values = re.findall(r"[0-9a-fA-F]{8}", m.group(2)) for i, val in enumerate(values): addr = base_addr + i * 4 registers.append({ "address": f"0x{addr:08x}", "value": f"0x{val.lower()}", "name": _DSIM_NAMES.get(addr, ""), }) return registers # --------------------------------------------------------------------------- # Routes # --------------------------------------------------------------------------- @app.route("/display", methods=["PUT"]) def control_display(): data = request.get_json() state = data.get("state", "").lower() if state == "off": os.system("echo 4 > /sys/class/graphics/fb0/blank") return jsonify({"status": "Display OFF"}), 200 elif state == "on": os.system("echo 0 > /sys/class/graphics/fb0/blank") return jsonify({"status": "Display ON"}), 200 else: return jsonify({"error": "Invalid state. Use 'on' or 'off'"}), 400 @app.route("/registers", methods=["GET"]) def get_registers(): """Read MIPI DSI PHY timing registers via memtool and return JSON.""" all_registers = [] raw_lines = [] errors = [] for cmd_str in REGISTER_COMMANDS: try: result = subprocess.run( cmd_str.split(), capture_output=True, text=True, timeout=5 ) raw = result.stdout.strip() if raw: raw_lines.append(raw) all_registers.extend(_parse_memtool_output(raw)) if result.returncode != 0 and result.stderr.strip(): errors.append(f"{cmd_str}: {result.stderr.strip()}") except FileNotFoundError: errors.append(f"{cmd_str}: memtool not found in PATH") except subprocess.TimeoutExpired: errors.append(f"{cmd_str}: timed out after 5 s") except Exception as e: errors.append(f"{cmd_str}: {e}") return jsonify({ "commands": REGISTER_COMMANDS, "registers": all_registers, "raw": "\n".join(raw_lines), "errors": errors if errors else None, }), 200 if __name__ == "__main__": app.run(host="0.0.0.0", port=5000)