#!/usr/bin/env python3 # -*- coding: utf-8 -*- """从设备树复算 gpio-in-N 对应的全局 GPIO 号。""" from pathlib import Path from .config import DEVICETREE_BASE def _read_be32(path: Path, offset: int = 0): try: data = path.read_bytes() except OSError: return None if len(data) < offset + 4: return None return int.from_bytes(data[offset:offset + 4], "big") def derive_gpio(n: int, base_dir: str = DEVICETREE_BASE): """从设备树复算 IN 的全局 GPIO 号。 返回 (gpio_num, label, pin) 或 None。 """ base = Path(base_dir) f = base / f"gpio-in-{n}" / "control-gpios" if not f.exists(): return None try: data = f.read_bytes() except OSError: return None if len(data) < 8: return None ph = int.from_bytes(data[0:4], "big") pin = int.from_bytes(data[4:8], "big") # phandle -> gpio-controller 节点 ctrl = None for c in base.glob("gpio@*/gpio-controller@*"): cph = _read_be32(c / "phandle") if cph == ph: ctrl = c break if ctrl is None: return None bank = ctrl.parent.name if bank.startswith("gpio@"): bank = bank[len("gpio@"):] label = f"{bank}.gpio" # label -> gpiochip base gpio_class = Path("/sys/class/gpio") if not gpio_class.exists(): return None for g in gpio_class.glob("gpiochip*"): try: if (g / "label").read_text().strip() == label: chip_base = int((g / "base").read_text().strip()) return chip_base + pin, label, pin except (OSError, ValueError): continue return None