Merge branch 'master' of ssh://github.com/commaai/openpilot into qcom-replay

pull/35821/head
Adeeb Shihadeh 3 days ago
commit a4a7150dab
  1. 2
      opendbc_repo
  2. 45
      selfdrive/car/tests/test_car_interfaces.py
  3. 2
      selfdrive/modeld/models/driving_policy.onnx
  4. 2
      selfdrive/modeld/models/driving_vision.onnx
  5. 2
      selfdrive/test/process_replay/ref_commit
  6. 7
      system/hardware/base.py
  7. 27
      system/hardware/esim.py
  8. 29
      system/hardware/tici/esim.py
  9. 10
      system/hardware/tici/hardware.py
  10. 4
      tools/auto_source.py

@ -1 +1 @@
Subproject commit ac6122e272e0dc040d5abf3bde6fca4e034a7ef7 Subproject commit 7afc25d8d4096bb31e25c0b7ae0b961ea05f5394

@ -1,15 +1,12 @@
import os import os
import math
import hypothesis.strategies as st import hypothesis.strategies as st
from hypothesis import Phase, given, settings from hypothesis import Phase, given, settings
from parameterized import parameterized from parameterized import parameterized
from cereal import car from cereal import car
from opendbc.car import DT_CTRL from opendbc.car import DT_CTRL
from opendbc.car.car_helpers import interfaces
from opendbc.car.structs import CarParams from opendbc.car.structs import CarParams
from opendbc.car.tests.test_car_interfaces import get_fuzzy_car_interface_args from opendbc.car.tests.test_car_interfaces import get_fuzzy_car_interface
from opendbc.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS
from opendbc.car.mock.values import CAR as MOCK from opendbc.car.mock.values import CAR as MOCK
from opendbc.car.values import PLATFORMS from opendbc.car.values import PLATFORMS
from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle
@ -18,11 +15,6 @@ from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque
from openpilot.selfdrive.controls.lib.longcontrol import LongControl from openpilot.selfdrive.controls.lib.longcontrol import LongControl
from openpilot.selfdrive.test.fuzzy_generation import FuzzyGenerator from openpilot.selfdrive.test.fuzzy_generation import FuzzyGenerator
ALL_ECUS = {ecu for ecus in FW_VERSIONS.values() for ecu in ecus.keys()}
ALL_ECUS |= {ecu for config in FW_QUERY_CONFIGS.values() for ecu in config.extra_ecus}
ALL_REQUESTS = {tuple(r.request) for config in FW_QUERY_CONFIGS.values() for r in config.requests}
MAX_EXAMPLES = int(os.environ.get('MAX_EXAMPLES', '60')) MAX_EXAMPLES = int(os.environ.get('MAX_EXAMPLES', '60'))
@ -34,39 +26,8 @@ class TestCarInterfaces:
phases=(Phase.reuse, Phase.generate, Phase.shrink)) phases=(Phase.reuse, Phase.generate, Phase.shrink))
@given(data=st.data()) @given(data=st.data())
def test_car_interfaces(self, car_name, data): def test_car_interfaces(self, car_name, data):
CarInterface = interfaces[car_name] car_interface = get_fuzzy_car_interface(car_name, data.draw)
car_params = car_interface.CP.as_reader()
args = get_fuzzy_car_interface_args(data.draw)
car_params = CarInterface.get_params(car_name, args['fingerprints'], args['car_fw'],
alpha_long=args['alpha_long'], is_release=False, docs=False)
car_params = car_params.as_reader()
car_interface = CarInterface(car_params)
assert car_params
assert car_interface
assert car_params.mass > 1
assert car_params.wheelbase > 0
# centerToFront is center of gravity to front wheels, assert a reasonable range
assert car_params.wheelbase * 0.3 < car_params.centerToFront < car_params.wheelbase * 0.7
assert car_params.maxLateralAccel > 0
# Longitudinal sanity checks
assert len(car_params.longitudinalTuning.kpV) == len(car_params.longitudinalTuning.kpBP)
assert len(car_params.longitudinalTuning.kiV) == len(car_params.longitudinalTuning.kiBP)
# Lateral sanity checks
if car_params.steerControlType != CarParams.SteerControlType.angle:
tune = car_params.lateralTuning
if tune.which() == 'pid':
if car_name != MOCK.MOCK:
assert not math.isnan(tune.pid.kf) and tune.pid.kf > 0
assert len(tune.pid.kpV) > 0 and len(tune.pid.kpV) == len(tune.pid.kpBP)
assert len(tune.pid.kiV) > 0 and len(tune.pid.kiV) == len(tune.pid.kiBP)
elif tune.which() == 'torque':
assert not math.isnan(tune.torque.kf) and tune.torque.kf > 0
assert not math.isnan(tune.torque.friction) and tune.torque.friction > 0
cc_msg = FuzzyGenerator.get_random_msg(data.draw, car.CarControl, real_floats=True) cc_msg = FuzzyGenerator.get_random_msg(data.draw, car.CarControl, real_floats=True)
# Run car interface # Run car interface

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:72e98a95541f200bd2faeae8d718997483696fd4801fc7d718c167b05854707d oid sha256:ebb38a934d6472c061cc6010f46d9720ca132d631a47e585a893bdd41ade2419
size 12343535 size 12343535

@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:e66bb8d53eced3786ed71a59b55ffc6810944cb217f0518621cc76303260a1ef oid sha256:befac016a247b7ad5dc5b55d339d127774ed7bd2b848f1583f72aa4caee37781
size 46271991 size 46271991

@ -1 +1 @@
4c677a3ebcbd3d4faa3de98e3fb9c0bb83b47926 afcab1abb62b9d5678342956cced4712f44e909e

@ -65,6 +65,10 @@ class ThermalConfig:
return ret return ret
class LPABase(ABC): class LPABase(ABC):
@abstractmethod
def bootstrap(self) -> None:
pass
@abstractmethod @abstractmethod
def list_profiles(self) -> list[Profile]: def list_profiles(self) -> list[Profile]:
pass pass
@ -89,6 +93,9 @@ class LPABase(ABC):
def switch_profile(self, iccid: str) -> None: def switch_profile(self, iccid: str) -> None:
pass pass
def is_comma_profile(self, iccid: str) -> bool:
return any(iccid.startswith(prefix) for prefix in ('8985235',))
class HardwareBase(ABC): class HardwareBase(ABC):
@staticmethod @staticmethod
def get_cmdline() -> dict[str, str]: def get_cmdline() -> dict[str, str]:

@ -3,10 +3,32 @@
import argparse import argparse
import time import time
from openpilot.system.hardware import HARDWARE from openpilot.system.hardware import HARDWARE
from openpilot.system.hardware.base import LPABase
def bootstrap(lpa: LPABase) -> None:
print('┌──────────────────────────────────────────────────────────────────────────────┐')
print('│ WARNING, PLEASE READ BEFORE PROCEEDING │')
print('│ │')
print('│ this is an irreversible operation that will remove the comma-provisioned │')
print('│ profile. │')
print('│ │')
print('│ after this operation, you must purchase a new eSIM from comma in order to │')
print('│ use the comma prime subscription again. │')
print('└──────────────────────────────────────────────────────────────────────────────┘')
print()
for severity in ('sure', '100% sure'):
print(f'are you {severity} you want to proceed? (y/N) ', end='')
confirm = input()
if confirm != 'y':
print('aborting')
exit(0)
lpa.bootstrap()
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser(prog='esim.py', description='manage eSIM profiles on your comma device', epilog='comma.ai') parser = argparse.ArgumentParser(prog='esim.py', description='manage eSIM profiles on your comma device', epilog='comma.ai')
parser.add_argument('--bootstrap', action='store_true', help='bootstrap the eUICC (required before downloading profiles)')
parser.add_argument('--backend', choices=['qmi', 'at'], default='qmi', help='use the specified backend, defaults to qmi') parser.add_argument('--backend', choices=['qmi', 'at'], default='qmi', help='use the specified backend, defaults to qmi')
parser.add_argument('--switch', metavar='iccid', help='switch to profile') parser.add_argument('--switch', metavar='iccid', help='switch to profile')
parser.add_argument('--delete', metavar='iccid', help='delete profile (warning: this cannot be undone)') parser.add_argument('--delete', metavar='iccid', help='delete profile (warning: this cannot be undone)')
@ -16,7 +38,10 @@ if __name__ == '__main__':
mutated = False mutated = False
lpa = HARDWARE.get_sim_lpa() lpa = HARDWARE.get_sim_lpa()
if args.switch: if args.bootstrap:
bootstrap(lpa)
mutated = True
elif args.switch:
lpa.switch_profile(args.switch) lpa.switch_profile(args.switch)
mutated = True mutated = True
elif args.delete: elif args.delete:

@ -40,6 +40,7 @@ class TiciLPA(LPABase):
self._process_notifications() self._process_notifications()
def download_profile(self, qr: str, nickname: str | None = None) -> None: def download_profile(self, qr: str, nickname: str | None = None) -> None:
self._check_bootstrapped()
msgs = self._invoke('profile', 'download', '-a', qr) msgs = self._invoke('profile', 'download', '-a', qr)
self._validate_successful(msgs) self._validate_successful(msgs)
new_profile = next((m for m in msgs if m['payload']['message'] == 'es8p_meatadata_parse'), None) new_profile = next((m for m in msgs if m['payload']['message'] == 'es8p_meatadata_parse'), None)
@ -54,6 +55,7 @@ class TiciLPA(LPABase):
self._validate_successful(self._invoke('profile', 'nickname', iccid, nickname)) self._validate_successful(self._invoke('profile', 'nickname', iccid, nickname))
def switch_profile(self, iccid: str) -> None: def switch_profile(self, iccid: str) -> None:
self._check_bootstrapped()
self._validate_profile_exists(iccid) self._validate_profile_exists(iccid)
latest = self.get_active_profile() latest = self.get_active_profile()
if latest and latest.iccid == iccid: if latest and latest.iccid == iccid:
@ -61,6 +63,33 @@ class TiciLPA(LPABase):
self._validate_successful(self._invoke('profile', 'enable', iccid)) self._validate_successful(self._invoke('profile', 'enable', iccid))
self._process_notifications() self._process_notifications()
def bootstrap(self) -> None:
"""
find all comma-provisioned profiles and delete them. they conflict with user-provisioned profiles
and must be deleted.
**note**: this is a **very** destructive operation. you **must** purchase a new comma SIM in order
to use comma prime again.
"""
if self._is_bootstrapped():
return
for p in self.list_profiles():
if self.is_comma_profile(p.iccid):
self._disable_profile(p.iccid)
self.delete_profile(p.iccid)
def _disable_profile(self, iccid: str) -> None:
self._validate_successful(self._invoke('profile', 'disable', iccid))
self._process_notifications()
def _check_bootstrapped(self) -> None:
assert self._is_bootstrapped(), 'eUICC is not bootstrapped, please bootstrap before performing this operation'
def _is_bootstrapped(self) -> bool:
""" check if any comma provisioned profiles are on the eUICC """
return not any(self.is_comma_profile(iccid) for iccid in (p.iccid for p in self.list_profiles()))
def _invoke(self, *cmd: str): def _invoke(self, *cmd: str):
proc = subprocess.Popen(['sudo', '-E', 'lpac'] + list(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=self.env) proc = subprocess.Popen(['sudo', '-E', 'lpac'] + list(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=self.env)
try: try:

@ -487,7 +487,7 @@ class Tici(HardwareBase):
# eSIM prime # eSIM prime
dest = "/etc/NetworkManager/system-connections/esim.nmconnection" dest = "/etc/NetworkManager/system-connections/esim.nmconnection"
if sim_id.startswith('8985235') and not os.path.exists(dest): if self.get_sim_lpa().is_comma_profile(sim_id) and not os.path.exists(dest):
with open(Path(__file__).parent/'esim.nmconnection') as f, tempfile.NamedTemporaryFile(mode='w') as tf: with open(Path(__file__).parent/'esim.nmconnection') as f, tempfile.NamedTemporaryFile(mode='w') as tf:
dat = f.read() dat = f.read()
dat = dat.replace("sim-id=", f"sim-id={sim_id}") dat = dat.replace("sim-id=", f"sim-id={sim_id}")
@ -498,6 +498,14 @@ class Tici(HardwareBase):
os.system(f"sudo cp {tf.name} {dest}") os.system(f"sudo cp {tf.name} {dest}")
os.system(f"sudo nmcli con load {dest}") os.system(f"sudo nmcli con load {dest}")
def reboot_modem(self):
modem = self.get_modem()
for state in (0, 1):
try:
modem.Command(f'AT+CFUN={state}', math.ceil(TIMEOUT), dbus_interface=MM_MODEM, timeout=TIMEOUT)
except Exception:
pass
def get_networks(self): def get_networks(self):
r = {} r = {}

@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import sys import sys
from openpilot.tools.lib.logreader import LogReader from openpilot.tools.lib.logreader import LogReader, ReadMode
def main(): def main():
@ -9,7 +9,7 @@ def main():
sys.exit(1) sys.exit(1)
log_path = sys.argv[1] log_path = sys.argv[1]
lr = LogReader(log_path, sort_by_time=True) lr = LogReader(log_path, default_mode=ReadMode.AUTO, sort_by_time=True)
print("\n".join(lr.logreader_identifiers)) print("\n".join(lr.logreader_identifiers))

Loading…
Cancel
Save