import os from abc import abstractmethod, ABC from dataclasses import dataclass, fields from cereal import log 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): @staticmethod def get_cmdline() -> dict[str, str]: with open('/proc/cmdline') as f: cmdline = f.read() return {kv[0]: kv[1] for kv in [s.split('=') for s in cmdline.split(' ')] if len(kv) == 2} @staticmethod def read_param_file(path, parser, default=0): try: with open(path) as f: return parser(f.read()) except Exception: return default def booted(self) -> bool: return True @abstractmethod def reboot(self, reason=None): pass @abstractmethod def uninstall(self): pass @abstractmethod def get_os_version(self): pass @abstractmethod def get_device_type(self): pass @abstractmethod def get_imei(self, slot) -> str: pass @abstractmethod def get_serial(self): pass @abstractmethod def get_network_info(self): pass @abstractmethod def get_network_type(self): pass @abstractmethod def get_sim_info(self): pass @abstractmethod def get_network_strength(self, network_type): pass def get_network_metered(self, network_type) -> bool: return network_type not in (NetworkType.none, NetworkType.wifi, NetworkType.ethernet) @staticmethod def set_bandwidth_limit(upload_speed_kbps: int, download_speed_kbps: int) -> None: pass @abstractmethod def get_current_power_draw(self): pass @abstractmethod def get_som_power_draw(self): pass @abstractmethod def shutdown(self): pass def get_thermal_config(self): return ThermalConfig() @abstractmethod def set_screen_brightness(self, percentage): pass @abstractmethod def get_screen_brightness(self): pass @abstractmethod def set_power_save(self, powersave_enabled): pass @abstractmethod def get_gpu_usage_percent(self): pass def get_modem_version(self): return None @abstractmethod def get_modem_temperatures(self): pass @abstractmethod def get_nvme_temperatures(self): pass @abstractmethod def initialize_hardware(self): pass def configure_modem(self): pass @abstractmethod def get_networks(self): pass def has_internal_panda(self) -> bool: return False def reset_internal_panda(self): pass def recover_internal_panda(self): pass def get_modem_data_usage(self): return -1, -1