Merge remote-tracking branch 'upstream/master' into disp-personality

pull/31760/head
Shane Smiskol 1 year ago
commit 6af6057ba7
  1. 12
      .vscode/settings.json
  2. 2
      pyproject.toml
  3. 5
      selfdrive/car/__init__.py
  4. 2
      selfdrive/car/card.py
  5. 5
      selfdrive/car/chrysler/values.py
  6. 6
      selfdrive/car/ford/values.py
  7. 6
      selfdrive/car/honda/values.py
  8. 6
      selfdrive/car/hyundai/values.py
  9. 5
      selfdrive/car/mazda/values.py
  10. 5
      selfdrive/car/nissan/interface.py
  11. 6
      selfdrive/car/subaru/values.py
  12. 3
      selfdrive/car/tests/routes.py
  13. 25
      selfdrive/car/tests/test_models.py
  14. 6
      selfdrive/car/toyota/values.py
  15. 6
      selfdrive/car/volkswagen/values.py
  16. 37
      selfdrive/test/helpers.py
  17. 60
      selfdrive/updated/tests/test_updated.py
  18. 6
      tools/car_porting/test_car_model.py

@ -12,5 +12,15 @@
"**/.git": true,
"**/.venv": true,
"**/__pycache__": true
}
},
"python.analysis.exclude": [
"**/.git",
"**/.venv",
"**/__pycache__",
// exclude directories should be using the symlinked version
"common/**",
"selfdrive/**",
"system/**",
"tools/**",
]
}

@ -177,6 +177,8 @@ lint.ignore = ["E741", "E402", "C408", "ISC003", "B027", "B024"]
line-length = 160
target-version="py311"
exclude = [
"body",
"cereal",
"panda",
"opendbc",
"rednose_repo",

@ -318,3 +318,8 @@ class Platforms(str, ReprEnum):
for flag, platforms in platforms_with_flag.items():
print(f"{flag:32s}: {', '.join(p.name for p in platforms)}")
class PlatformFlags(IntFlag):
def __init__(self, value: int):
assert value < 2**32, "undefined behaviour with >32 bit flags"

@ -70,7 +70,7 @@ class CarD:
if prev_cp is not None:
self.params.put("CarParamsPrevRoute", prev_cp)
# Write CarParams for radard
# Write CarParams for controls and radard
cp_bytes = self.CP.to_bytes()
self.params.put("CarParams", cp_bytes)
self.params.put_nonblocking("CarParamsCache", cp_bytes)

@ -1,16 +1,15 @@
from enum import IntFlag
from dataclasses import dataclass, field
from cereal import car
from panda.python import uds
from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict
from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, PlatformFlags, Platforms, dbc_dict
from openpilot.selfdrive.car.docs_definitions import CarHarness, CarInfo, CarParts
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16
Ecu = car.CarParams.Ecu
class ChryslerFlags(IntFlag):
class ChryslerFlags(PlatformFlags):
# Detected flags
HIGHER_MIN_STEERING_SPEED = 1

@ -1,9 +1,9 @@
from dataclasses import dataclass, field
from enum import Enum, IntFlag
from enum import Enum
import panda.python.uds as uds
from cereal import car
from openpilot.selfdrive.car import AngleRateLimit, CarSpecs, dbc_dict, DbcDict, PlatformConfig, Platforms
from openpilot.selfdrive.car import AngleRateLimit, CarSpecs, PlatformFlags, dbc_dict, DbcDict, PlatformConfig, Platforms
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarInfo, CarParts, Column, \
Device
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16
@ -39,7 +39,7 @@ class CarControllerParams:
pass
class FordFlags(IntFlag):
class FordFlags(PlatformFlags):
# Static flags
CANFD = 1

@ -1,10 +1,10 @@
from dataclasses import dataclass
from enum import Enum, IntFlag
from enum import Enum
from cereal import car
from openpilot.common.conversions import Conversions as CV
from panda.python import uds
from openpilot.selfdrive.car import CarSpecs, PlatformConfig, Platforms, dbc_dict
from openpilot.selfdrive.car import CarSpecs, PlatformConfig, PlatformFlags, Platforms, dbc_dict
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarInfo, CarParts, Column
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16
@ -45,7 +45,7 @@ class CarControllerParams:
self.STEER_LOOKUP_V = [v * -1 for v in CP.lateralParams.torqueV][1:][::-1] + list(CP.lateralParams.torqueV)
class HondaFlags(IntFlag):
class HondaFlags(PlatformFlags):
# Detected flags
# Bosch models with alternate set of LKAS_HUD messages
BOSCH_EXT_HUD = 1

@ -1,11 +1,11 @@
import re
from dataclasses import dataclass, field
from enum import Enum, IntFlag
from enum import Enum
from cereal import car
from panda.python import uds
from openpilot.common.conversions import Conversions as CV
from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict
from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, PlatformFlags, Platforms, dbc_dict
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarInfo, CarParts, Column
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16
@ -51,7 +51,7 @@ class CarControllerParams:
self.STEER_MAX = 384
class HyundaiFlags(IntFlag):
class HyundaiFlags(PlatformFlags):
# Dynamic Flags
CANFD_HDA2 = 1
CANFD_ALT_BUTTONS = 2

@ -1,9 +1,8 @@
from dataclasses import dataclass, field
from enum import IntFlag
from cereal import car
from openpilot.common.conversions import Conversions as CV
from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict
from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, PlatformFlags, Platforms, dbc_dict
from openpilot.selfdrive.car.docs_definitions import CarHarness, CarInfo, CarParts
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
@ -37,7 +36,7 @@ class MazdaCarSpecs(CarSpecs):
tireStiffnessFactor: float = 0.7 # not optimized yet
class MazdaFlags(IntFlag):
class MazdaFlags(PlatformFlags):
# Static flags
# Gen 1 hardware: same CAN messages and same camera
GEN1 = 1

@ -30,11 +30,6 @@ class CarInterface(CarInterfaceBase):
def _update(self, c):
ret = self.CS.update(self.cp, self.cp_adas, self.cp_cam)
buttonEvents = []
be = car.CarState.ButtonEvent.new_message()
be.type = car.CarState.ButtonEvent.Type.accelCruise
buttonEvents.append(be)
events = self.create_common_events(ret, extra_gears=[car.CarState.GearShifter.brake])
if self.CS.lkas_enabled:

@ -1,9 +1,9 @@
from dataclasses import dataclass, field
from enum import Enum, IntFlag
from enum import Enum
from cereal import car
from panda.python import uds
from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict
from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, PlatformFlags, dbc_dict
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarInfo, CarParts, Tool, Column
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16
@ -52,7 +52,7 @@ class CarControllerParams:
BRAKE_LOOKUP_V = [BRAKE_MAX, BRAKE_MIN]
class SubaruFlags(IntFlag):
class SubaruFlags(PlatformFlags):
# Detected flags
SEND_INFOTAINMENT = 1
DISABLE_EYESIGHT = 2

@ -10,6 +10,7 @@ from openpilot.selfdrive.car.nissan.values import CAR as NISSAN
from openpilot.selfdrive.car.mazda.values import CAR as MAZDA
from openpilot.selfdrive.car.subaru.values import CAR as SUBARU
from openpilot.selfdrive.car.toyota.values import CAR as TOYOTA
from openpilot.selfdrive.car.values import Platform
from openpilot.selfdrive.car.volkswagen.values import CAR as VOLKSWAGEN
from openpilot.selfdrive.car.tesla.values import CAR as TESLA
from openpilot.selfdrive.car.body.values import CAR as COMMA
@ -29,7 +30,7 @@ non_tested_cars = [
class CarTestRoute(NamedTuple):
route: str
car_model: str | None
car_model: Platform | None
segment: int | None = None

@ -19,6 +19,7 @@ from openpilot.selfdrive.car.fingerprints import all_known_cars
from openpilot.selfdrive.car.car_helpers import FRAME_FINGERPRINT, interfaces
from openpilot.selfdrive.car.honda.values import CAR as HONDA, HondaFlags
from openpilot.selfdrive.car.tests.routes import non_tested_cars, routes, CarTestRoute
from openpilot.selfdrive.car.values import PLATFORMS, Platform
from openpilot.selfdrive.controls.controlsd import Controls
from openpilot.selfdrive.test.helpers import read_segment_list
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
@ -64,7 +65,7 @@ def get_test_cases() -> list[tuple[str, CarTestRoute | None]]:
@pytest.mark.slow
@pytest.mark.shared_download_cache
class TestCarModelBase(unittest.TestCase):
car_model: str | None = None
platform: Platform | None = None
test_route: CarTestRoute | None = None
test_route_on_bucket: bool = True # whether the route is on the preserved CI bucket
@ -93,8 +94,8 @@ class TestCarModelBase(unittest.TestCase):
car_fw = msg.carParams.carFw
if msg.carParams.openpilotLongitudinalControl:
experimental_long = True
if cls.car_model is None and not cls.ci:
cls.car_model = msg.carParams.carFingerprint
if cls.platform is None and not cls.ci:
cls.platform = PLATFORMS.get(msg.carParams.carFingerprint)
# Log which can frame the panda safety mode left ELM327, for CAN validity checks
elif msg.which() == 'pandaStates':
@ -155,15 +156,11 @@ class TestCarModelBase(unittest.TestCase):
if cls.__name__ == 'TestCarModel' or cls.__name__.endswith('Base'):
raise unittest.SkipTest
if 'FILTER' in os.environ:
if not cls.car_model.startswith(tuple(os.environ.get('FILTER').split(','))):
raise unittest.SkipTest
if cls.test_route is None:
if cls.car_model in non_tested_cars:
print(f"Skipping tests for {cls.car_model}: missing route")
if cls.platform in non_tested_cars:
print(f"Skipping tests for {cls.platform}: missing route")
raise unittest.SkipTest
raise Exception(f"missing test route for {cls.car_model}")
raise Exception(f"missing test route for {cls.platform}")
car_fw, can_msgs, experimental_long = cls.get_testing_data()
@ -172,10 +169,10 @@ class TestCarModelBase(unittest.TestCase):
cls.can_msgs = sorted(can_msgs, key=lambda msg: msg.logMonoTime)
cls.CarInterface, cls.CarController, cls.CarState = interfaces[cls.car_model]
cls.CP = cls.CarInterface.get_params(cls.car_model, cls.fingerprint, car_fw, experimental_long, docs=False)
cls.CarInterface, cls.CarController, cls.CarState = interfaces[cls.platform]
cls.CP = cls.CarInterface.get_params(cls.platform, cls.fingerprint, car_fw, experimental_long, docs=False)
assert cls.CP
assert cls.CP.carFingerprint == cls.car_model
assert cls.CP.carFingerprint == cls.platform
os.environ["COMMA_CACHE"] = DEFAULT_DOWNLOAD_CACHE_ROOT
@ -478,7 +475,7 @@ class TestCarModelBase(unittest.TestCase):
"This is fine to fail for WIP car ports, just let us know and we can upload your routes to the CI bucket.")
@parameterized_class(('car_model', 'test_route'), get_test_cases())
@parameterized_class(('platform', 'test_route'), get_test_cases())
@pytest.mark.xdist_group_class_property('test_route')
class TestCarModel(TestCarModelBase):
pass

@ -1,11 +1,11 @@
import re
from collections import defaultdict
from dataclasses import dataclass, field
from enum import Enum, IntFlag
from enum import Enum
from cereal import car
from openpilot.common.conversions import Conversions as CV
from openpilot.selfdrive.car import CarSpecs, PlatformConfig, Platforms
from openpilot.selfdrive.car import CarSpecs, PlatformConfig, PlatformFlags, Platforms
from openpilot.selfdrive.car import AngleRateLimit, dbc_dict
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarInfo, Column, CarParts, CarHarness
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
@ -41,7 +41,7 @@ class CarControllerParams:
self.STEER_DELTA_DOWN = 25 # always lower than 45 otherwise the Rav4 faults (Prius seems ok with 50)
class ToyotaFlags(IntFlag):
class ToyotaFlags(PlatformFlags):
# Detected flags
HYBRID = 1
SMART_DSU = 2

@ -1,12 +1,12 @@
from collections import namedtuple
from dataclasses import dataclass, field
from enum import Enum, IntFlag
from enum import Enum
from cereal import car
from panda.python import uds
from opendbc.can.can_define import CANDefine
from openpilot.common.conversions import Conversions as CV
from openpilot.selfdrive.car import dbc_dict, CarSpecs, DbcDict, PlatformConfig, Platforms
from openpilot.selfdrive.car import PlatformFlags, dbc_dict, CarSpecs, DbcDict, PlatformConfig, Platforms
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarInfo, CarParts, Column, \
Device
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16
@ -109,7 +109,7 @@ class CANBUS:
cam = 2
class VolkswagenFlags(IntFlag):
class VolkswagenFlags(PlatformFlags):
# Detected flags
STOCK_HCA_PRESENT = 1

@ -88,23 +88,28 @@ def read_segment_list(segment_list_path):
return [(platform[2:], segment) for platform, segment in zip(seg_list[::2], seg_list[1::2], strict=True)]
@contextlib.contextmanager
def http_server_context(handler, setup=None):
host = '127.0.0.1'
server = http.server.HTTPServer((host, 0), handler)
port = server.server_port
t = threading.Thread(target=server.serve_forever)
t.start()
if setup is not None:
setup(host, port)
try:
yield (host, port)
finally:
server.shutdown()
server.server_close()
t.join()
def with_http_server(func, handler=http.server.BaseHTTPRequestHandler, setup=None):
@wraps(func)
def inner(*args, **kwargs):
host = '127.0.0.1'
server = http.server.HTTPServer((host, 0), handler)
port = server.server_port
t = threading.Thread(target=server.serve_forever)
t.start()
if setup is not None:
setup(host, port)
try:
return func(*args, f'http://{host}:{port}', **kwargs)
finally:
server.shutdown()
server.server_close()
t.join()
with http_server_context(handler, setup) as (host, port):
return func(*args, f"http://{host}:{port}", **kwargs)
return inner

@ -21,7 +21,7 @@ def run(args, **kwargs):
return subprocess.run(args, **kwargs, check=True)
def update_release(directory, name, version, release_notes):
def update_release(directory, name, version, agnos_version, release_notes):
with open(directory / "RELEASES.md", "w") as f:
f.write(release_notes)
@ -30,6 +30,9 @@ def update_release(directory, name, version, release_notes):
with open(directory / "common" / "version.h", "w") as f:
f.write(f'#define COMMA_VERSION "{version}"')
with open(directory / "launch_env.sh", "w") as f:
f.write(f'export AGNOS_VERSION="{agnos_version}"')
run(["git", "add", "."], cwd=directory)
run(["git", "commit", "-m", f"openpilot release {version}"], cwd=directory)
@ -60,8 +63,8 @@ class TestUpdateD(unittest.TestCase):
os.environ["UPDATER_LOCK_FILE"] = str(self.mock_update_path / "safe_staging_overlay.lock")
self.MOCK_RELEASES = {
"release3": ("0.1.2", "0.1.2 release notes"),
"master": ("0.1.3", "0.1.3 release notes"),
"release3": ("0.1.2", "1.2", "0.1.2 release notes"),
"master": ("0.1.3", "1.2", "0.1.3 release notes"),
}
def set_target_branch(self, branch):
@ -97,7 +100,7 @@ class TestUpdateD(unittest.TestCase):
self.assertEqual(self.params.get_bool("UpdaterFetchAvailable"), fetch_available)
self.assertEqual(self.params.get_bool("UpdateAvailable"), update_available)
def _test_update_params(self, branch, version, release_notes):
def _test_update_params(self, branch, version, agnos_version, release_notes):
self.assertTrue(self.params.get("UpdaterNewDescription", encoding="utf-8").startswith(f"{version} / {branch}"))
self.assertEqual(self.params.get("UpdaterNewReleaseNotes", encoding="utf-8"), f"<p>{release_notes}</p>\n")
@ -116,6 +119,22 @@ class TestUpdateD(unittest.TestCase):
time.sleep(1)
def test_no_update(self):
# Start on release3, ensure we don't fetch any updates
self.setup_remote_release("release3")
self.setup_basedir_release("release3")
with processes_context(["updated"]) as [updated]:
self._test_params("release3", False, False)
time.sleep(1)
self._test_params("release3", False, False)
self.send_check_for_updates_signal(updated)
self.wait_for_idle()
self._test_params("release3", False, False)
def test_new_release(self):
# Start on release3, simulate a release3 commit, ensure we fetch that update properly
self.setup_remote_release("release3")
@ -126,7 +145,7 @@ class TestUpdateD(unittest.TestCase):
time.sleep(1)
self._test_params("release3", False, False)
self.MOCK_RELEASES["release3"] = ("0.1.3", "0.1.3 release notes")
self.MOCK_RELEASES["release3"] = ("0.1.3", "1.2", "0.1.3 release notes")
self.update_remote_release("release3")
self.send_check_for_updates_signal(updated)
@ -167,6 +186,37 @@ class TestUpdateD(unittest.TestCase):
self._test_params("master", False, True)
self._test_update_params("master", *self.MOCK_RELEASES["master"])
def test_agnos_update(self):
# Start on release3, push an update with an agnos change
self.setup_remote_release("release3")
self.setup_basedir_release("release3")
with mock.patch("openpilot.system.hardware.AGNOS", "True"), \
mock.patch("openpilot.system.hardware.tici.hardware.Tici.get_os_version", "1.2"), \
mock.patch("openpilot.system.hardware.tici.agnos.get_target_slot_number"), \
mock.patch("openpilot.system.hardware.tici.agnos.flash_agnos_update"), \
processes_context(["updated"]) as [updated]:
self._test_params("release3", False, False)
time.sleep(1)
self._test_params("release3", False, False)
self.MOCK_RELEASES["release3"] = ("0.1.3", "1.3", "0.1.3 release notes")
self.update_remote_release("release3")
self.send_check_for_updates_signal(updated)
self.wait_for_idle()
self._test_params("release3", True, False)
self.send_download_signal(updated)
self.wait_for_idle()
self._test_params("release3", False, True)
self._test_update_params("release3", *self.MOCK_RELEASES["release3"])
if __name__ == "__main__":
unittest.main()

@ -5,6 +5,7 @@ import unittest
from openpilot.selfdrive.car.tests.routes import CarTestRoute
from openpilot.selfdrive.car.tests.test_models import TestCarModel
from openpilot.selfdrive.car.values import PLATFORMS
from openpilot.tools.lib.route import SegmentName
@ -31,7 +32,10 @@ if __name__ == "__main__":
route_or_segment_name = SegmentName(args.route_or_segment_name.strip(), allow_route_name=True)
segment_num = route_or_segment_name.segment_num if route_or_segment_name.segment_num != -1 else None
test_route = CarTestRoute(route_or_segment_name.route_name.canonical_name, args.car, segment=segment_num)
platform = PLATFORMS.get(args.car)
test_route = CarTestRoute(route_or_segment_name.route_name.canonical_name, platform, segment=segment_num)
test_suite = create_test_models_suite([test_route], ci=args.ci)
unittest.TextTestRunner().run(test_suite)

Loading…
Cancel
Save