From 16fe1bb2ada1e48e439463a52435f9eae5c3b9aa Mon Sep 17 00:00:00 2001 From: Willem Melching Date: Wed, 26 Aug 2020 14:57:17 +0200 Subject: [PATCH] Hardware abstraction class (#2080) * hardware abstraction class * De Morgan * Rename pc hardware class * Fix sound card in controlsd * Pc get sim info * fix hardware in test * two more * No more random imei on android * no randomness on android * Need to return something that looks like imei for registration to work * Return proper network strength * Unused import * Bug fixes + gpsd is only android old-commit-hash: c7152d54192605c833912b69cf85514ac2e1b1fc --- common/android.py | 472 +++++++++--------- common/basedir.py | 10 +- common/hardware.py | 50 ++ common/hardware_base.py | 34 ++ common/realtime.py | 2 +- release/files_common | 1 + selfdrive/athena/athenad.py | 20 +- .../boardd/tests/test_boardd_loopback.py | 2 +- selfdrive/controls/controlsd.py | 4 +- selfdrive/crash.py | 4 +- selfdrive/loggerd/uploader.py | 31 +- selfdrive/manager.py | 15 +- selfdrive/registration.py | 7 +- selfdrive/test/helpers.py | 9 +- .../test/process_replay/camera_replay.py | 3 +- selfdrive/test/test_sounds.py | 4 +- selfdrive/thermald/thermald.py | 7 +- tools/lib/auth_config.py | 14 +- 18 files changed, 390 insertions(+), 299 deletions(-) create mode 100644 common/hardware_base.py diff --git a/common/android.py b/common/android.py index 43bb0f3c1e..8fd69acd07 100644 --- a/common/android.py +++ b/common/android.py @@ -1,78 +1,32 @@ -import os import binascii import itertools +import os import re import struct import subprocess -import random + from cereal import log +from common.hardware_base import HardwareBase NetworkType = log.ThermalData.NetworkType NetworkStrength = log.ThermalData.NetworkStrength -ANDROID = os.path.isfile('/EON') - -def get_sound_card_online(): - return (os.path.isfile('/proc/asound/card0/state') and - open('/proc/asound/card0/state').read().strip() == 'ONLINE') - -def getprop(key): - if not ANDROID: - return "" - return subprocess.check_output(["getprop", key], encoding='utf8').strip() - -def get_imei(slot): - slot = str(slot) - if slot not in ("0", "1"): - raise ValueError("SIM slot must be 0 or 1") - - ret = parse_service_call_string(service_call(["iphonesubinfo", "3" , "i32", str(slot)])) - if not ret: - # allow non android to be identified differently - ret = "%015d" % random.randint(0, 1 << 32) - return ret - -def get_serial(): - ret = getprop("ro.serialno") - if ret == "": - ret = "cccccccc" - return ret - -def get_subscriber_info(): - ret = parse_service_call_string(service_call(["iphonesubinfo", "7"])) - if ret is None or len(ret) < 8: - return "" - return ret - -def reboot(reason=None): - if reason is None: - reason_args = ["null"] - else: - reason_args = ["s16", reason] - - subprocess.check_output([ - "service", "call", "power", "16", # IPowerManager.reboot - "i32", "0", # no confirmation, - *reason_args, - "i32", "1" # wait - ]) def service_call(call): - if not ANDROID: - return None - ret = subprocess.check_output(["service", "call", *call], encoding='utf8').strip() if 'Parcel' not in ret: return None return parse_service_call_bytes(ret) + def parse_service_call_unpack(r, fmt): try: return struct.unpack(fmt, r)[0] except Exception: return None + def parse_service_call_string(r): try: r = r[8:] # Cut off length field @@ -89,6 +43,7 @@ def parse_service_call_string(r): except Exception: return None + def parse_service_call_bytes(ret): try: r = b"" @@ -98,189 +53,248 @@ def parse_service_call_bytes(ret): except Exception: return None -def get_network_type(): - if not ANDROID: - return NetworkType.none - - wifi_check = parse_service_call_string(service_call(["connectivity", "2"])) - if wifi_check is None: - return NetworkType.none - elif 'WIFI' in wifi_check: - return NetworkType.wifi - else: - cell_check = parse_service_call_unpack(service_call(['phone', '59']), ">q") - # from TelephonyManager.java - cell_networks = { - 0: NetworkType.none, - 1: NetworkType.cell2G, - 2: NetworkType.cell2G, - 3: NetworkType.cell3G, - 4: NetworkType.cell2G, - 5: NetworkType.cell3G, - 6: NetworkType.cell3G, - 7: NetworkType.cell3G, - 8: NetworkType.cell3G, - 9: NetworkType.cell3G, - 10: NetworkType.cell3G, - 11: NetworkType.cell2G, - 12: NetworkType.cell3G, - 13: NetworkType.cell4G, - 14: NetworkType.cell4G, - 15: NetworkType.cell3G, - 16: NetworkType.cell2G, - 17: NetworkType.cell3G, - 18: NetworkType.cell4G, - 19: NetworkType.cell4G - } - return cell_networks.get(cell_check, NetworkType.none) - -def get_network_strength(network_type): - network_strength = NetworkStrength.unknown - - # from SignalStrength.java - def get_lte_level(rsrp, rssnr): - INT_MAX = 2147483647 - if rsrp == INT_MAX: - lvl_rsrp = NetworkStrength.unknown - elif rsrp >= -95: - lvl_rsrp = NetworkStrength.great - elif rsrp >= -105: - lvl_rsrp = NetworkStrength.good - elif rsrp >= -115: - lvl_rsrp = NetworkStrength.moderate + +def getprop(key): + return subprocess.check_output(["getprop", key], encoding='utf8').strip() + + +class Android(HardwareBase): + def get_sound_card_online(self): + return (os.path.isfile('/proc/asound/card0/state') and + open('/proc/asound/card0/state').read().strip() == 'ONLINE') + + def get_imei(self, slot): + slot = str(slot) + if slot not in ("0", "1"): + raise ValueError("SIM slot must be 0 or 1") + + return parse_service_call_string(service_call(["iphonesubinfo", "3", "i32", str(slot)])) + + def get_serial(self): + ret = getprop("ro.serialno") + if ret == "": + ret = "cccccccc" + return ret + + def get_subscriber_info(self): + ret = parse_service_call_string(service_call(["iphonesubinfo", "7"])) + if ret is None or len(ret) < 8: + return "" + return ret + + def reboot(self, reason=None): + # e.g. reason="recovery" to go into recover mode + if reason is None: + reason_args = ["null"] else: - lvl_rsrp = NetworkStrength.poor - if rssnr == INT_MAX: - lvl_rssnr = NetworkStrength.unknown - elif rssnr >= 45: - lvl_rssnr = NetworkStrength.great - elif rssnr >= 10: - lvl_rssnr = NetworkStrength.good - elif rssnr >= -30: - lvl_rssnr = NetworkStrength.moderate + reason_args = ["s16", reason] + + subprocess.check_output([ + "service", "call", "power", "16", # IPowerManager.reboot + "i32", "0", # no confirmation, + *reason_args, + "i32", "1" # wait + ]) + + def get_sim_info(self): + # Used for athena + # TODO: build using methods from this class + sim_state = getprop("gsm.sim.state").split(",") + network_type = getprop("gsm.network.type").split(',') + mcc_mnc = getprop("gsm.sim.operator.numeric") or None + + sim_id = parse_service_call_string(service_call(['iphonesubinfo', '11'])) + cell_data_state = parse_service_call_unpack(service_call(['phone', '46']), ">q") + cell_data_connected = (cell_data_state == 2) + + return { + 'sim_id': sim_id, + 'mcc_mnc': mcc_mnc, + 'network_type': network_type, + 'sim_state': sim_state, + 'data_connected': cell_data_connected + } + + def get_network_type(self): + wifi_check = parse_service_call_string(service_call(["connectivity", "2"])) + if wifi_check is None: + return NetworkType.none + elif 'WIFI' in wifi_check: + return NetworkType.wifi else: - lvl_rssnr = NetworkStrength.poor - return max(lvl_rsrp, lvl_rssnr) + cell_check = parse_service_call_unpack(service_call(['phone', '59']), ">q") + # from TelephonyManager.java + cell_networks = { + 0: NetworkType.none, + 1: NetworkType.cell2G, + 2: NetworkType.cell2G, + 3: NetworkType.cell3G, + 4: NetworkType.cell2G, + 5: NetworkType.cell3G, + 6: NetworkType.cell3G, + 7: NetworkType.cell3G, + 8: NetworkType.cell3G, + 9: NetworkType.cell3G, + 10: NetworkType.cell3G, + 11: NetworkType.cell2G, + 12: NetworkType.cell3G, + 13: NetworkType.cell4G, + 14: NetworkType.cell4G, + 15: NetworkType.cell3G, + 16: NetworkType.cell2G, + 17: NetworkType.cell3G, + 18: NetworkType.cell4G, + 19: NetworkType.cell4G + } + return cell_networks.get(cell_check, NetworkType.none) - def get_tdscdma_level(tdscmadbm): - lvl = NetworkStrength.unknown - if tdscmadbm > -25: - lvl = NetworkStrength.unknown - elif tdscmadbm >= -49: - lvl = NetworkStrength.great - elif tdscmadbm >= -73: - lvl = NetworkStrength.good - elif tdscmadbm >= -97: - lvl = NetworkStrength.moderate - elif tdscmadbm >= -110: - lvl = NetworkStrength.poor - return lvl - - def get_gsm_level(asu): - if asu <= 2 or asu == 99: + def get_network_strength(self, network_type): + network_strength = NetworkStrength.unknown + + # from SignalStrength.java + def get_lte_level(rsrp, rssnr): + INT_MAX = 2147483647 + if rsrp == INT_MAX: + lvl_rsrp = NetworkStrength.unknown + elif rsrp >= -95: + lvl_rsrp = NetworkStrength.great + elif rsrp >= -105: + lvl_rsrp = NetworkStrength.good + elif rsrp >= -115: + lvl_rsrp = NetworkStrength.moderate + else: + lvl_rsrp = NetworkStrength.poor + if rssnr == INT_MAX: + lvl_rssnr = NetworkStrength.unknown + elif rssnr >= 45: + lvl_rssnr = NetworkStrength.great + elif rssnr >= 10: + lvl_rssnr = NetworkStrength.good + elif rssnr >= -30: + lvl_rssnr = NetworkStrength.moderate + else: + lvl_rssnr = NetworkStrength.poor + return max(lvl_rsrp, lvl_rssnr) + + def get_tdscdma_level(tdscmadbm): lvl = NetworkStrength.unknown - elif asu >= 12: - lvl = NetworkStrength.great - elif asu >= 8: - lvl = NetworkStrength.good - elif asu >= 5: - lvl = NetworkStrength.moderate + if tdscmadbm > -25: + lvl = NetworkStrength.unknown + elif tdscmadbm >= -49: + lvl = NetworkStrength.great + elif tdscmadbm >= -73: + lvl = NetworkStrength.good + elif tdscmadbm >= -97: + lvl = NetworkStrength.moderate + elif tdscmadbm >= -110: + lvl = NetworkStrength.poor + return lvl + + def get_gsm_level(asu): + if asu <= 2 or asu == 99: + lvl = NetworkStrength.unknown + elif asu >= 12: + lvl = NetworkStrength.great + elif asu >= 8: + lvl = NetworkStrength.good + elif asu >= 5: + lvl = NetworkStrength.moderate + else: + lvl = NetworkStrength.poor + return lvl + + def get_evdo_level(evdodbm, evdosnr): + lvl_evdodbm = NetworkStrength.unknown + lvl_evdosnr = NetworkStrength.unknown + if evdodbm >= -65: + lvl_evdodbm = NetworkStrength.great + elif evdodbm >= -75: + lvl_evdodbm = NetworkStrength.good + elif evdodbm >= -90: + lvl_evdodbm = NetworkStrength.moderate + elif evdodbm >= -105: + lvl_evdodbm = NetworkStrength.poor + if evdosnr >= 7: + lvl_evdosnr = NetworkStrength.great + elif evdosnr >= 5: + lvl_evdosnr = NetworkStrength.good + elif evdosnr >= 3: + lvl_evdosnr = NetworkStrength.moderate + elif evdosnr >= 1: + lvl_evdosnr = NetworkStrength.poor + return max(lvl_evdodbm, lvl_evdosnr) + + def get_cdma_level(cdmadbm, cdmaecio): + lvl_cdmadbm = NetworkStrength.unknown + lvl_cdmaecio = NetworkStrength.unknown + if cdmadbm >= -75: + lvl_cdmadbm = NetworkStrength.great + elif cdmadbm >= -85: + lvl_cdmadbm = NetworkStrength.good + elif cdmadbm >= -95: + lvl_cdmadbm = NetworkStrength.moderate + elif cdmadbm >= -100: + lvl_cdmadbm = NetworkStrength.poor + if cdmaecio >= -90: + lvl_cdmaecio = NetworkStrength.great + elif cdmaecio >= -110: + lvl_cdmaecio = NetworkStrength.good + elif cdmaecio >= -130: + lvl_cdmaecio = NetworkStrength.moderate + elif cdmaecio >= -150: + lvl_cdmaecio = NetworkStrength.poor + return max(lvl_cdmadbm, lvl_cdmaecio) + + if network_type == NetworkType.none: + return network_strength + if network_type == NetworkType.wifi: + out = subprocess.check_output('dumpsys connectivity', shell=True).decode('utf-8') + network_strength = NetworkStrength.unknown + for line in out.split('\n'): + signal_str = "SignalStrength: " + if signal_str in line: + lvl_idx_start = line.find(signal_str) + len(signal_str) + lvl_idx_end = line.find(']', lvl_idx_start) + lvl = int(line[lvl_idx_start : lvl_idx_end]) + if lvl >= -50: + network_strength = NetworkStrength.great + elif lvl >= -60: + network_strength = NetworkStrength.good + elif lvl >= -70: + network_strength = NetworkStrength.moderate + else: + network_strength = NetworkStrength.poor + return network_strength else: - lvl = NetworkStrength.poor - return lvl - - def get_evdo_level(evdodbm, evdosnr): - lvl_evdodbm = NetworkStrength.unknown - lvl_evdosnr = NetworkStrength.unknown - if evdodbm >= -65: - lvl_evdodbm = NetworkStrength.great - elif evdodbm >= -75: - lvl_evdodbm = NetworkStrength.good - elif evdodbm >= -90: - lvl_evdodbm = NetworkStrength.moderate - elif evdodbm >= -105: - lvl_evdodbm = NetworkStrength.poor - if evdosnr >= 7: - lvl_evdosnr = NetworkStrength.great - elif evdosnr >= 5: - lvl_evdosnr = NetworkStrength.good - elif evdosnr >= 3: - lvl_evdosnr = NetworkStrength.moderate - elif evdosnr >= 1: - lvl_evdosnr = NetworkStrength.poor - return max(lvl_evdodbm, lvl_evdosnr) - - def get_cdma_level(cdmadbm, cdmaecio): - lvl_cdmadbm = NetworkStrength.unknown - lvl_cdmaecio = NetworkStrength.unknown - if cdmadbm >= -75: - lvl_cdmadbm = NetworkStrength.great - elif cdmadbm >= -85: - lvl_cdmadbm = NetworkStrength.good - elif cdmadbm >= -95: - lvl_cdmadbm = NetworkStrength.moderate - elif cdmadbm >= -100: - lvl_cdmadbm = NetworkStrength.poor - if cdmaecio >= -90: - lvl_cdmaecio = NetworkStrength.great - elif cdmaecio >= -110: - lvl_cdmaecio = NetworkStrength.good - elif cdmaecio >= -130: - lvl_cdmaecio = NetworkStrength.moderate - elif cdmaecio >= -150: - lvl_cdmaecio = NetworkStrength.poor - return max(lvl_cdmadbm, lvl_cdmaecio) - - if network_type == NetworkType.none: - return network_strength - if network_type == NetworkType.wifi: - out = subprocess.check_output('dumpsys connectivity', shell=True).decode('utf-8') - network_strength = NetworkStrength.unknown - for line in out.split('\n'): - signal_str = "SignalStrength: " - if signal_str in line: - lvl_idx_start = line.find(signal_str) + len(signal_str) - lvl_idx_end = line.find(']', lvl_idx_start) - lvl = int(line[lvl_idx_start : lvl_idx_end]) - if lvl >= -50: - network_strength = NetworkStrength.great - elif lvl >= -60: - network_strength = NetworkStrength.good - elif lvl >= -70: - network_strength = NetworkStrength.moderate - else: - network_strength = NetworkStrength.poor - return network_strength - else: - # check cell strength - out = subprocess.check_output('dumpsys telephony.registry', shell=True).decode('utf-8') - for line in out.split('\n'): - if "mSignalStrength" in line: - arr = line.split(' ') - ns = 0 - if ("gsm" in arr[14]): - rsrp = int(arr[9]) - rssnr = int(arr[11]) - ns = get_lte_level(rsrp, rssnr) - if ns == NetworkStrength.unknown: - tdscmadbm = int(arr[13]) - ns = get_tdscdma_level(tdscmadbm) + # check cell strength + out = subprocess.check_output('dumpsys telephony.registry', shell=True).decode('utf-8') + for line in out.split('\n'): + if "mSignalStrength" in line: + arr = line.split(' ') + ns = 0 + if ("gsm" in arr[14]): + rsrp = int(arr[9]) + rssnr = int(arr[11]) + ns = get_lte_level(rsrp, rssnr) if ns == NetworkStrength.unknown: - asu = int(arr[1]) - ns = get_gsm_level(asu) - else: - cdmadbm = int(arr[3]) - cdmaecio = int(arr[4]) - evdodbm = int(arr[5]) - evdosnr = int(arr[7]) - lvl_cdma = get_cdma_level(cdmadbm, cdmaecio) - lvl_edmo = get_evdo_level(evdodbm, evdosnr) - if lvl_edmo == NetworkStrength.unknown: - ns = lvl_cdma - elif lvl_cdma == NetworkStrength.unknown: - ns = lvl_edmo + tdscmadbm = int(arr[13]) + ns = get_tdscdma_level(tdscmadbm) + if ns == NetworkStrength.unknown: + asu = int(arr[1]) + ns = get_gsm_level(asu) else: - ns = min(lvl_cdma, lvl_edmo) - network_strength = max(network_strength, ns) + cdmadbm = int(arr[3]) + cdmaecio = int(arr[4]) + evdodbm = int(arr[5]) + evdosnr = int(arr[7]) + lvl_cdma = get_cdma_level(cdmadbm, cdmaecio) + lvl_edmo = get_evdo_level(evdodbm, evdosnr) + if lvl_edmo == NetworkStrength.unknown: + ns = lvl_cdma + elif lvl_cdma == NetworkStrength.unknown: + ns = lvl_edmo + else: + ns = min(lvl_cdma, lvl_edmo) + network_strength = max(network_strength, ns) - return network_strength + return network_strength diff --git a/common/basedir.py b/common/basedir.py index 4d62fdc19c..d98509ed6d 100644 --- a/common/basedir.py +++ b/common/basedir.py @@ -1,10 +1,10 @@ import os BASEDIR = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), "../")) -from common.android import ANDROID -if ANDROID: - PERSIST = "/persist" - PARAMS = "/data/params" -else: +from common.hardware import PC +if PC: PERSIST = os.path.join(BASEDIR, "persist") PARAMS = os.path.join(BASEDIR, "persist", "params") +else: + PERSIST = "/persist" + PARAMS = "/data/params" diff --git a/common/hardware.py b/common/hardware.py index a1bab3c313..28cfe53451 100644 --- a/common/hardware.py +++ b/common/hardware.py @@ -1,4 +1,54 @@ import os +import random +from typing import cast + +from cereal import log +from common.android import Android +from common.hardware_base import HardwareBase EON = os.path.isfile('/EON') TICI = os.path.isfile('/TICI') +PC = not (EON or TICI) +ANDROID = EON + + +NetworkType = log.ThermalData.NetworkType +NetworkStrength = log.ThermalData.NetworkStrength + + +class Pc(HardwareBase): + def get_sound_card_online(self): + return True + + def get_imei(self, slot): + return "%015d" % random.randint(0, 1 << 32) + + def get_serial(self): + return "cccccccc" + + def get_subscriber_info(self): + return "" + + def reboot(self, reason=None): + print("REBOOT!") + + def get_network_type(self): + return NetworkType.none + + def get_sim_info(self): + return { + 'sim_id': '', + 'mcc_mnc': None, + 'network_type': ["Unknown"], + 'sim_state': ["ABSENT"], + 'data_connected': False + } + + def get_network_strength(self, network_type): + return NetworkStrength.unknown + + +if EON: + HARDWARE = cast(HardwareBase, Android()) +else: + HARDWARE = cast(HardwareBase, Pc()) diff --git a/common/hardware_base.py b/common/hardware_base.py new file mode 100644 index 0000000000..d5cc08253b --- /dev/null +++ b/common/hardware_base.py @@ -0,0 +1,34 @@ +from abc import abstractmethod + +class HardwareBase: + @abstractmethod + def get_sound_card_online(self): + pass + + @abstractmethod + def get_imei(self, slot): + pass + + @abstractmethod + def get_serial(self): + pass + + @abstractmethod + def get_subscriber_info(self): + pass + + @abstractmethod + def reboot(self, reason=None): + pass + + @abstractmethod + def get_network_type(self): + pass + + @abstractmethod + def get_sim_info(self): + pass + + @abstractmethod + def get_network_strength(self, network_type): + pass diff --git a/common/realtime.py b/common/realtime.py index e734438646..5e5fb709ca 100644 --- a/common/realtime.py +++ b/common/realtime.py @@ -6,7 +6,7 @@ import subprocess import multiprocessing from cffi import FFI -from common.android import ANDROID +from common.hardware import ANDROID from common.common_pyx import sec_since_boot # pylint: disable=no-name-in-module, import-error diff --git a/release/files_common b/release/files_common index bf350b7e3a..02bee33d6c 100644 --- a/release/files_common +++ b/release/files_common @@ -19,6 +19,7 @@ common/.gitignore common/__init__.py common/android.py common/hardware.py +common/hardware_base.py common/gpio.py common/realtime.py common/clock.pyx diff --git a/selfdrive/athena/athenad.py b/selfdrive/athena/athenad.py index 72e81a58bb..6f34cbed7c 100755 --- a/selfdrive/athena/athenad.py +++ b/selfdrive/athena/athenad.py @@ -20,7 +20,7 @@ from websocket import ABNF, WebSocketTimeoutException, create_connection import cereal.messaging as messaging from cereal.services import service_list -from common import android +from common.hardware import HARDWARE from common.api import Api from common.basedir import PERSIST from common.params import Params @@ -132,7 +132,7 @@ def reboot(): def do_reboot(): time.sleep(2) - android.reboot() + HARDWARE.reboot() threading.Thread(target=do_reboot).start() @@ -218,21 +218,7 @@ def getSshAuthorizedKeys(): @dispatcher.add_method def getSimInfo(): - sim_state = android.getprop("gsm.sim.state").split(",") - network_type = android.getprop("gsm.network.type").split(',') - mcc_mnc = android.getprop("gsm.sim.operator.numeric") or None - - sim_id = android.parse_service_call_string(android.service_call(['iphonesubinfo', '11'])) - cell_data_state = android.parse_service_call_unpack(android.service_call(['phone', '46']), ">q") - cell_data_connected = (cell_data_state == 2) - - return { - 'sim_id': sim_id, - 'mcc_mnc': mcc_mnc, - 'network_type': network_type, - 'sim_state': sim_state, - 'data_connected': cell_data_connected - } + return HARDWARE.get_sim_info() @dispatcher.add_method diff --git a/selfdrive/boardd/tests/test_boardd_loopback.py b/selfdrive/boardd/tests/test_boardd_loopback.py index d6c110bbbe..8e1ec9ca25 100755 --- a/selfdrive/boardd/tests/test_boardd_loopback.py +++ b/selfdrive/boardd/tests/test_boardd_loopback.py @@ -8,7 +8,7 @@ from functools import wraps import cereal.messaging as messaging from cereal import car from common.basedir import PARAMS -from common.android import ANDROID +from common.hardware import ANDROID from common.params import Params from common.spinner import Spinner from panda import Panda diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 2546a598af..0b240ca5a9 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -2,7 +2,7 @@ import os import gc from cereal import car, log -from common.android import ANDROID, get_sound_card_online +from common.hardware import HARDWARE from common.numpy_fast import clip from common.realtime import sec_since_boot, set_realtime_priority, set_core_affinity, Ratekeeper, DT_CTRL from common.profiler import Profiler @@ -79,7 +79,7 @@ class Controls: internet_needed or not openpilot_enabled_toggle # detect sound card presence and ensure successful init - sounds_available = not ANDROID or get_sound_card_online() + sounds_available = HARDWARE.get_sound_card_online() car_recognized = self.CP.carName != 'mock' # If stock camera is disconnected, we loaded car controls and it's not dashcam mode diff --git a/selfdrive/crash.py b/selfdrive/crash.py index 7459f71668..22d6aa0680 100644 --- a/selfdrive/crash.py +++ b/selfdrive/crash.py @@ -6,9 +6,9 @@ import capnp from selfdrive.version import version, dirty from selfdrive.swaglog import cloudlog -from common.android import ANDROID +from common.hardware import PC -if os.getenv("NOLOG") or os.getenv("NOCRASH") or not ANDROID: +if os.getenv("NOLOG") or os.getenv("NOCRASH") or PC: def capture_exception(*args, **kwargs): pass diff --git a/selfdrive/loggerd/uploader.py b/selfdrive/loggerd/uploader.py index 34bfc78959..453fe90ca1 100644 --- a/selfdrive/loggerd/uploader.py +++ b/selfdrive/loggerd/uploader.py @@ -1,24 +1,26 @@ #!/usr/bin/env python3 +import ctypes +import inspect +import json import os +import random import re +import subprocess +import threading import time -import json -import random -import ctypes -import inspect -import requests import traceback -import threading -import subprocess -from selfdrive.swaglog import cloudlog -from selfdrive.loggerd.config import ROOT +import requests -from common import android -from common.params import Params +from cereal import log +from common.hardware import HARDWARE from common.api import Api +from common.params import Params from common.xattr import getxattr, setxattr +from selfdrive.loggerd.config import ROOT +from selfdrive.swaglog import cloudlog +NetworkType = log.ThermalData.NetworkType UPLOAD_ATTR_NAME = 'user.upload' UPLOAD_ATTR_VALUE = b'1' @@ -69,13 +71,8 @@ def clear_locks(root): cloudlog.exception("clear_locks failed") def is_on_wifi(): - # ConnectivityManager.getActiveNetworkInfo() try: - # TODO: figure out why the android service call sometimes dies with SIGUSR2 (signal from MSGQ) - result = android.parse_service_call_string(android.service_call(["connectivity", "2"])) - if result is None: - return True - return 'WIFI' in result + return HARDWARE.get_network_type() == NetworkType.wifi except Exception: cloudlog.exception("is_on_wifi failed") return False diff --git a/selfdrive/manager.py b/selfdrive/manager.py index 75168781b3..90b6b221ec 100755 --- a/selfdrive/manager.py +++ b/selfdrive/manager.py @@ -14,7 +14,7 @@ from selfdrive.swaglog import cloudlog, add_logentries_handler from common.basedir import BASEDIR, PARAMS -from common.android import ANDROID +from common.hardware import HARDWARE, ANDROID, PC WEBCAM = os.getenv("WEBCAM") is not None sys.path.append(os.path.join(BASEDIR, "pyextra")) os.environ['BASEDIR'] = BASEDIR @@ -156,7 +156,6 @@ from selfdrive.registration import register from selfdrive.version import version, dirty from selfdrive.loggerd.config import ROOT from selfdrive.launcher import launcher -from common import android from common.apk import update_apks, pm_apply_packages, start_offroad ThermalStatus = cereal.log.ThermalData.ThermalStatus @@ -253,13 +252,18 @@ if WEBCAM: 'dmonitoringmodeld', ] -if ANDROID: +if not PC: car_started_processes += [ 'sensord', - 'gpsd', 'dmonitoringmodeld', ] +if ANDROID: + car_started_processes += [ + 'gpsd', + ] + + def register_managed_process(name, desc, car_started=False): global managed_processes, car_started_processes, persistent_processes print("registering %s" % name) @@ -365,6 +369,7 @@ def kill_managed_process(name): join_process(running[name], 15) if running[name].exitcode is None: cloudlog.critical("unkillable process %s failed to die!" % name) + # TODO: Use method from HARDWARE if ANDROID: cloudlog.critical("FORCE REBOOTING PHONE!") os.system("date >> /sdcard/unkillable_reboot") @@ -536,7 +541,7 @@ def uninstall(): with open('/cache/recovery/command', 'w') as f: f.write('--wipe_data\n') # IPowerManager.reboot(confirm=false, reason="recovery", wait=true) - android.reboot(reason="recovery") + HARDWARE.reboot(reason="recovery") def main(): os.environ['PARAMS_PATH'] = PARAMS diff --git a/selfdrive/registration.py b/selfdrive/registration.py index 6e1596f35a..de2231a458 100644 --- a/selfdrive/registration.py +++ b/selfdrive/registration.py @@ -4,12 +4,13 @@ import json from datetime import datetime, timedelta from selfdrive.swaglog import cloudlog from selfdrive.version import version, terms_version, training_version, get_git_commit, get_git_branch, get_git_remote -from common.android import get_imei, get_serial, get_subscriber_info +from common.hardware import HARDWARE from common.api import api_get from common.params import Params from common.file_helpers import mkdirs_exists_ok from common.basedir import PERSIST + def register(): params = Params() params.put("Version", version) @@ -19,7 +20,7 @@ def register(): params.put("GitCommit", get_git_commit(default="")) params.put("GitBranch", get_git_branch(default="")) params.put("GitRemote", get_git_remote(default="")) - params.put("SubscriberInfo", get_subscriber_info()) + params.put("SubscriberInfo", HARDWARE.get_subscriber_info()) # create a key for auth # your private key is kept on your device persist partition and never sent to our servers @@ -50,7 +51,7 @@ def register(): try: cloudlog.info("getting pilotauth") resp = api_get("v2/pilotauth/", method='POST', timeout=15, - imei=get_imei(0), imei2=get_imei(1), serial=get_serial(), public_key=public_key, register_token=register_token) + imei=HARDWARE.get_imei(0), imei2=HARDWARE.get_imei(1), serial=HARDWARE.get_serial(), public_key=public_key, register_token=register_token) dongleauth = json.loads(resp.text) dongle_id = dongleauth["dongle_id"] diff --git a/selfdrive/test/helpers.py b/selfdrive/test/helpers.py index 8e852e997f..47d302fff4 100644 --- a/selfdrive/test/helpers.py +++ b/selfdrive/test/helpers.py @@ -3,7 +3,7 @@ import subprocess from functools import wraps from nose.tools import nottest -from common.android import ANDROID +from common.hardware import PC from common.apk import update_apks, start_offroad, pm_apply_packages, android_packages from common.params import Params from selfdrive.version import training_version, terms_version @@ -19,10 +19,10 @@ def set_params_enabled(): params.put("CompletedTrainingVersion", training_version) def phone_only(x): - if ANDROID: - return x - else: + if PC: return nottest(x) + else: + return x def with_processes(processes, init_time=0): def wrapper(func): @@ -68,4 +68,3 @@ def with_apks(): assert apk_is_not_running, package return wrap return wrapper - diff --git a/selfdrive/test/process_replay/camera_replay.py b/selfdrive/test/process_replay/camera_replay.py index 501f8f6111..fb50b0c4af 100755 --- a/selfdrive/test/process_replay/camera_replay.py +++ b/selfdrive/test/process_replay/camera_replay.py @@ -5,7 +5,7 @@ import time from typing import Any from tqdm import tqdm -from common.android import ANDROID +from common.hardware import ANDROID os.environ['CI'] = "1" if ANDROID: os.environ['QCOM_REPLAY'] = "1" @@ -101,4 +101,3 @@ if __name__ == "__main__": f.write(diff2) sys.exit(int(failed)) - diff --git a/selfdrive/test/test_sounds.py b/selfdrive/test/test_sounds.py index e9946efb0f..2ee7b0826c 100755 --- a/selfdrive/test/test_sounds.py +++ b/selfdrive/test/test_sounds.py @@ -5,7 +5,7 @@ import subprocess from cereal import log, car import cereal.messaging as messaging from selfdrive.test.helpers import phone_only, with_processes -from common.android import get_sound_card_online +from common.hardware import HARDWARE from common.realtime import DT_CTRL AudibleAlert = car.CarControl.HUDControl.AudibleAlert @@ -30,7 +30,7 @@ def get_total_writes(): @phone_only def test_sound_card_init(): - assert get_sound_card_online() + assert HARDWARE.get_sound_card_online() @phone_only diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index 63f1a7e9b6..255015a761 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -9,9 +9,8 @@ from smbus2 import SMBus import cereal.messaging as messaging from cereal import log -from common.android import get_network_strength, get_network_type from common.filter_simple import FirstOrderFilter -from common.hardware import EON, TICI +from common.hardware import EON, HARDWARE, TICI from common.numpy_fast import clip, interp from common.params import Params, put_nonblocking from common.realtime import DT_TRML, sec_since_boot @@ -241,8 +240,8 @@ def thermald_thread(): # get_network_type is an expensive call. update every 10s if (count % int(10. / DT_TRML)) == 0: try: - network_type = get_network_type() - network_strength = get_network_strength(network_type) + network_type = HARDWARE.get_network_type() + network_strength = HARDWARE.get_network_strength(network_type) except Exception: cloudlog.exception("Error getting network status") diff --git a/tools/lib/auth_config.py b/tools/lib/auth_config.py index 0cc3e33b51..b59fa2e89f 100644 --- a/tools/lib/auth_config.py +++ b/tools/lib/auth_config.py @@ -1,17 +1,21 @@ import json import os -from common.android import ANDROID +from common.hardware import PC from common.file_helpers import mkdirs_exists_ok + class MissingAuthConfigError(Exception): pass -if ANDROID: - CONFIG_DIR = "/tmp/.comma" -else: + +if PC: CONFIG_DIR = os.path.expanduser('~/.comma') +else: + CONFIG_DIR = "/tmp/.comma" + mkdirs_exists_ok(CONFIG_DIR) + def get_token(): try: with open(os.path.join(CONFIG_DIR, 'auth.json')) as f: @@ -20,9 +24,11 @@ def get_token(): except Exception: raise MissingAuthConfigError('Authenticate with tools/lib/auth.py') + def set_token(token): with open(os.path.join(CONFIG_DIR, 'auth.json'), 'w') as f: json.dump({'access_token': token}, f) + def clear_token(): os.unlink(os.path.join(CONFIG_DIR, 'auth.json'))