mirror of
https://jihulab.com/mr-one/openpilot.git
synced 2026-10-27 21:13:42 +08:00
This reverts commit 7d5596d5c3527f274a3615181f52095909ffb8e9. (cherry picked from commit c9f1602040149be793ea3d3e17a5fd8d915408c8)
This commit is contained in:
committed by
Comma Device
parent
5f4e447a3f
commit
b66b3af59c
@@ -2593,7 +2593,6 @@ struct Event {
|
||||
clocks @35 :Clocks;
|
||||
deviceState @6 :DeviceState;
|
||||
chestnutState @152 :ChestnutState;
|
||||
chestnutGpuState @153 :ChestnutState;
|
||||
logMessage @18 :Text;
|
||||
errorLogMessage @85 :Text;
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ _services: dict[str, tuple] = {
|
||||
"temperatureSensor": (True, 2., 200),
|
||||
"deviceState": (True, 2., 1),
|
||||
"chestnutState": (True, 10., 10),
|
||||
"chestnutGpuState": (False, 10.),
|
||||
"touch": (True, 20., 1),
|
||||
"can": (True, 100., 2053, QueueSize.BIG), # decimation gives ~3 msgs in a full segment
|
||||
"controlsState": (True, 100., 10, QueueSize.MEDIUM),
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
import struct
|
||||
from contextlib import suppress
|
||||
|
||||
import usb1
|
||||
|
||||
import openpilot.cereal.messaging as messaging
|
||||
from openpilot.cereal.services import SERVICE_LIST
|
||||
from openpilot.common.hardware.usb import CHESTNUT_USB_IDS
|
||||
|
||||
|
||||
USB_TIMEOUT_MS = 100
|
||||
PCIE_LTSSM_ADDRESS = 0xB450
|
||||
|
||||
|
||||
class ChestnutUsb:
|
||||
def __init__(self):
|
||||
self.context: usb1.USBContext | None = None
|
||||
self.handle = None
|
||||
|
||||
def close(self) -> None:
|
||||
handle, context = self.handle, self.context
|
||||
self.handle = None
|
||||
self.context = None
|
||||
with suppress(Exception):
|
||||
if handle is not None:
|
||||
handle.close()
|
||||
with suppress(Exception):
|
||||
if context is not None:
|
||||
context.close()
|
||||
|
||||
def connect(self) -> bool:
|
||||
if self.handle is not None:
|
||||
return True
|
||||
|
||||
context = usb1.USBContext()
|
||||
for vendor_id, product_id in CHESTNUT_USB_IDS:
|
||||
handle = context.openByVendorIDAndProductID(vendor_id, product_id, skip_on_error=True)
|
||||
if handle is not None:
|
||||
self.context = context
|
||||
self.handle = handle
|
||||
return True
|
||||
context.close()
|
||||
return False
|
||||
|
||||
def _read(self, request: int, value: int, length: int) -> bytes:
|
||||
if self.handle is None:
|
||||
raise usb1.USBErrorNoDevice
|
||||
raw = bytes(self.handle.controlRead(0xC0, request, value, 0, length, timeout=USB_TIMEOUT_MS))
|
||||
if len(raw) != length:
|
||||
raise ValueError(f"short chestnut USB response: {len(raw)}/{length}")
|
||||
return raw
|
||||
|
||||
def read_ina(self) -> tuple[int, int, bool]:
|
||||
return struct.unpack('<Hh?', self._read(0xC0, 0, 5))
|
||||
|
||||
def read_pcie_ltssm(self) -> int:
|
||||
return self._read(0xE4, PCIE_LTSSM_ADDRESS, 1)[0]
|
||||
|
||||
|
||||
class ChestnutMonitoring:
|
||||
def __init__(self, usb: ChestnutUsb | None = None):
|
||||
self.usb = usb or ChestnutUsb()
|
||||
self.gpu_state = None
|
||||
self.seen = False
|
||||
self.enabled = False
|
||||
self.usb_failed = False
|
||||
|
||||
def set_enabled(self, enabled: bool) -> None:
|
||||
if self.enabled == enabled:
|
||||
return
|
||||
self.enabled = enabled
|
||||
self.usb.close()
|
||||
self.usb_failed = False
|
||||
|
||||
def retry(self) -> None:
|
||||
self.usb_failed = False
|
||||
|
||||
def model_alive(self, sm: messaging.SubMaster, now: float) -> bool:
|
||||
modeld = next((p for p in sm['managerState'].processes if p.name == 'modeld'), None)
|
||||
if modeld is not None and modeld.shouldBeRunning and not modeld.running:
|
||||
return False
|
||||
recv_time = sm.recv_time['chestnutGpuState']
|
||||
return recv_time > 0. and now - recv_time < 10. / SERVICE_LIST['chestnutGpuState'].frequency
|
||||
|
||||
def update_gpu_state(self, sm: messaging.SubMaster, now: float) -> None:
|
||||
if sm.updated['chestnutGpuState']:
|
||||
self.gpu_state = sm['chestnutGpuState'] if sm.valid['chestnutGpuState'] else None
|
||||
elif not self.model_alive(sm, now):
|
||||
self.gpu_state = None
|
||||
|
||||
def update(self, sm: messaging.SubMaster, now: float, model_loading: bool = False):
|
||||
self.update_gpu_state(sm, now)
|
||||
return self.build_message(model_loading)
|
||||
|
||||
def build_message(self, model_loading: bool = False):
|
||||
if not self.enabled:
|
||||
return None
|
||||
|
||||
msg = messaging.new_message('chestnutState')
|
||||
if self.gpu_state is not None:
|
||||
msg.chestnutState = self.gpu_state
|
||||
state = msg.chestnutState
|
||||
|
||||
if self.usb_failed:
|
||||
return msg if self.seen else None
|
||||
|
||||
try:
|
||||
if not self.usb.connect():
|
||||
self.usb_failed = True
|
||||
return msg if self.seen else None
|
||||
|
||||
self.seen = True
|
||||
voltage, current, fault = self.usb.read_ina()
|
||||
pcie_ltssm = self.usb.read_pcie_ltssm()
|
||||
state.supplyVoltage = voltage
|
||||
state.supplyCurrent = current
|
||||
state.supplyFault = fault
|
||||
state.pcieLtssm = pcie_ltssm
|
||||
msg.valid = True
|
||||
except Exception as e:
|
||||
if not model_loading or not isinstance(e, usb1.USBErrorTimeout):
|
||||
self.usb.close()
|
||||
self.usb_failed = True
|
||||
return msg
|
||||
@@ -21,13 +21,14 @@ class ChestnutStatus:
|
||||
self.power_lost = False
|
||||
self.power_restored = False
|
||||
self.link_failures = 0
|
||||
self.model_loading_seen = False
|
||||
self.model_attempted = False
|
||||
self.overheated = False
|
||||
self.usb_seen = False
|
||||
self.usb_failed = False
|
||||
|
||||
def update(self, offroad: bool, branch: str, usb_state: list[dict], firmware_failed: bool,
|
||||
model_active: bool | None, state, usb_failed: bool, set_alert) -> None:
|
||||
model_loading: bool, model_active: bool | None, state, set_alert) -> None:
|
||||
detected = [d for d in usb_state if is_chestnut_usb_id(d["vendorId"], d["productId"], include_bootloader=True)]
|
||||
devices = [d for d in detected if is_chestnut_usb_id(d["vendorId"], d["productId"])]
|
||||
firmware_ok = len(devices) == 1 and devices[0]["product"] == CHESTNUT_USB_PRODUCT
|
||||
@@ -39,15 +40,16 @@ class ChestnutStatus:
|
||||
self.power_lost = False
|
||||
self.power_restored = False
|
||||
self.link_failures = 0
|
||||
self.model_loading_seen = False
|
||||
self.model_attempted = False
|
||||
self.usb_seen = firmware_ok
|
||||
self.usb_failed = False
|
||||
|
||||
self.model_attempted |= model_active is not None
|
||||
self.model_loading_seen |= model_loading
|
||||
self.model_attempted |= self.model_loading_seen and not model_loading and model_active is not None
|
||||
|
||||
if not offroad:
|
||||
self.usb_seen |= firmware_ok
|
||||
self.usb_failed = not offroad and self.usb_seen and (not firmware_ok or usb_failed)
|
||||
if not offroad and self.usb_seen and not firmware_ok:
|
||||
self.usb_failed = True
|
||||
|
||||
if not offroad and state is not None:
|
||||
powered = state.supplyVoltage >= CHESTNUT_POWERED_VOLTAGE
|
||||
@@ -78,28 +80,17 @@ class ChestnutStatus:
|
||||
release = branch in CHESTNUT_RELEASE_BRANCHES
|
||||
missing = self.usb_failed or (offroad and release and time.monotonic() - self.started > 10. and len(detected) != 1)
|
||||
slow_usb = offroad and len(devices) == 1 and devices[0]["speedMbps"] < 5000
|
||||
update_failed = offroad and firmware_failed
|
||||
compiled = firmware_ok and chestnut_compiled()
|
||||
uncompiled = offroad and firmware_ok and not compiled
|
||||
|
||||
set_alert("Offroad_ChestnutBranch", not release and len(devices) == 1)
|
||||
set_alert("Offroad_ChestnutNotDetected", missing)
|
||||
set_alert("Offroad_ChestnutOverheated", self.overheated, f"{state.tempC:.0f} °C" if state is not None else None)
|
||||
set_alert("Offroad_ChestnutUsbSlow", slow_usb, f"{devices[0]['speedMbps']} Mbps" if slow_usb else None)
|
||||
if self.power_lost:
|
||||
pcie_alert = ("Chestnut power restored. 12V is stable again, cycle ignition." if self.power_restored else
|
||||
"Chestnut power disconnected. Check 12V connection, then cycle ignition." if self.power_unavailable else
|
||||
"Chestnut power lost. Possibly caused by an engine-crank voltage drop. Check 12V connection, then cycle ignition.")
|
||||
else:
|
||||
pcie_alert = "Chestnut GPU unavailable. PCIe link is not up. Check the GPU is securely seated."
|
||||
|
||||
alerts = (
|
||||
("Offroad_ChestnutNotDetected", missing, None),
|
||||
("Offroad_ChestnutUpdateFailed", update_failed, None),
|
||||
("Offroad_ChestnutUncompiled", uncompiled, None),
|
||||
("Offroad_ChestnutPcieUnavailable", self.pcie_failed, pcie_alert),
|
||||
("Offroad_ChestnutOverheated", self.overheated, f"{state.tempC:.0f} °C" if state is not None else None),
|
||||
("Offroad_ChestnutUsbSlow", slow_usb, f"{devices[0]['speedMbps']} Mbps" if slow_usb else None),
|
||||
)
|
||||
active_alert = next((name for name, active, _ in alerts if active), None)
|
||||
|
||||
set_alert("Offroad_ChestnutBranch", not release and len(devices) == 1 and not missing)
|
||||
for name, _, extra_text in alerts:
|
||||
set_alert(name, name == active_alert, extra_text)
|
||||
set_alert("Offroad_ChestnutPcieUnavailable", self.pcie_failed, pcie_alert)
|
||||
set_alert("Offroad_ChestnutUncompiled", offroad and firmware_ok and not chestnut_compiled())
|
||||
set_alert("Offroad_ChestnutUpdateFailed", offroad and firmware_failed)
|
||||
self.offroad = offroad
|
||||
|
||||
Reference in New Issue
Block a user