Document X4 USB power limits from root hub diagnostics
This commit is contained in:
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user