From c8eed435383147fc18b0627d87a5b9c56ae06ba3 Mon Sep 17 00:00:00 2001 From: Adeeb Shihadeh Date: Sun, 21 Dec 2025 17:02:39 -0800 Subject: [PATCH] misc system/hardware/ cleanup (#36949) * misc system/hardware/ cleanup * lil more * pc is kinda base * lil more * lil more * lil more * int * lil more? --- system/hardware/.gitignore | 1 - system/hardware/base.py | 66 ++++++----------- system/hardware/fan_controller.py | 29 ++------ system/hardware/hardwared.py | 13 +--- system/hardware/pc/hardware.h | 1 - system/hardware/pc/hardware.py | 70 +----------------- system/hardware/tests/test_fan_controller.py | 6 +- system/hardware/tici/amplifier.py | 78 +++++++------------- system/hardware/tici/hardware.py | 6 +- system/hardware/tici/tests/test_amplifier.py | 5 +- 10 files changed, 71 insertions(+), 204 deletions(-) delete mode 100644 system/hardware/.gitignore diff --git a/system/hardware/.gitignore b/system/hardware/.gitignore deleted file mode 100644 index 980f09abf..000000000 --- a/system/hardware/.gitignore +++ /dev/null @@ -1 +0,0 @@ -eon/rat diff --git a/system/hardware/base.py b/system/hardware/base.py index 17d0ec161..05e8eb015 100644 --- a/system/hardware/base.py +++ b/system/hardware/base.py @@ -5,6 +5,7 @@ from dataclasses import dataclass, fields from cereal import log NetworkType = log.DeviceState.NetworkType +NetworkStrength = log.DeviceState.NetworkStrength class LPAError(RuntimeError): pass @@ -114,68 +115,57 @@ class HardwareBase(ABC): def booted(self) -> bool: return True - @abstractmethod def reboot(self, reason=None): - pass + print("REBOOT!") - @abstractmethod def uninstall(self): - pass + print("uninstall") - @abstractmethod def get_os_version(self): - pass + return None @abstractmethod def get_device_type(self): pass - @abstractmethod def get_imei(self, slot) -> str: - pass + return "" - @abstractmethod def get_serial(self): - pass + return "" - @abstractmethod def get_network_info(self): - pass + return None - @abstractmethod def get_network_type(self): - pass + return NetworkType.none - @abstractmethod def get_sim_info(self): - pass + return { + 'sim_id': '', + 'mcc_mnc': None, + 'network_type': ["Unknown"], + 'sim_state': ["ABSENT"], + 'data_connected': False + } - @abstractmethod def get_sim_lpa(self) -> LPABase: - pass + raise NotImplementedError("SIM LPA not available") - @abstractmethod def get_network_strength(self, network_type): - pass + return NetworkStrength.unknown 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 + return 0 - @abstractmethod def get_som_power_draw(self): - pass + return 0 - @abstractmethod def shutdown(self): - pass + print("SHUTDOWN!") def get_thermal_config(self): return ThermalConfig() @@ -183,31 +173,24 @@ class HardwareBase(ABC): def set_display_power(self, on: bool): pass - @abstractmethod def set_screen_brightness(self, percentage): pass - @abstractmethod def get_screen_brightness(self): - pass + return 0 - @abstractmethod def set_power_save(self, powersave_enabled): pass - @abstractmethod def get_gpu_usage_percent(self): - pass + return 0 def get_modem_version(self): return None - @abstractmethod def get_modem_temperatures(self): - pass + return [] - - @abstractmethod def initialize_hardware(self): pass @@ -217,9 +200,8 @@ class HardwareBase(ABC): def reboot_modem(self): pass - @abstractmethod def get_networks(self): - pass + return None def has_internal_panda(self) -> bool: return False diff --git a/system/hardware/fan_controller.py b/system/hardware/fan_controller.py index 365688429..b2140d33d 100755 --- a/system/hardware/fan_controller.py +++ b/system/hardware/fan_controller.py @@ -1,24 +1,13 @@ #!/usr/bin/env python3 import numpy as np -from abc import ABC, abstractmethod -from openpilot.common.realtime import DT_HW -from openpilot.common.swaglog import cloudlog from openpilot.common.pid import PIDController -class BaseFanController(ABC): - @abstractmethod - def update(self, cur_temp: float, ignition: bool) -> int: - pass - - -class TiciFanController(BaseFanController): - def __init__(self) -> None: - super().__init__() - cloudlog.info("Setting up TICI fan handler") +class FanController: + def __init__(self, rate: int) -> None: self.last_ignition = False - self.controller = PIDController(k_p=0, k_i=4e-3, rate=(1 / DT_HW)) + self.controller = PIDController(k_p=0, k_i=4e-3, rate=rate) def update(self, cur_temp: float, ignition: bool) -> int: self.controller.pos_limit = 100 if ignition else 30 @@ -26,13 +15,9 @@ class TiciFanController(BaseFanController): if ignition != self.last_ignition: self.controller.reset() - - error = cur_temp - 75 - fan_pwr_out = int(self.controller.update( - error=error, - feedforward=np.interp(cur_temp, [60.0, 100.0], [0, 100]) - )) - self.last_ignition = ignition - return fan_pwr_out + return int(self.controller.update( + error=(cur_temp - 75), # temperature setpoint in C + feedforward=np.interp(cur_temp, [60.0, 100.0], [0, 100]) + )) diff --git a/system/hardware/hardwared.py b/system/hardware/hardwared.py index 8ddc4da2f..aad30f77b 100755 --- a/system/hardware/hardwared.py +++ b/system/hardware/hardwared.py @@ -22,7 +22,7 @@ from openpilot.system.loggerd.config import get_available_percent from openpilot.system.statsd import statlog from openpilot.common.swaglog import cloudlog from openpilot.system.hardware.power_monitoring import PowerMonitoring -from openpilot.system.hardware.fan_controller import TiciFanController +from openpilot.system.hardware.fan_controller import FanController from openpilot.system.version import terms_version, training_version from openpilot.system.athena.registration import UNREGISTERED_DONGLE_ID @@ -210,14 +210,13 @@ def hardware_thread(end_event, hw_queue) -> None: HARDWARE.initialize_hardware() thermal_config = HARDWARE.get_thermal_config() - fan_controller = None + fan_controller = FanController(int(1./DT_HW)) while not end_event.is_set(): sm.update(PANDA_STATES_TIMEOUT) pandaStates = sm['pandaStates'] peripheralState = sm['peripheralState'] - peripheral_panda_present = peripheralState.pandaType != log.PandaState.PandaType.unknown # handle requests to cycle system started state if params.get_bool("OnroadCycleRequested"): @@ -234,11 +233,6 @@ def hardware_thread(end_event, hw_queue) -> None: in_car = pandaState.harnessStatus != log.PandaState.HarnessStatus.notConnected - # Setup fan handler on first connect to panda - if fan_controller is None and peripheral_panda_present: - if TICI: - fan_controller = TiciFanController() - elif (time.monotonic() - sm.recv_time['pandaStates']) > DISCONNECT_TIMEOUT: if onroad_conditions["ignition"]: onroad_conditions["ignition"] = False @@ -289,8 +283,7 @@ def hardware_thread(end_event, hw_queue) -> None: all_comp_temp = all_temp_filter.update(max(temp_sources)) msg.deviceState.maxTempC = all_comp_temp - if fan_controller is not None: - msg.deviceState.fanSpeedPercentDesired = fan_controller.update(all_comp_temp, onroad_conditions["ignition"]) + msg.deviceState.fanSpeedPercentDesired = fan_controller.update(all_comp_temp, onroad_conditions["ignition"]) is_offroad_for_5_min = (started_ts is None) and ((not started_seen) or (off_ts is None) or (time.monotonic() - off_ts > 60 * 5)) if is_offroad_for_5_min and offroad_comp_temp > OFFROAD_DANGER_TEMP: diff --git a/system/hardware/pc/hardware.h b/system/hardware/pc/hardware.h index 978dd771c..71f58b188 100644 --- a/system/hardware/pc/hardware.h +++ b/system/hardware/pc/hardware.h @@ -6,7 +6,6 @@ class HardwarePC : public HardwareNone { public: - static std::string get_os_version() { return "openpilot for PC"; } static std::string get_name() { return "pc"; } static cereal::InitData::DeviceType get_device_type() { return cereal::InitData::DeviceType::PC; } static bool PC() { return true; } diff --git a/system/hardware/pc/hardware.py b/system/hardware/pc/hardware.py index 6c1189639..f3d527429 100644 --- a/system/hardware/pc/hardware.py +++ b/system/hardware/pc/hardware.py @@ -1,78 +1,12 @@ -import random - from cereal import log -from openpilot.system.hardware.base import HardwareBase, LPABase +from openpilot.system.hardware.base import HardwareBase NetworkType = log.DeviceState.NetworkType -NetworkStrength = log.DeviceState.NetworkStrength + class Pc(HardwareBase): - def get_os_version(self): - return None - def get_device_type(self): return "pc" - def reboot(self, reason=None): - print("REBOOT!") - - def uninstall(self): - print("uninstall") - - def get_imei(self, slot): - return f"{random.randint(0, 1 << 32):015d}" - - def get_serial(self): - return "cccccccc" - - def get_network_info(self): - return None - def get_network_type(self): return NetworkType.wifi - - def get_sim_info(self): - return { - 'sim_id': '', - 'mcc_mnc': None, - 'network_type': ["Unknown"], - 'sim_state': ["ABSENT"], - 'data_connected': False - } - - def get_sim_lpa(self) -> LPABase: - raise NotImplementedError("SIM LPA not implemented for PC") - - def get_network_strength(self, network_type): - return NetworkStrength.unknown - - def get_current_power_draw(self): - return 0 - - def get_som_power_draw(self): - return 0 - - def shutdown(self): - print("SHUTDOWN!") - - def set_screen_brightness(self, percentage): - pass - - def get_screen_brightness(self): - return 0 - - def set_power_save(self, powersave_enabled): - pass - - def get_gpu_usage_percent(self): - return 0 - - def get_modem_temperatures(self): - return [] - - - def initialize_hardware(self): - pass - - def get_networks(self): - return None diff --git a/system/hardware/tests/test_fan_controller.py b/system/hardware/tests/test_fan_controller.py index 002c1edfd..ee39a24f8 100644 --- a/system/hardware/tests/test_fan_controller.py +++ b/system/hardware/tests/test_fan_controller.py @@ -1,12 +1,12 @@ import pytest -from openpilot.system.hardware.fan_controller import TiciFanController +from openpilot.system.hardware.fan_controller import FanController -ALL_CONTROLLERS = [TiciFanController] +ALL_CONTROLLERS = [FanController] def patched_controller(mocker, controller_class): mocker.patch("os.system", new=mocker.Mock()) - return controller_class() + return controller_class(2) class TestFanController: def wind_up(self, controller, ignition=True): diff --git a/system/hardware/tici/amplifier.py b/system/hardware/tici/amplifier.py index bfdcc6dda..d714837bb 100755 --- a/system/hardware/tici/amplifier.py +++ b/system/hardware/tici/amplifier.py @@ -6,23 +6,8 @@ from collections import namedtuple # https://datasheets.maximintegrated.com/en/ds/MAX98089.pdf AmpConfig = namedtuple('AmpConfig', ['name', 'value', 'register', 'offset', 'mask']) -EQParams = namedtuple('EQParams', ['K', 'k1', 'k2', 'c1', 'c2']) -def configs_from_eq_params(base, eq_params): - return [ - AmpConfig("K (high)", (eq_params.K >> 8), base, 0, 0xFF), - AmpConfig("K (low)", (eq_params.K & 0xFF), base + 1, 0, 0xFF), - AmpConfig("k1 (high)", (eq_params.k1 >> 8), base + 2, 0, 0xFF), - AmpConfig("k1 (low)", (eq_params.k1 & 0xFF), base + 3, 0, 0xFF), - AmpConfig("k2 (high)", (eq_params.k2 >> 8), base + 4, 0, 0xFF), - AmpConfig("k2 (low)", (eq_params.k2 & 0xFF), base + 5, 0, 0xFF), - AmpConfig("c1 (high)", (eq_params.c1 >> 8), base + 6, 0, 0xFF), - AmpConfig("c1 (low)", (eq_params.c1 & 0xFF), base + 7, 0, 0xFF), - AmpConfig("c2 (high)", (eq_params.c2 >> 8), base + 8, 0, 0xFF), - AmpConfig("c2 (low)", (eq_params.c2 & 0xFF), base + 9, 0, 0xFF), - ] - -BASE_CONFIG = [ +CONFIG = [ AmpConfig("MCLK prescaler", 0b01, 0x10, 4, 0b00110000), AmpConfig("PM: enable speakers", 0b11, 0x4D, 4, 0b00110000), AmpConfig("PM: enable DACs", 0b11, 0x4D, 0, 0b00000011), @@ -58,35 +43,31 @@ BASE_CONFIG = [ AmpConfig("Enhanced volume smoothing disabled", 0b0, 0x49, 7, 0b10000000), AmpConfig("Volume adjustment smoothing disabled", 0b0, 0x49, 6, 0b01000000), AmpConfig("Zero-crossing detection disabled", 0b0, 0x49, 5, 0b00100000), + + AmpConfig("Left speaker output from left DAC", 0b1, 0x2B, 0, 0b11111111), + AmpConfig("Right speaker output from right DAC", 0b1, 0x2C, 0, 0b11111111), + AmpConfig("Left Speaker Mixer Gain", 0b00, 0x2D, 0, 0b00000011), + AmpConfig("Right Speaker Mixer Gain", 0b00, 0x2D, 2, 0b00001100), + AmpConfig("Left speaker output volume", 0x17, 0x3D, 0, 0b00011111), + AmpConfig("Right speaker output volume", 0x17, 0x3E, 0, 0b00011111), + + AmpConfig("DAI2 EQ enable", 0b0, 0x49, 1, 0b00000010), + AmpConfig("DAI2: DC blocking", 0b0, 0x20, 0, 0b00000001), + AmpConfig("ALC enable", 0b0, 0x43, 7, 0b10000000), + AmpConfig("DAI2 EQ attenuation", 0x2, 0x32, 0, 0b00001111), + AmpConfig("Excursion limiter upper corner freq", 0b001, 0x41, 4, 0b01110000), + AmpConfig("Excursion limiter threshold", 0b100, 0x42, 0, 0b00001111), + AmpConfig("Distortion limit (THDCLP)", 0x0, 0x46, 4, 0b11110000), + AmpConfig("Distortion limiter release time constant", 0b1, 0x46, 0, 0b00000001), + AmpConfig("Left DAC input mixer: DAI1 left", 0b0, 0x22, 7, 0b10000000), + AmpConfig("Left DAC input mixer: DAI1 right", 0b0, 0x22, 6, 0b01000000), + AmpConfig("Left DAC input mixer: DAI2 left", 0b1, 0x22, 5, 0b00100000), + AmpConfig("Left DAC input mixer: DAI2 right", 0b0, 0x22, 4, 0b00010000), + AmpConfig("Right DAC input mixer: DAI2 left", 0b0, 0x22, 1, 0b00000010), + AmpConfig("Right DAC input mixer: DAI2 right", 0b1, 0x22, 0, 0b00000001), + AmpConfig("Volume adjustment smoothing disabled", 0b1, 0x49, 6, 0b01000000), ] -CONFIGS = { - "tizi": [ - AmpConfig("Left speaker output from left DAC", 0b1, 0x2B, 0, 0b11111111), - AmpConfig("Right speaker output from right DAC", 0b1, 0x2C, 0, 0b11111111), - AmpConfig("Left Speaker Mixer Gain", 0b00, 0x2D, 0, 0b00000011), - AmpConfig("Right Speaker Mixer Gain", 0b00, 0x2D, 2, 0b00001100), - AmpConfig("Left speaker output volume", 0x17, 0x3D, 0, 0b00011111), - AmpConfig("Right speaker output volume", 0x17, 0x3E, 0, 0b00011111), - - AmpConfig("DAI2 EQ enable", 0b0, 0x49, 1, 0b00000010), - AmpConfig("DAI2: DC blocking", 0b0, 0x20, 0, 0b00000001), - AmpConfig("ALC enable", 0b0, 0x43, 7, 0b10000000), - AmpConfig("DAI2 EQ attenuation", 0x2, 0x32, 0, 0b00001111), - AmpConfig("Excursion limiter upper corner freq", 0b001, 0x41, 4, 0b01110000), - AmpConfig("Excursion limiter threshold", 0b100, 0x42, 0, 0b00001111), - AmpConfig("Distortion limit (THDCLP)", 0x0, 0x46, 4, 0b11110000), - AmpConfig("Distortion limiter release time constant", 0b1, 0x46, 0, 0b00000001), - AmpConfig("Left DAC input mixer: DAI1 left", 0b0, 0x22, 7, 0b10000000), - AmpConfig("Left DAC input mixer: DAI1 right", 0b0, 0x22, 6, 0b01000000), - AmpConfig("Left DAC input mixer: DAI2 left", 0b1, 0x22, 5, 0b00100000), - AmpConfig("Left DAC input mixer: DAI2 right", 0b0, 0x22, 4, 0b00010000), - AmpConfig("Right DAC input mixer: DAI2 left", 0b0, 0x22, 1, 0b00000010), - AmpConfig("Right DAC input mixer: DAI2 right", 0b1, 0x22, 0, 0b00000001), - AmpConfig("Volume adjustment smoothing disabled", 0b1, 0x49, 6, 0b01000000), - ], -} - class Amplifier: AMP_I2C_BUS = 0 AMP_ADDRESS = 0x10 @@ -127,20 +108,15 @@ class Amplifier: def set_global_shutdown(self, amp_disabled: bool) -> bool: return self.set_configs([self._get_shutdown_config(amp_disabled), ]) - def initialize_configuration(self, model: str) -> bool: + def initialize_configuration(self) -> bool: cfgs = [ self._get_shutdown_config(True), - *BASE_CONFIG, - *CONFIGS[model], + *CONFIG, self._get_shutdown_config(False), ] return self.set_configs(cfgs) if __name__ == "__main__": - with open("/sys/firmware/devicetree/base/model") as f: - model = f.read().strip('\x00') - model = model.split('comma ')[-1] - amp = Amplifier() - amp.initialize_configuration(model) + amp.initialize_configuration() diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index 9791f15f3..3cdb33608 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -125,7 +125,7 @@ class Tici(HardwareBase): return int(f.read()) def set_ir_power(self, percent: int): - if self.get_device_type() in ("tici", "tizi"): + if self.get_device_type() == "tizi": return value = int((percent / 100) * 300) @@ -369,7 +369,7 @@ class Tici(HardwareBase): if self.amplifier is not None: self.amplifier.set_global_shutdown(amp_disabled=powersave_enabled) if not powersave_enabled: - self.amplifier.initialize_configuration(self.get_device_type()) + self.amplifier.initialize_configuration() # *** CPU config *** @@ -404,7 +404,7 @@ class Tici(HardwareBase): def initialize_hardware(self): if self.amplifier is not None: - self.amplifier.initialize_configuration(self.get_device_type()) + self.amplifier.initialize_configuration() # Allow hardwared to write engagement status to kmsg os.system("sudo chmod a+w /dev/kmsg") diff --git a/system/hardware/tici/tests/test_amplifier.py b/system/hardware/tici/tests/test_amplifier.py index 3f75436db..9ce00c3ff 100644 --- a/system/hardware/tici/tests/test_amplifier.py +++ b/system/hardware/tici/tests/test_amplifier.py @@ -5,7 +5,6 @@ import subprocess from panda import Panda from openpilot.system.hardware import TICI, HARDWARE -from openpilot.system.hardware.tici.hardware import Tici from openpilot.system.hardware.tici.amplifier import Amplifier @@ -39,7 +38,7 @@ class TestAmplifier: def test_init(self): amp = Amplifier(debug=True) - r = amp.initialize_configuration(Tici().get_device_type()) + r = amp.initialize_configuration() assert r assert self._check_for_i2c_errors(False) @@ -61,7 +60,7 @@ class TestAmplifier: time.sleep(random.randint(0, 5)) amp = Amplifier(debug=True) - r = amp.initialize_configuration(Tici().get_device_type()) + r = amp.initialize_configuration() assert r if self._check_for_i2c_errors(True):