#!/usr/bin/env python3 import os import subprocess import sys def parse_hex_byte(s): assert(s.endswith("h")) s = s[:-1] assert(0 <= int(s, 16) <= 255) return "0x" + s def parse_hex_list(s): if s == "n/a": return None if s.startswith("("): assert(s.endswith(")h")) s = s[1:-2] l = [b.strip() for b in s.split(",")] l = [b[:-1] if b.endswith("h") else b for b in l] for b in l: assert(0 <= int(b, 16) <= 255) return "0x" + "".join(l) def parse_timing(page): lines = [l.strip() for l in page.splitlines()] if len(lines) < 6: return None try: i = lines.index("Detailed Timing Parameters") except ValueError: return None raw_metadata = lines[1:i] raw_params = lines[i+1:] metadata = {} for l in raw_metadata: if not ": " in l: continue k, v = l.split(":", 1) metadata[k.strip()] = v.strip() assert("Resolution" in metadata and "EDID ID" in metadata) if "Proposed" in metadata and not "Adopted" in metadata: print("skipping proposed but not adopted timing: " + metadata["Resolution"], file=sys.stderr) return None params = {} for l in raw_params: if not " = " in l: continue tokens = [l.strip() for l in l.split("=")] params[tokens[0]] = tokens[1:] assert("Timing Name" in params) res = metadata["Resolution"] size, rest = res.split(" at ", 1) horiz_video, vert_video = size.split("x", 1) refresh_rate_hz, rest = rest.split(" Hz ", 1) horiz_video = int(horiz_video.strip()) vert_video = int(vert_video.strip()) refresh_rate_hz = float(refresh_rate_hz.strip()) ids = {} for kv in metadata["EDID ID"].split(";"): k, v = kv.split(":") ids[k.strip()] = v.strip() assert("DMT ID" in ids) dmt_id = parse_hex_byte(ids["DMT ID"]) edid_std_id = parse_hex_list(ids["Std. 2 Byte Code"]) cvt_id = parse_hex_list(ids["CVT 3 Byte Code"]) return { "dmt_id": dmt_id, "edid_std_id": 0 if edid_std_id is None else edid_std_id, "cvt_id": 0 if cvt_id is None else cvt_id, "horiz_video": horiz_video, "vert_video": vert_video, "refresh_rate_hz": refresh_rate_hz, } if len(sys.argv) != 2: print("usage: gen-dmt.py ", file=sys.stderr) sys.exit(1) in_path = sys.argv[1] in_basename = os.path.basename(in_path) tool_dir = os.path.dirname(os.path.realpath(__file__)) out_path = tool_dir + "/../dmt-table.c" cmd = ["pdftotext", "-nodiag", "-layout", in_path, "-"] page = "" timings = [] for l in subprocess.check_output(cmd, text=True): if l.startswith("\f"): t = parse_timing(page) if t is not None: timings.append(t) page = l[1:] else: page += l with open(out_path, "w+") as f: f.write("/* DO NOT EDIT! This file has been generated by gen-dmt.py from {}. */\n\n".format(in_basename)) f.write('#include "dmt.h"\n\n') f.write("const struct di_dmt_timing _di_dmt_timings[] = {\n") for t in timings: f.write("\t{\n") for k, v in t.items(): f.write("\t\t.{} = {},\n".format(k, v)) f.write("\t},\n") f.write("};\n\n") f.write("const size_t _di_dmt_timings_len = {};\n".format(len(timings)))