diff --git a/cereal/log.capnp b/cereal/log.capnp index b6ccf2f55f122a..70508f36e268b9 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -488,6 +488,7 @@ struct DeviceState @0xa4d8b5af2aa492eb { pmicTempC @39 :List(Float32); intakeTempC @46 :Float32; exhaustTempC @47 :Float32; + caseTempC @48 :Float32; maxTempC @44 :Float32; # max of other temps, used to control fan thermalZones @38 :List(ThermalZone); thermalStatus @14 :ThermalStatus; diff --git a/system/hardware/base.py b/system/hardware/base.py index 0f8b7d8680b2cb..5206753c1d3e9b 100644 --- a/system/hardware/base.py +++ b/system/hardware/base.py @@ -1,11 +1,53 @@ +import os from abc import abstractmethod, ABC -from collections import namedtuple +from dataclasses import dataclass, fields from cereal import log -ThermalConfig = namedtuple('ThermalConfig', ['cpu', 'gpu', 'mem', 'pmic', 'intake', 'exhaust']) NetworkType = log.DeviceState.NetworkType +@dataclass +class ThermalZone: + # a zone from /sys/class/thermal/thermal_zone* + name: str # a.k.a type + scale: float = 1000. # scale to get degrees in C + zone_number = -1 + + def read(self) -> float: + if self.zone_number < 0: + for n in os.listdir("/sys/devices/virtual/thermal"): + if not n.startswith("thermal_zone"): + continue + with open(os.path.join("/sys/devices/virtual/thermal", n, "type")) as f: + if f.read().strip() == self.name: + self.zone_number = int(n.removeprefix("thermal_zone")) + break + + try: + with open(f"/sys/devices/virtual/thermal/thermal_zone{self.zone_number}/temp") as f: + return int(f.read()) / self.scale + except FileNotFoundError: + return 0 + +@dataclass +class ThermalConfig: + cpu: list[ThermalZone] + gpu: list[ThermalZone] + pmic: list[ThermalZone] + memory: ThermalZone + intake: ThermalZone = None + exhaust: ThermalZone = None + case: ThermalZone = None + + def get_msg(self): + ret = {} + for f in fields(ThermalConfig): + v = getattr(self, f.name) + if isinstance(v, list): + ret[f.name + "TempC"] = [x.read() for x in v] + else: + ret[f.name + "TempC"] = v.read() + return ret class HardwareBase(ABC): @staticmethod diff --git a/system/hardware/hardwared.py b/system/hardware/hardwared.py index 15b144ec4e5ade..e9b645691cfe54 100755 --- a/system/hardware/hardwared.py +++ b/system/hardware/hardwared.py @@ -51,41 +51,6 @@ prev_offroad_states: dict[str, tuple[bool, str | None]] = {} -tz_by_type: dict[str, int] | None = None -def populate_tz_by_type(): - global tz_by_type - tz_by_type = {} - for n in os.listdir("/sys/devices/virtual/thermal"): - if not n.startswith("thermal_zone"): - continue - with open(os.path.join("/sys/devices/virtual/thermal", n, "type")) as f: - tz_by_type[f.read().strip()] = int(n.removeprefix("thermal_zone")) - -def read_tz(x): - if x is None: - return 0 - - if isinstance(x, str): - if tz_by_type is None: - populate_tz_by_type() - x = tz_by_type[x] - - try: - with open(f"/sys/devices/virtual/thermal/thermal_zone{x}/temp") as f: - return int(f.read()) - except FileNotFoundError: - return 0 - - -def read_thermal(thermal_config): - dat = messaging.new_message('deviceState', valid=True) - dat.deviceState.cpuTempC = [read_tz(z) / thermal_config.cpu[1] for z in thermal_config.cpu[0]] - dat.deviceState.gpuTempC = [read_tz(z) / thermal_config.gpu[1] for z in thermal_config.gpu[0]] - dat.deviceState.memoryTempC = read_tz(thermal_config.mem[0]) / thermal_config.mem[1] - dat.deviceState.pmicTempC = [read_tz(z) / thermal_config.pmic[1] for z in thermal_config.pmic[0]] - dat.deviceState.intakeTempC = read_tz(thermal_config.intake[0]) / thermal_config.intake[1] - dat.deviceState.exhaustTempC = read_tz(thermal_config.exhaust[0]) / thermal_config.exhaust[1] - return dat def set_offroad_alert_if_changed(offroad_alert: str, show_alert: bool, extra_text: str | None=None): @@ -234,7 +199,8 @@ def hardware_thread(end_event, hw_queue) -> None: if (sm.frame % round(SERVICE_LIST['pandaStates'].frequency * DT_HW) != 0) and not ign_edge: continue - msg = read_thermal(thermal_config) + msg = messaging.new_message('deviceState', valid=True) + msg.deviceState = thermal_config.get_msg() msg.deviceState.deviceType = HARDWARE.get_device_type() try: diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index 89503298418c0e..b69de4dd962e49 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -10,7 +10,7 @@ from cereal import log from openpilot.common.gpio import gpio_set, gpio_init, get_irqs_for_action -from openpilot.system.hardware.base import HardwareBase, ThermalConfig +from openpilot.system.hardware.base import HardwareBase, ThermalConfig, ThermalZone from openpilot.system.hardware.tici import iwlist from openpilot.system.hardware.tici.pins import GPIO from openpilot.system.hardware.tici.amplifier import Amplifier @@ -323,17 +323,19 @@ def shutdown(self): os.system("sudo poweroff") def get_thermal_config(self): - intake, exhaust = (None, 1), (None, 1) + intake, exhaust, case = None, None, None if self.get_device_type() == "mici": - intake = ("intake", 1000) - exhaust = ("exhaust", 1000) - return ThermalConfig(cpu=([f"cpu{i}-silver-usr" for i in range(4)] + - [f"cpu{i}-gold-usr" for i in range(4)], 1000), - gpu=(("gpu0-usr", "gpu1-usr"), 1000), - mem=("ddr-usr", 1000), - pmic=(("pm8998_tz", "pm8005_tz"), 1000), + case = ThermalZone("case") + intake = ThermalZone("intake") + exhaust = ThermalZone("exhaust") + return ThermalConfig(cpu=[ThermalZone(f"cpu{i}-silver-usr") for i in range(4)] + + [ThermalZone(f"cpu{i}-gold-usr") for i in range(4)], + gpu=[ThermalZone("gpu0-usr"), ThermalZone("gpu1-usr")], + memory=ThermalZone("ddr-usr"), + pmic=[ThermalZone("pm8998_tz"), ThermalZone("pm8005_tz")], intake=intake, - exhaust=exhaust) + exhaust=exhaust, + case=case) def set_screen_brightness(self, percentage): try: