|  |  |  | @ -1,23 +1,32 @@ | 
			
		
	
		
			
				
					|  |  |  |  | #!/usr/bin/env python3 | 
			
		
	
		
			
				
					|  |  |  |  | import os | 
			
		
	
		
			
				
					|  |  |  |  | import datetime | 
			
		
	
		
			
				
					|  |  |  |  | import psutil | 
			
		
	
		
			
				
					|  |  |  |  | import os | 
			
		
	
		
			
				
					|  |  |  |  | import time | 
			
		
	
		
			
				
					|  |  |  |  | from collections import namedtuple | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | import psutil | 
			
		
	
		
			
				
					|  |  |  |  | from smbus2 import SMBus | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | import cereal.messaging as messaging | 
			
		
	
		
			
				
					|  |  |  |  | from cereal import log | 
			
		
	
		
			
				
					|  |  |  |  | from common.android import ANDROID, get_network_type, get_network_strength | 
			
		
	
		
			
				
					|  |  |  |  | from common.params import Params, put_nonblocking | 
			
		
	
		
			
				
					|  |  |  |  | from common.realtime import sec_since_boot, DT_TRML | 
			
		
	
		
			
				
					|  |  |  |  | from common.numpy_fast import clip, interp | 
			
		
	
		
			
				
					|  |  |  |  | from common.android import get_network_strength, get_network_type | 
			
		
	
		
			
				
					|  |  |  |  | from common.filter_simple import FirstOrderFilter | 
			
		
	
		
			
				
					|  |  |  |  | from selfdrive.version import terms_version, training_version, get_git_branch | 
			
		
	
		
			
				
					|  |  |  |  | from selfdrive.swaglog import cloudlog | 
			
		
	
		
			
				
					|  |  |  |  | import cereal.messaging as messaging | 
			
		
	
		
			
				
					|  |  |  |  | from common.numpy_fast import clip, interp | 
			
		
	
		
			
				
					|  |  |  |  | from common.params import Params, put_nonblocking | 
			
		
	
		
			
				
					|  |  |  |  | from common.realtime import DT_TRML, sec_since_boot | 
			
		
	
		
			
				
					|  |  |  |  | from selfdrive.controls.lib.alertmanager import set_offroad_alert | 
			
		
	
		
			
				
					|  |  |  |  | from selfdrive.loggerd.config import get_available_percent | 
			
		
	
		
			
				
					|  |  |  |  | from selfdrive.pandad import get_expected_signature | 
			
		
	
		
			
				
					|  |  |  |  | from selfdrive.thermald.power_monitoring import PowerMonitoring, get_battery_capacity, get_battery_status, \ | 
			
		
	
		
			
				
					|  |  |  |  |                                                 get_battery_current, get_battery_voltage, get_usb_present | 
			
		
	
		
			
				
					|  |  |  |  | from selfdrive.swaglog import cloudlog | 
			
		
	
		
			
				
					|  |  |  |  | from selfdrive.thermald.power_monitoring import (PowerMonitoring, | 
			
		
	
		
			
				
					|  |  |  |  |                                                  get_battery_capacity, | 
			
		
	
		
			
				
					|  |  |  |  |                                                  get_battery_current, | 
			
		
	
		
			
				
					|  |  |  |  |                                                  get_battery_status, | 
			
		
	
		
			
				
					|  |  |  |  |                                                  get_battery_voltage, | 
			
		
	
		
			
				
					|  |  |  |  |                                                  get_usb_present) | 
			
		
	
		
			
				
					|  |  |  |  | from selfdrive.version import get_git_branch, terms_version, training_version | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | ThermalConfig = namedtuple('ThermalConfig', ['cpu', 'gpu', 'mem', 'bat', 'ambient']) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | FW_SIGNATURE = get_expected_signature() | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -30,35 +39,41 @@ DAYS_NO_CONNECTIVITY_MAX = 7  # do not allow to engage after a week without inte | 
			
		
	
		
			
				
					|  |  |  |  | DAYS_NO_CONNECTIVITY_PROMPT = 4  # send an offroad prompt after 4 days with no internet | 
			
		
	
		
			
				
					|  |  |  |  | DISCONNECT_TIMEOUT = 5.  # wait 5 seconds before going offroad after disconnect so you get an alert | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | EON = os.path.isfile('/EON') | 
			
		
	
		
			
				
					|  |  |  |  | TICI = os.path.isfile('/TICI') | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | LEON = False | 
			
		
	
		
			
				
					|  |  |  |  | last_eon_fan_val = None | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | def read_tz(x, clip=True): | 
			
		
	
		
			
				
					|  |  |  |  |   if not ANDROID: | 
			
		
	
		
			
				
					|  |  |  |  |     # we don't monitor thermal on PC | 
			
		
	
		
			
				
					|  |  |  |  | def get_thermal_config(): | 
			
		
	
		
			
				
					|  |  |  |  |   # (tz, scale) | 
			
		
	
		
			
				
					|  |  |  |  |   if EON: | 
			
		
	
		
			
				
					|  |  |  |  |     return ThermalConfig(cpu=((5, 7, 10, 12), 10), gpu=((16,), 10), mem=(2, 10), bat=(29, 1000), ambient=(25, 1)) | 
			
		
	
		
			
				
					|  |  |  |  |   elif TICI: | 
			
		
	
		
			
				
					|  |  |  |  |     return ThermalConfig(cpu=((1, 2, 3, 4, 5, 6, 7, 8), 1000), gpu=((48,49), 1000), mem=(15, 1000), bat=(None, 1), ambient=(70, 1000)) | 
			
		
	
		
			
				
					|  |  |  |  |   else: | 
			
		
	
		
			
				
					|  |  |  |  |     return ThermalConfig(cpu=((None,), 1), gpu=((None,), 1), mem=(None, 1), bat=(None, 1), ambient=(None, 1)) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | def read_tz(x): | 
			
		
	
		
			
				
					|  |  |  |  |   if x is None: | 
			
		
	
		
			
				
					|  |  |  |  |     return 0 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   try: | 
			
		
	
		
			
				
					|  |  |  |  |     with open("/sys/devices/virtual/thermal/thermal_zone%d/temp" % x) as f: | 
			
		
	
		
			
				
					|  |  |  |  |       ret = int(f.read()) | 
			
		
	
		
			
				
					|  |  |  |  |       if clip: | 
			
		
	
		
			
				
					|  |  |  |  |         ret = max(0, ret) | 
			
		
	
		
			
				
					|  |  |  |  |       return int(f.read()) | 
			
		
	
		
			
				
					|  |  |  |  |   except FileNotFoundError: | 
			
		
	
		
			
				
					|  |  |  |  |     return 0 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   return ret | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | def read_thermal(): | 
			
		
	
		
			
				
					|  |  |  |  | def read_thermal(thermal_config): | 
			
		
	
		
			
				
					|  |  |  |  |   dat = messaging.new_message('thermal') | 
			
		
	
		
			
				
					|  |  |  |  |   dat.thermal.cpu0 = read_tz(5) | 
			
		
	
		
			
				
					|  |  |  |  |   dat.thermal.cpu1 = read_tz(7) | 
			
		
	
		
			
				
					|  |  |  |  |   dat.thermal.cpu2 = read_tz(10) | 
			
		
	
		
			
				
					|  |  |  |  |   dat.thermal.cpu3 = read_tz(12) | 
			
		
	
		
			
				
					|  |  |  |  |   dat.thermal.mem = read_tz(2) | 
			
		
	
		
			
				
					|  |  |  |  |   dat.thermal.gpu = read_tz(16) | 
			
		
	
		
			
				
					|  |  |  |  |   dat.thermal.bat = read_tz(29) | 
			
		
	
		
			
				
					|  |  |  |  |   dat.thermal.pa0 = read_tz(25) | 
			
		
	
		
			
				
					|  |  |  |  |   dat.thermal.cpu = [read_tz(z) / thermal_config.cpu[1] for z in thermal_config.cpu[0]] | 
			
		
	
		
			
				
					|  |  |  |  |   dat.thermal.gpu = [read_tz(z) / thermal_config.gpu[1] for z in thermal_config.gpu[0]] | 
			
		
	
		
			
				
					|  |  |  |  |   dat.thermal.mem = read_tz(thermal_config.mem[0]) / thermal_config.mem[1] | 
			
		
	
		
			
				
					|  |  |  |  |   dat.thermal.ambient = read_tz(thermal_config.ambient[0]) / thermal_config.ambient[1] | 
			
		
	
		
			
				
					|  |  |  |  |   dat.thermal.bat = read_tz(thermal_config.bat[0]) / thermal_config.bat[1] | 
			
		
	
		
			
				
					|  |  |  |  |   return dat | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -183,11 +198,13 @@ def thermald_thread(): | 
			
		
	
		
			
				
					|  |  |  |  |   pm = PowerMonitoring() | 
			
		
	
		
			
				
					|  |  |  |  |   no_panda_cnt = 0 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   thermal_config = get_thermal_config() | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   while 1: | 
			
		
	
		
			
				
					|  |  |  |  |     health = messaging.recv_sock(health_sock, wait=True) | 
			
		
	
		
			
				
					|  |  |  |  |     location = messaging.recv_sock(location_sock) | 
			
		
	
		
			
				
					|  |  |  |  |     location = location.gpsLocation if location else None | 
			
		
	
		
			
				
					|  |  |  |  |     msg = read_thermal() | 
			
		
	
		
			
				
					|  |  |  |  |     msg = read_thermal(thermal_config) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     if health is not None: | 
			
		
	
		
			
				
					|  |  |  |  |       usb_power = health.health.usbPowerMode != log.HealthData.UsbPowerMode.client | 
			
		
	
	
		
			
				
					|  |  |  | @ -208,7 +225,7 @@ def thermald_thread(): | 
			
		
	
		
			
				
					|  |  |  |  |         is_uno = health.health.hwType == log.HealthData.HwType.uno | 
			
		
	
		
			
				
					|  |  |  |  |         has_relay = health.health.hwType in [log.HealthData.HwType.blackPanda, log.HealthData.HwType.uno, log.HealthData.HwType.dos] | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         if is_uno or not ANDROID: | 
			
		
	
		
			
				
					|  |  |  |  |         if (not EON) or is_uno: | 
			
		
	
		
			
				
					|  |  |  |  |           cloudlog.info("Setting up UNO fan handler") | 
			
		
	
		
			
				
					|  |  |  |  |           handle_fan = handle_fan_uno | 
			
		
	
		
			
				
					|  |  |  |  |         else: | 
			
		
	
	
		
			
				
					|  |  |  | @ -243,7 +260,7 @@ def thermald_thread(): | 
			
		
	
		
			
				
					|  |  |  |  |     msg.thermal.usbOnline = get_usb_present() | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     # Fake battery levels on uno for frame | 
			
		
	
		
			
				
					|  |  |  |  |     if is_uno: | 
			
		
	
		
			
				
					|  |  |  |  |     if (not EON) or is_uno: | 
			
		
	
		
			
				
					|  |  |  |  |       msg.thermal.batteryPercent = 100 | 
			
		
	
		
			
				
					|  |  |  |  |       msg.thermal.batteryStatus = "Charging" | 
			
		
	
		
			
				
					|  |  |  |  |       msg.thermal.bat = 0 | 
			
		
	
	
		
			
				
					|  |  |  | @ -251,14 +268,9 @@ def thermald_thread(): | 
			
		
	
		
			
				
					|  |  |  |  |     current_filter.update(msg.thermal.batteryCurrent / 1e6) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     # TODO: add car battery voltage check | 
			
		
	
		
			
				
					|  |  |  |  |     max_cpu_temp = cpu_temp_filter.update( | 
			
		
	
		
			
				
					|  |  |  |  |       max(msg.thermal.cpu0, | 
			
		
	
		
			
				
					|  |  |  |  |           msg.thermal.cpu1, | 
			
		
	
		
			
				
					|  |  |  |  |           msg.thermal.cpu2, | 
			
		
	
		
			
				
					|  |  |  |  |           msg.thermal.cpu3) / 10.0) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     max_comp_temp = max(max_cpu_temp, msg.thermal.mem / 10., msg.thermal.gpu / 10.) | 
			
		
	
		
			
				
					|  |  |  |  |     bat_temp = msg.thermal.bat / 1000. | 
			
		
	
		
			
				
					|  |  |  |  |     max_cpu_temp = cpu_temp_filter.update(max(msg.thermal.cpu)) | 
			
		
	
		
			
				
					|  |  |  |  |     max_comp_temp = max(max_cpu_temp, msg.thermal.mem, max(msg.thermal.gpu)) | 
			
		
	
		
			
				
					|  |  |  |  |     bat_temp = msg.thermal.bat | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     if handle_fan is not None: | 
			
		
	
		
			
				
					|  |  |  |  |       fan_speed = handle_fan(max_cpu_temp, bat_temp, fan_speed, ignition) | 
			
		
	
	
		
			
				
					|  |  |  | 
 |