system/hardware: refactor thermal config (#34177)

* system/hardware: refactor thermal config

* fix

* fixup

---------

Co-authored-by: Comma Device <device@comma.ai>
pull/34178/head
Adeeb Shihadeh 5 months ago committed by GitHub
parent be67d5a1d9
commit 2e9540d2b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      cereal/log.capnp
  2. 50
      system/hardware/base.py
  3. 38
      system/hardware/hardwared.py
  4. 5
      system/hardware/pc/hardware.py
  5. 22
      system/hardware/tici/hardware.py

@ -488,6 +488,7 @@ struct DeviceState @0xa4d8b5af2aa492eb {
pmicTempC @39 :List(Float32); pmicTempC @39 :List(Float32);
intakeTempC @46 :Float32; intakeTempC @46 :Float32;
exhaustTempC @47 :Float32; exhaustTempC @47 :Float32;
caseTempC @48 :Float32;
maxTempC @44 :Float32; # max of other temps, used to control fan maxTempC @44 :Float32; # max of other temps, used to control fan
thermalZones @38 :List(ThermalZone); thermalZones @38 :List(ThermalZone);
thermalStatus @14 :ThermalStatus; thermalStatus @14 :ThermalStatus;

@ -1,11 +1,54 @@
import os
from abc import abstractmethod, ABC from abc import abstractmethod, ABC
from collections import namedtuple from dataclasses import dataclass, fields
from cereal import log from cereal import log
ThermalConfig = namedtuple('ThermalConfig', ['cpu', 'gpu', 'mem', 'pmic', 'intake', 'exhaust'])
NetworkType = log.DeviceState.NetworkType 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] | None = None
gpu: list[ThermalZone] | None = None
pmic: list[ThermalZone] | None = None
memory: ThermalZone | None = None
intake: ThermalZone | None = None
exhaust: ThermalZone | None = None
case: ThermalZone | None = None
def get_msg(self):
ret = {}
for f in fields(ThermalConfig):
v = getattr(self, f.name)
if v is not None:
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): class HardwareBase(ABC):
@staticmethod @staticmethod
@ -84,9 +127,8 @@ class HardwareBase(ABC):
def shutdown(self): def shutdown(self):
pass pass
@abstractmethod
def get_thermal_config(self): def get_thermal_config(self):
pass return ThermalConfig()
@abstractmethod @abstractmethod
def set_screen_brightness(self, percentage): def set_screen_brightness(self, percentage):

@ -51,41 +51,6 @@ OFFROAD_DANGER_TEMP = 75
prev_offroad_states: dict[str, tuple[bool, str | None]] = {} 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): 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: if (sm.frame % round(SERVICE_LIST['pandaStates'].frequency * DT_HW) != 0) and not ign_edge:
continue 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() msg.deviceState.deviceType = HARDWARE.get_device_type()
try: try:

@ -1,7 +1,7 @@
import random import random
from cereal import log from cereal import log
from openpilot.system.hardware.base import HardwareBase, ThermalConfig from openpilot.system.hardware.base import HardwareBase
NetworkType = log.DeviceState.NetworkType NetworkType = log.DeviceState.NetworkType
NetworkStrength = log.DeviceState.NetworkStrength NetworkStrength = log.DeviceState.NetworkStrength
@ -53,9 +53,6 @@ class Pc(HardwareBase):
def shutdown(self): def shutdown(self):
print("SHUTDOWN!") print("SHUTDOWN!")
def get_thermal_config(self):
return ThermalConfig(cpu=((None,), 1), gpu=((None,), 1), mem=(None, 1), pmic=((None,), 1), intake=(None, 1), exhaust=(None, 1))
def set_screen_brightness(self, percentage): def set_screen_brightness(self, percentage):
pass pass

@ -10,7 +10,7 @@ from pathlib import Path
from cereal import log from cereal import log
from openpilot.common.gpio import gpio_set, gpio_init, get_irqs_for_action 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 import iwlist
from openpilot.system.hardware.tici.pins import GPIO from openpilot.system.hardware.tici.pins import GPIO
from openpilot.system.hardware.tici.amplifier import Amplifier from openpilot.system.hardware.tici.amplifier import Amplifier
@ -323,17 +323,19 @@ class Tici(HardwareBase):
os.system("sudo poweroff") os.system("sudo poweroff")
def get_thermal_config(self): def get_thermal_config(self):
intake, exhaust = (None, 1), (None, 1) intake, exhaust, case = None, None, None
if self.get_device_type() == "mici": if self.get_device_type() == "mici":
intake = ("intake", 1000) case = ThermalZone("case")
exhaust = ("exhaust", 1000) intake = ThermalZone("intake")
return ThermalConfig(cpu=([f"cpu{i}-silver-usr" for i in range(4)] + exhaust = ThermalZone("exhaust")
[f"cpu{i}-gold-usr" for i in range(4)], 1000), return ThermalConfig(cpu=[ThermalZone(f"cpu{i}-silver-usr") for i in range(4)] +
gpu=(("gpu0-usr", "gpu1-usr"), 1000), [ThermalZone(f"cpu{i}-gold-usr") for i in range(4)],
mem=("ddr-usr", 1000), gpu=[ThermalZone("gpu0-usr"), ThermalZone("gpu1-usr")],
pmic=(("pm8998_tz", "pm8005_tz"), 1000), memory=ThermalZone("ddr-usr"),
pmic=[ThermalZone("pm8998_tz"), ThermalZone("pm8005_tz")],
intake=intake, intake=intake,
exhaust=exhaust) exhaust=exhaust,
case=case)
def set_screen_brightness(self, percentage): def set_screen_brightness(self, percentage):
try: try:

Loading…
Cancel
Save