Skip to content
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions cereal/log.capnp
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,14 @@ struct PeripheralState {
}
}

struct UsbState {
connected @0 :Bool;
speedMbps @1 :UInt16;
pmActive @2 :Bool;
disconnectCount @3 :UInt32;
overCurrentCount @4 :UInt32;
}

struct RadarState @0x9a185389d6fdd05f {
mdMonoTime @6 :UInt64;
carStateMonoTime @11 :UInt64;
Expand Down Expand Up @@ -2472,6 +2480,7 @@ struct Event {
temperatureSensor @97 :SensorEventData;
pandaStates @81 :List(PandaState);
peripheralState @80 :PeripheralState;
usbState @152 :UsbState;
radarState @13 :RadarState;
liveTracks @131 :Car.RadarData;
sendcan @17 :List(CanData);
Expand Down
1 change: 1 addition & 0 deletions cereal/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def __init__(self, should_log: bool, frequency: float, decimation: Optional[int]
"selfdriveState": (True, 100., 10),
"pandaStates": (True, 10., 1),
"peripheralState": (True, 2., 1),
"usbState": (True, 10., 1),
"radarState": (True, 20., 5),
"roadEncodeIdx": (False, 20., 1),
"liveTracks": (True, 20.),
Expand Down
1 change: 1 addition & 0 deletions selfdrive/test/test_onroad.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"selfdrive.modeld.modeld": 22.0,
"selfdrive.modeld.dmonitoringmodeld": 18.0,
"system.hardware.hardwared": 4.0,
"system.hardware.usbd": 1.0,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this just goes in hardwared

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about 100Hz+ usb state sampling inside usbd to catch transients but could do that in the kernel with interrupts and sample only the resulting counters in hardwared with 2Hz

"selfdrive.locationd.calibrationd": 2.0,
"selfdrive.locationd.torqued": 5.0,
"selfdrive.locationd.locationd": 25.0,
Expand Down
71 changes: 71 additions & 0 deletions system/hardware/usbd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env python3
from pathlib import Path

from cereal import messaging
from openpilot.common.realtime import Ratekeeper
from openpilot.common.swaglog import cloudlog
from openpilot.selfdrive.modeld.helpers import USBGPU_VID, USBGPU_PID

RATE = 10 # Hz


def find_device() -> Path | None:
# discover the eGPU by VID/PID
for d in Path("/sys/bus/usb/devices").glob("*"):
try:
if int((d / "idVendor").read_text(), 16) == USBGPU_VID and \
int((d / "idProduct").read_text(), 16) == USBGPU_PID:
return d
except Exception:
pass
return None


def read(device: Path, attr: str) -> str | None:
try:
return (device / attr).read_text().strip()
except OSError:
return None


def over_current_count(device: Path) -> int:
# upstream root-hub port, e.g. device "4-1" -> usb4/4-0:1.0/usb4-port1
bus, _, port = device.name.partition("-")
try:
return int((Path(f"/sys/bus/usb/devices/usb{bus}/{bus}-0:1.0/usb{bus}-port{port}") / "over_current_count").read_text())
except (OSError, ValueError):
return 0


def main():
pm = messaging.PubMaster(['usbState'])
rk = Ratekeeper(RATE)
disconnect_count = 0
was_connected = False

while True:
device = find_device()
connected = device is not None
if was_connected and not connected:
disconnect_count += 1
cloudlog.event("usb_disconnected", count=disconnect_count)
elif connected and not was_connected:
cloudlog.event("usb_connected", speed=read(device, "speed"))
was_connected = connected

msg = messaging.new_message('usbState', valid=True)
state = msg.usbState
state.connected = connected
if device is not None:
speed = read(device, "speed")
state.speedMbps = int(speed) if (speed and speed.isdigit()) else 0
state.pmActive = read(device, "power/runtime_status") == "active"
state.overCurrentCount = over_current_count(device)
state.disconnectCount = disconnect_count

pm.send('usbState', msg)
rk.keep_time()


if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions system/manager/process_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def and_(*fns):
PythonProcess("lateral_maneuversd", "tools.lateral_maneuvers.lateral_maneuversd", lat_maneuver),
PythonProcess("radard", "selfdrive.controls.radard", only_onroad),
PythonProcess("hardwared", "system.hardware.hardwared", always_run),
PythonProcess("usbd", "system.hardware.usbd", always_run),
PythonProcess("modem", "system.hardware.tici.modem", always_run, enabled=TICI),
PythonProcess("tombstoned", "system.tombstoned", always_run, enabled=not PC),
PythonProcess("updated", "system.updated.updated", only_offroad, enabled=not PC),
Expand Down
Loading