Document X4 USB power limits from root hub diagnostics

This commit is contained in:
DCCONSTRUCTIONS
2026-09-10 11:04:04 +03:00
parent 505844adc3
commit 3b85299fd9
5 changed files with 178 additions and 12 deletions
@@ -65,7 +65,52 @@ def report():
)
def launch():
def usb_report():
"""Read xHCI root-hub capabilities; never open the attached camera or switch ports.
This is an engineering observation, not an installation prerequisite.
usbutils must already exist: this reader never installs or repairs anything.
The same versioned file is executed in the owner terminal and retained with
its report. A hub's advertised switching capability is not a VBUS measurement.
"""
if os.geteuid() != 0:
raise ValueError("Use the owner terminal")
roots = []
for root in sorted(Path("/sys/bus/usb/devices").glob("usb[0-9]*")):
if not re.fullmatch(r"usb[0-9]+", root.name):
continue
device = root.resolve(strict=True)
if (device.parent / "driver").resolve().name != "xhci_hcd":
continue
if (root / "idVendor").read_text().strip() != "1d6b":
continue
if (root / "idProduct").read_text().strip() not in {"0002", "0003"}:
continue
bus = int((root / "busnum").read_text())
address = int((root / "devnum").read_text())
if not 1 <= bus <= 999 or address != 1:
raise ValueError("Unexpected root-hub address")
before = {"utc": datetime.now(UTC).isoformat(), "monotonic": time.monotonic()}
result = subprocess.run(
["/usr/bin/lsusb", "-v", "-s", f"{bus}:1"],
capture_output=True, text=True, timeout=10,
env={"PATH": "/usr/bin:/bin", "LC_ALL": "C"},
)
roots.append({
"root": str(device), "before": before,
"returncode": result.returncode,
"stdout": result.stdout, "stderr": result.stderr,
})
if not roots:
raise ValueError("No admitted Linux xHCI root hubs")
print(json.dumps({
"schema": "missioncore.node.x4-usb-power-diagnostic/v1",
"utc": datetime.now(UTC).isoformat(), "monotonic": time.monotonic(),
"roots": roots, "port_writes": False, "electrical_measurement": False,
}), flush=True)
def launch(usb=False):
if os.geteuid() == 0:
raise ValueError("Launch as the desktop owner")
source = Path(__file__).resolve()
@@ -76,18 +121,22 @@ def launch():
raise ValueError("Diagnostic artifact changed")
os.umask(0o077)
folder = source.with_suffix("")
if usb:
folder = folder.with_name(folder.name + "-usb")
folder.mkdir(mode=0o700, exist_ok=True)
info = folder.lstat()
if folder.is_symlink() or info.st_uid != os.getuid() or info.st_mode & 0o077:
raise ValueError("Diagnostic directory must be private")
script = folder / "read-report"
title = "чтение возможностей USB-портов" if usb else "чтение ошибки подготовки X4"
mode = "--read-usb" if usb else "--read"
script.write_text(
"#!/bin/bash\nset -uo pipefail\numask 077\nprintf '%s\\n' "
"'Mission Core: чтение ошибки подготовки X4' "
"'Mission Core: " + title + "' "
"'Изменений системы и команд камеры не будет. Введите пароль Ubuntu.'\n"
"/usr/bin/sudo /usr/bin/python3 -I '"
+ str(source)
+ "' --read 2>&1 | /usr/bin/tee '"
+ "' " + mode + " 2>&1 | /usr/bin/tee '"
+ str(folder / "report.json")
+ "'\nmc_x4_result=${PIPESTATUS[0]}\nprintf "
"'\\nКод завершения: %s\\nНажмите Enter, чтобы закрыть.\\n' "
@@ -134,5 +183,9 @@ if __name__ == "__main__":
report()
elif sys.argv[1:] == ["--launch"]:
launch()
elif sys.argv[1:] == ["--read-usb"]:
usb_report()
elif sys.argv[1:] == ["--launch-usb"]:
launch(usb=True)
else:
sys.exit("Use --launch or --read")
sys.exit("Use --launch, --read, --launch-usb or --read-usb")