#!/usr/bin/python3

import hashlib
import uuid
import os
import glob

CHID_NAMESPACE = uuid.UUID("70ffd812-4c7f-4c7d-0000-000000000000")

def get_dmi_value(node):
    try:
        path = f"/sys/class/dmi/id/{node}"
        if os.path.exists(path):
            with open(path, 'r') as f:
                return f.read().strip()
    except:
        pass
    return None

def generate_chid(fields):
    if not all(fields):
        return None

    data_string = "&".join(fields)
    encoded_string = data_string.encode('utf-16-le')

    hash_obj = hashlib.sha1(CHID_NAMESPACE.bytes + encoded_string).digest()

    raw = list(hash_obj[:16])
    raw[6] = (raw[6] & 0x0f) | 0x50
    raw[8] = (raw[8] & 0x3f) | 0x80

    return uuid.UUID(bytes=bytes(raw))

def get_edid_info():
    panels = []
    for edid_path in glob.glob("/sys/class/drm/*/edid"):
        try:
            with open(edid_path, "rb") as f:
                blob = f.read()
                panel_id = parse_edid(blob)
                if panel_id:
                    panels.append(panel_id)
        except (IOError, PermissionError):
            continue
    if len(panels) != 1:
        print("Invalid number of monitors, skipping EDID CHID extensions")
        return None
    return panels[0]

def parse_edid(blob):
    if len(blob) < 128:
        return None
    EDID_FIXED_HEADER = b'\x00\xff\xff\xff\xff\xff\xff\x00'
    if blob[0:8] != EDID_FIXED_HEADER:
        return None
    m_id = int.from_bytes(blob[8:10], byteorder='big')
    m_chars = [''] * 3
    for i in range(3):
        letter = (m_id >> (5 * i)) & 0b11111
        if letter > 0b11010: # 26
            return None
        m_chars[2 - i] = chr(letter + ord('A') - 1)
    manuf_name = "".join(m_chars)
    p_code = int.from_bytes(blob[10:12], byteorder='little')
    panel_id = f"{manuf_name}{p_code:04x}"
    return panel_id

def main():
    m = get_dmi_value("sys_vendor")
    f = get_dmi_value("product_family")
    p = get_dmi_value("product_name")
    s = get_dmi_value("product_sku")
    c = get_dmi_value("chassis_type")
    bn = get_dmi_value("board_name")
    bv = get_dmi_value("board_vendor")
    e = get_edid_info()

    smbios_definitions = [
        (3,  [m, f, p, s, bv, bn], "Manufacturer + Family + ProductName + ProductSku + BaseboardManufacturer + BaseboardProduct"),
        (4,  [m, f, p, s],         "Manufacturer + Family + ProductName + ProductSku"),
        (5,  [m, f, p],            "Manufacturer + Family + ProductName"),
        (6,  [m, s, bv, bn],       "Manufacturer + ProductSku + BaseboardManufacturer + BaseboardProduct"),
        (7,  [m, s],               "Manufacturer + ProductSku"),
        (8,  [m, p, bv, bn],       "Manufacturer + ProductName + BaseboardManufacturer + BaseboardProduct"),
        (9,  [m, p],               "Manufacturer + ProductName"),
        (10, [m, f, bv, bn],       "Manufacturer + Family + BaseboardManufacturer + BaseboardProduct"),
        (11, [m, f],               "Manufacturer + Family"),
        (11, [m, c],               "Manufacturer + EnclosureKind"),
        (13, [m, bv, bn],          "Manufacturer + BaseboardManufacturer + BaseboardProduct"),
        (14, [m],                  "Manufacturer"),
        (15, [m, f, p, e],         "Manufacturer + Family + ProductName + EDID"),
        (16, [m, f, e],            "Manufacturer + Family + EDID"),
        (17, [m, s, e],            "Manufacturer + ProductSku + EDID")
    ]

    print(f"Computer Information")
    print("--------------------")
    print(f"Manufacturer: {m}")
    print(f"Family: {f}")
    print(f"ProductName: {p}")
    print(f"ProductSku: {s}")
    print(f"BaseboardManufacturer: {bv}")
    print(f"BaseboardProduct: {bn}")
    print(f"EDID: {e}")

    print(f"Hardware IDs")
    print("------------")
    for level, fields, descr in smbios_definitions:
        chid = generate_chid(fields)
        val = str(chid) if chid else "---"
        if chid:
            print(f"{{{val}}}\t<- #{level:<3} {descr}")

if __name__ == "__main__":
    main()
