diff --git a/cereal b/cereal
index c331e76b96..44c93ef17c 160000
--- a/cereal
+++ b/cereal
@@ -1 +1 @@
-Subproject commit c331e76b966d324a4f8d56b48db44f59601423dc
+Subproject commit 44c93ef17cd0973347935b93c67b65ddd5ace22c
diff --git a/docs/CARS.md b/docs/CARS.md
index 373851932f..a4af5fc4c0 100644
--- a/docs/CARS.md
+++ b/docs/CARS.md
@@ -8,8 +8,8 @@ A supported vehicle is one that just works when you install a comma three. All s
|Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|
Hardware Needed
|Video|
|---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
-|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Acura|ILX 2016-19|AcuraWatch Plus|openpilot|25 mph|25 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Acura|RDX 2016-18|AcuraWatch Plus|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Acura|RDX 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[](##)|[](##)|View
- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[](##)|[](##)|View
- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,10](#footnotes)|0 mph|0 mph|[](##)|[](##)|View
- 1 J533 connector
- 1 USB-C coupler
- 1 comma three
- 1 harness box
- 1 long OBD-C cable
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
@@ -55,20 +55,20 @@ A supported vehicle is one that just works when you install a comma three. All s
|Honda|Civic 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|View
- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here |
|
|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[](##)|[](##)|View
- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Honda|Civic Hatchback 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|View
- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here |
|
-|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Honda|CR-V 2015-16|Touring Trim|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[](##)|[](##)|View
- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Honda|CR-V Hybrid 2017-19|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[](##)|[](##)|View
- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Honda|e 2020|All|openpilot available[1](#footnotes)|0 mph|3 mph|[](##)|[](##)|View
- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Honda|Fit 2018-20|Honda Sensing|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Honda|Freed 2020|Honda Sensing|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Honda|HR-V 2019-22|Honda Sensing|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Honda|HR-V 2023|All|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|View
- 1 Honda Bosch B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[](##)|[](##)|View
- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[](##)|[](##)|View
- 1 Honda Bosch A connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Honda|Passport 2019-23|All|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
-|Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Honda|Odyssey 2018-20|Honda Sensing|openpilot|25 mph|0 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Honda|Passport 2019-23|All|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Honda|Pilot 2016-22|Honda Sensing|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
+|Honda|Ridgeline 2017-23|Honda Sensing|openpilot|25 mph|12 mph|[](##)|[](##)|View
- 1 Honda Nidec connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Hyundai|Elantra 2017-19|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[](##)|[](##)|View
- 1 Hyundai B connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[](##)|[](##)|View
- 1 Hyundai K connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here |
|
|Hyundai|Elantra GT 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[](##)|[](##)|View
- 1 Hyundai E connector
- 1 RJ45 cable (7 ft)
- 1 comma power v2
- 1 comma three
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here ||
diff --git a/panda b/panda
index 1a9a94c519..b563405904 160000
--- a/panda
+++ b/panda
@@ -1 +1 @@
-Subproject commit 1a9a94c519cb74e9e0f57bea4d316a54c27ea8aa
+Subproject commit b56340590485bba2428538259e020f176127458c
diff --git a/selfdrive/car/fw_query_definitions.py b/selfdrive/car/fw_query_definitions.py
index aa28a35db4..21458b8287 100755
--- a/selfdrive/car/fw_query_definitions.py
+++ b/selfdrive/car/fw_query_definitions.py
@@ -76,12 +76,12 @@ class FwQueryConfig:
extra_ecus: List[Tuple[capnp.lib.capnp._EnumModule, int, Optional[int]]] = field(default_factory=list)
# Brand-specific fuzzy fingerprinting config options:
- # A function to get uniquely identifiable codes for a set of versions
+ # A function to get unique, platform-specific identification codes for a set of versions
fuzzy_get_platform_codes: Optional[Callable[[List[bytes]], Set[bytes]]] = None
# The minimum number of version matches to fuzzy fingerprint
fuzzy_min_match_count: int = 2
- # List of ECUs to consider for fuzzy fingerprinting, only used with platforms codes
- fuzzy_ecus: List[capnp.lib.capnp._EnumModule] = field(default_factory=list)
+ # List of ECUs expected to have platform codes
+ platform_code_ecus: List[capnp.lib.capnp._EnumModule] = field(default_factory=list)
def __post_init__(self):
for i in range(len(self.requests)):
diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py
index 2c936cf3b6..11eff61b33 100755
--- a/selfdrive/car/honda/interface.py
+++ b/selfdrive/car/honda/interface.py
@@ -292,8 +292,8 @@ class CarInterface(CarInterfaceBase):
# min speed to enable ACC. if car can do stop and go, then set enabling speed
# to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not
# conflict with PCM acc
- stop_and_go = candidate in (HONDA_BOSCH | {CAR.CIVIC}) or ret.enableGasInterceptor
- ret.minEnableSpeed = -1. if stop_and_go else 25.5 * CV.MPH_TO_MS
+ ret.autoResumeSng = candidate in (HONDA_BOSCH | {CAR.CIVIC}) or ret.enableGasInterceptor
+ ret.minEnableSpeed = -1. if ret.autoResumeSng else 25.5 * CV.MPH_TO_MS
# TODO: start from empirically derived lateral slip stiffness for the civic and scale by
# mass and CG position, so all cars will have approximately similar dyn behaviors
diff --git a/selfdrive/car/hyundai/tests/test_hyundai.py b/selfdrive/car/hyundai/tests/test_hyundai.py
index 6254a5878f..27726829e4 100755
--- a/selfdrive/car/hyundai/tests/test_hyundai.py
+++ b/selfdrive/car/hyundai/tests/test_hyundai.py
@@ -6,7 +6,7 @@ from cereal import car
from selfdrive.car.tests.test_fw_fingerprint import TestFwFingerprintBase
from selfdrive.car.fw_versions import match_fw_to_car
from selfdrive.car.hyundai.values import CAMERA_SCC_CAR, CANFD_CAR, CAN_GEARS, CAR, CHECKSUM, FW_QUERY_CONFIG, \
- FW_VERSIONS, LEGACY_SAFETY_MODE_CAR, PLATFORM_CODE_PATTERN
+ FW_VERSIONS, LEGACY_SAFETY_MODE_CAR
Ecu = car.CarParams.Ecu
ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()}
@@ -28,36 +28,38 @@ class TestHyundaiFingerprint(TestFwFingerprintBase):
ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_not_in_whitelist])
self.assertEqual(len(ecus_not_in_whitelist), 0, f'{car_model}: Car model has ECUs not in auxiliary request whitelists: {ecu_strings}')
- def test_fuzzy_ecus_available(self):
+ def test_platform_code_ecus_available(self):
+ no_eps_platforms = CANFD_CAR | {CAR.KIA_SORENTO, CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL,
+ CAR.SONATA_LF, CAR.TUCSON, CAR.GENESIS_G90, CAR.GENESIS_G80}
+
# Asserts ECU keys essential for fuzzy fingerprinting are available on all platforms
for car_model, ecus in FW_VERSIONS.items():
with self.subTest(car_model=car_model):
- for fuzzy_ecu in FW_QUERY_CONFIG.fuzzy_ecus:
- if car_model == CAR.HYUNDAI_GENESIS:
- raise unittest.SkipTest
+ for fuzzy_ecu in FW_QUERY_CONFIG.platform_code_ecus:
+ if fuzzy_ecu in (Ecu.fwdRadar, Ecu.eps) and car_model == CAR.HYUNDAI_GENESIS:
+ continue
+ if fuzzy_ecu == Ecu.eps and car_model in no_eps_platforms:
+ continue
self.assertIn(fuzzy_ecu, [e[0] for e in ecus])
def test_fuzzy_fw_dates(self):
# Some newer platforms have date codes in a different format we don't yet parse,
- # for now assert date format is consistent across each platform
+ # for now assert date format is consistent for all FW across each platform
for car_model, ecus in FW_VERSIONS.items():
with self.subTest(car_model=car_model):
for ecu, fws in ecus.items():
- if ecu[0] in FW_QUERY_CONFIG.fuzzy_ecus:
- dates = set()
- for fw in fws:
- # TODO: use FW_QUERY_CONFIG.fuzzy_get_platform_codes
- _, date = PLATFORM_CODE_PATTERN.search(fw).groups()
- dates.add(date)
- if date is not None:
- # Assert date is parsable and reasonable
- parsed = datetime.strptime(date.decode()[:4], '%y%m')
- self.assertTrue(2013 < parsed.year < 2023, parsed)
-
- # Either no dates should exist or all dates should be parsed
- self.assertEqual(len({d is None for d in dates}), 1)
+ if ecu[0] not in FW_QUERY_CONFIG.platform_code_ecus:
+ continue
+
+ codes = set()
+ for fw in fws:
+ codes |= FW_QUERY_CONFIG.fuzzy_get_platform_codes([fw])
+
+ # Either no dates should be parsed or all dates should be parsed
+ self.assertEqual(len({b'-' in code for code in codes}), 1)
def test_fuzzy_platform_codes(self):
+ # Asserts basic platform code parsing behavior
codes = FW_QUERY_CONFIG.fuzzy_get_platform_codes([b'\xf1\x00DH LKAS 1.1 -150210'])
self.assertEqual(codes, {b"DH-1502"})
diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py
index ef662d6e82..dda327804b 100644
--- a/selfdrive/car/hyundai/values.py
+++ b/selfdrive/car/hyundai/values.py
@@ -451,8 +451,8 @@ FW_QUERY_CONFIG = FwQueryConfig(
],
# Custom fuzzy fingerprinting config using platform codes + FW dates:
fuzzy_get_platform_codes=get_platform_codes,
- # Hyundai works best with camera and radar (which have standardized platform codes)
- fuzzy_ecus=[Ecu.fwdRadar, Ecu.fwdCamera],
+ # Camera and radar should exist on all cars
+ platform_code_ecus=[Ecu.fwdRadar, Ecu.fwdCamera, Ecu.eps],
)
FW_VERSIONS = {
diff --git a/selfdrive/car/tests/test_docs.py b/selfdrive/car/tests/test_docs.py
index f42c094856..7ea9f6c9fe 100755
--- a/selfdrive/car/tests/test_docs.py
+++ b/selfdrive/car/tests/test_docs.py
@@ -1,12 +1,16 @@
#!/usr/bin/env python3
from collections import defaultdict
+import os
import re
import unittest
+from common.basedir import BASEDIR
from selfdrive.car.car_helpers import interfaces, get_interface_attr
from selfdrive.car.docs import CARS_MD_OUT, CARS_MD_TEMPLATE, generate_cars_md, get_all_car_info
from selfdrive.car.docs_definitions import Cable, Column, PartType, Star
from selfdrive.car.honda.values import CAR as HONDA
+from selfdrive.debug.dump_car_info import dump_car_info
+from selfdrive.debug.print_docs_diff import print_car_info_diff
class TestCarDocs(unittest.TestCase):
@@ -22,6 +26,12 @@ class TestCarDocs(unittest.TestCase):
self.assertEqual(generated_cars_md, current_cars_md,
"Run selfdrive/car/docs.py to update the compatibility documentation")
+ def test_docs_diff(self):
+ dump_path = os.path.join(BASEDIR, "selfdrive", "car", "tests", "cars_dump")
+ dump_car_info(dump_path)
+ print_car_info_diff(dump_path)
+ os.remove(dump_path)
+
def test_duplicate_years(self):
make_model_years = defaultdict(list)
for car in self.all_cars:
diff --git a/selfdrive/car/tests/test_fw_fingerprint.py b/selfdrive/car/tests/test_fw_fingerprint.py
index 7462451b9b..f5e2713368 100755
--- a/selfdrive/car/tests/test_fw_fingerprint.py
+++ b/selfdrive/car/tests/test_fw_fingerprint.py
@@ -131,19 +131,19 @@ class TestFwFingerprint(TestFwFingerprintBase):
for brand, config in FW_QUERY_CONFIGS.items():
with self.subTest(brand=brand):
if config.fuzzy_get_platform_codes is None:
- self.assertEqual(len(config.fuzzy_ecus), 0, "Cannot specify fuzzy ECUs without full config")
+ self.assertEqual(len(config.platform_code_ecus), 0, "Cannot specify platform code ECUs without full config")
self.assertEqual(config.fuzzy_min_match_count, 2, "Cannot override minimum match count without full config")
else:
- self.assertGreater(len(config.fuzzy_ecus), 0, "Need to specify fuzzy ECUs")
- self.assertEqual(config.fuzzy_min_match_count, len(config.fuzzy_ecus),
+ self.assertGreater(len(config.platform_code_ecus), 0, "Need to specify platform code ECUs")
+ self.assertEqual(config.fuzzy_min_match_count, len(config.platform_code_ecus),
"Fuzzy ECU match count must equal number of fuzzy ECUs")
# Assert every supported ECU FW version returns one platform code
for fw_by_addr in VERSIONS[brand].values():
for addr, fws in fw_by_addr.items():
- if addr[0] in config.fuzzy_ecus:
+ if addr[0] in config.platform_code_ecus:
for f in fws:
- self.assertEqual(1, len(config.fuzzy_get_platform_codes([f])))
+ self.assertEqual(1, len(config.fuzzy_get_platform_codes([f])), f"Unable to parse FW: {f}")
def test_fw_request_ecu_whitelist(self):
for brand, config in FW_QUERY_CONFIGS.items():
diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py
index 3903340c8d..82c66a20f9 100755
--- a/selfdrive/controls/controlsd.py
+++ b/selfdrive/controls/controlsd.py
@@ -170,6 +170,7 @@ class Controls:
self.events_prev = []
self.current_alert_types = [ET.PERMANENT]
self.logged_comm_issue = None
+ self.not_running_prev = None
self.last_actuators = car.CarControl.Actuators.new_message()
self.steer_limited = False
self.desired_curvature = 0.0
@@ -330,6 +331,9 @@ class Controls:
not_running = {p.name for p in self.sm['managerState'].processes if not p.running and p.shouldBeRunning}
if self.sm.rcv_frame['managerState'] and (not_running - IGNORE_PROCESSES):
self.events.add(EventName.processNotRunning)
+ if not_running != self.not_running_prev:
+ cloudlog.event("process_not_running", not_running=not_running, error=True)
+ self.not_running_prev = not_running
else:
if not SIMULATION and not self.rk.lagging:
if not self.sm.all_alive(self.camera_packets):
diff --git a/selfdrive/test/process_replay/migration.py b/selfdrive/test/process_replay/migration.py
new file mode 100644
index 0000000000..31b3acde56
--- /dev/null
+++ b/selfdrive/test/process_replay/migration.py
@@ -0,0 +1,65 @@
+from cereal import messaging
+
+
+def migrate_all(lr, old_logtime=False):
+ msgs = migrate_sensorEvents(lr, old_logtime)
+ msgs = migrate_carParams(msgs, old_logtime)
+
+ return msgs
+
+
+def migrate_carParams(lr, old_logtime=False):
+ all_msgs = []
+ for msg in lr:
+ if msg.which() == 'carParams':
+ CP = messaging.new_message('carParams')
+ CP.carParams = msg.carParams.as_builder()
+ for car_fw in CP.carParams.carFw:
+ car_fw.brand = CP.carParams.carName
+ if old_logtime:
+ CP.logMonoTime = msg.logMonoTime
+ msg = CP.as_reader()
+ all_msgs.append(msg)
+
+ return all_msgs
+
+
+def migrate_sensorEvents(lr, old_logtime=False):
+ all_msgs = []
+ for msg in lr:
+ if msg.which() != 'sensorEventsDEPRECATED':
+ all_msgs.append(msg)
+ continue
+
+ # migrate to split sensor events
+ for evt in msg.sensorEventsDEPRECATED:
+ # build new message for each sensor type
+ sensor_service = ''
+ if evt.which() == 'acceleration':
+ sensor_service = 'accelerometer'
+ elif evt.which() == 'gyro' or evt.which() == 'gyroUncalibrated':
+ sensor_service = 'gyroscope'
+ elif evt.which() == 'light' or evt.which() == 'proximity':
+ sensor_service = 'lightSensor'
+ elif evt.which() == 'magnetic' or evt.which() == 'magneticUncalibrated':
+ sensor_service = 'magnetometer'
+ elif evt.which() == 'temperature':
+ sensor_service = 'temperatureSensor'
+
+ m = messaging.new_message(sensor_service)
+ m.valid = True
+ if old_logtime:
+ m.logMonoTime = msg.logMonoTime
+
+ m_dat = getattr(m, sensor_service)
+ m_dat.version = evt.version
+ m_dat.sensor = evt.sensor
+ m_dat.type = evt.type
+ m_dat.source = evt.source
+ if old_logtime:
+ m_dat.timestamp = evt.timestamp
+ setattr(m_dat, evt.which(), getattr(evt, evt.which()))
+
+ all_msgs.append(m.as_reader())
+
+ return all_msgs
diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py
index 9261aee838..22d1516373 100755
--- a/selfdrive/test/process_replay/process_replay.py
+++ b/selfdrive/test/process_replay/process_replay.py
@@ -18,6 +18,7 @@ from panda.python import ALTERNATIVE_EXPERIENCE
from selfdrive.car.car_helpers import get_car, interfaces
from selfdrive.manager.process_config import managed_processes
from selfdrive.test.process_replay.helpers import OpenpilotPrefix
+from selfdrive.test.process_replay.migration import migrate_all
# Numpy gives different results based on CPU features after version 19
NUMPY_TOLERANCE = 1e-7
@@ -342,7 +343,7 @@ def replay_process_with_name(name, lr, *args, **kwargs):
def replay_process(cfg, lr, fingerprint=None, return_all_logs=False, disable_progress=False):
- all_msgs = list(lr)
+ all_msgs = migrate_all(lr, old_logtime=True)
process_logs = _replay_single_process(cfg, all_msgs, fingerprint, disable_progress)
if return_all_logs:
diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit
index 2332054b69..f3a9408671 100644
--- a/selfdrive/test/process_replay/ref_commit
+++ b/selfdrive/test/process_replay/ref_commit
@@ -1 +1 @@
-3e684aef4483b8d311d71bab3bb543d7bad26563
+67bcd498f0432252a3f11a9fd2b59b344ee214ba
diff --git a/selfdrive/test/process_replay/regen.py b/selfdrive/test/process_replay/regen.py
index cc697bb9bf..18c7e3a8dc 100755
--- a/selfdrive/test/process_replay/regen.py
+++ b/selfdrive/test/process_replay/regen.py
@@ -20,6 +20,7 @@ from selfdrive.car.toyota.values import EPS_SCALE
from selfdrive.manager.process import ensure_running
from selfdrive.manager.process_config import managed_processes
from selfdrive.test.process_replay.process_replay import CONFIGS, FAKEDATA, setup_env, check_openpilot_enabled
+from selfdrive.test.process_replay.migration import migrate_all
from selfdrive.test.update_ci_routes import upload_route
from tools.lib.route import Route
from tools.lib.framereader import FrameReader
@@ -179,67 +180,11 @@ def replay_cameras(lr, frs, disable_tqdm=False):
return vs, p
-def migrate_carparams(lr):
- all_msgs = []
- for msg in lr:
- if msg.which() == 'carParams':
- CP = messaging.new_message('carParams')
- CP.carParams = msg.carParams.as_builder()
- for car_fw in CP.carParams.carFw:
- car_fw.brand = CP.carParams.carName
- msg = CP.as_reader()
- all_msgs.append(msg)
-
- return all_msgs
-
-
-def migrate_sensorEvents(lr, old_logtime=False):
- all_msgs = []
- for msg in lr:
- if msg.which() != 'sensorEventsDEPRECATED':
- all_msgs.append(msg)
- continue
-
- # migrate to split sensor events
- for evt in msg.sensorEventsDEPRECATED:
- # build new message for each sensor type
- sensor_service = ''
- if evt.which() == 'acceleration':
- sensor_service = 'accelerometer'
- elif evt.which() == 'gyro' or evt.which() == 'gyroUncalibrated':
- sensor_service = 'gyroscope'
- elif evt.which() == 'light' or evt.which() == 'proximity':
- sensor_service = 'lightSensor'
- elif evt.which() == 'magnetic' or evt.which() == 'magneticUncalibrated':
- sensor_service = 'magnetometer'
- elif evt.which() == 'temperature':
- sensor_service = 'temperatureSensor'
-
- m = messaging.new_message(sensor_service)
- m.valid = True
- if old_logtime:
- m.logMonoTime = msg.logMonoTime
-
- m_dat = getattr(m, sensor_service)
- m_dat.version = evt.version
- m_dat.sensor = evt.sensor
- m_dat.type = evt.type
- m_dat.source = evt.source
- if old_logtime:
- m_dat.timestamp = evt.timestamp
- setattr(m_dat, evt.which(), getattr(evt, evt.which()))
-
- all_msgs.append(m.as_reader())
-
- return all_msgs
-
-
def regen_segment(lr, frs=None, daemons="all", outdir=FAKEDATA, disable_tqdm=False):
if not isinstance(daemons, str) and not hasattr(daemons, "__iter__"):
raise ValueError("whitelist_proc must be a string or iterable")
- lr = migrate_carparams(list(lr))
- lr = migrate_sensorEvents(list(lr))
+ lr = migrate_all(lr)
if frs is None:
frs = dict()
diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py
index 57387e5186..aa78978619 100755
--- a/selfdrive/thermald/thermald.py
+++ b/selfdrive/thermald/thermald.py
@@ -41,7 +41,7 @@ HardwareState = namedtuple("HardwareState", ['network_type', 'network_info', 'ne
THERMAL_BANDS = OrderedDict({
ThermalStatus.green: ThermalBand(None, 80.0),
ThermalStatus.yellow: ThermalBand(75.0, 96.0),
- ThermalStatus.red: ThermalBand(80.0, 107.),
+ ThermalStatus.red: ThermalBand(88.0, 107.),
ThermalStatus.danger: ThermalBand(94.0, None),
})
diff --git a/selfdrive/ui/qt/maps/map_settings.cc b/selfdrive/ui/qt/maps/map_settings.cc
index 3205ca517d..f626925ad4 100644
--- a/selfdrive/ui/qt/maps/map_settings.cc
+++ b/selfdrive/ui/qt/maps/map_settings.cc
@@ -13,46 +13,46 @@ static QString shorten(const QString &str, int max_len) {
}
MapPanel::MapPanel(QWidget* parent) : QWidget(parent) {
- stack = new QStackedWidget;
+ QStackedLayout *stack = new QStackedLayout(this);
- QWidget * main_widget = new QWidget;
+ QWidget *main_widget = new QWidget;
QVBoxLayout *main_layout = new QVBoxLayout(main_widget);
- const int icon_size = 200;
-
- // Home
- QHBoxLayout *home_layout = new QHBoxLayout;
- home_button = new QPushButton;
- home_button->setIconSize(QSize(icon_size, icon_size));
- home_layout->addWidget(home_button);
-
- home_address = new QLabel;
- home_address->setWordWrap(true);
- home_layout->addSpacing(30);
- home_layout->addWidget(home_address);
- home_layout->addStretch();
-
- // Work
- QHBoxLayout *work_layout = new QHBoxLayout;
- work_button = new QPushButton;
- work_button->setIconSize(QSize(icon_size, icon_size));
- work_layout->addWidget(work_button);
-
- work_address = new QLabel;
- work_address->setWordWrap(true);
- work_layout->addSpacing(30);
- work_layout->addWidget(work_address);
- work_layout->addStretch();
+ main_layout->setSpacing(20);
// Home & Work layout
QHBoxLayout *home_work_layout = new QHBoxLayout;
- home_work_layout->addLayout(home_layout, 1);
- home_work_layout->addSpacing(50);
- home_work_layout->addLayout(work_layout, 1);
+ {
+ // Home
+ home_button = new QPushButton;
+ home_button->setIconSize(QSize(MAP_PANEL_ICON_SIZE, MAP_PANEL_ICON_SIZE));
+ home_address = new QLabel;
+ home_address->setWordWrap(true);
+
+ QHBoxLayout *home_layout = new QHBoxLayout;
+ home_layout->addWidget(home_button);
+ home_layout->addSpacing(30);
+ home_layout->addWidget(home_address);
+ home_layout->addStretch();
+
+ // Work
+ work_button = new QPushButton;
+ work_button->setIconSize(QSize(MAP_PANEL_ICON_SIZE, MAP_PANEL_ICON_SIZE));
+ work_address = new QLabel;
+ work_address->setWordWrap(true);
+
+ QHBoxLayout *work_layout = new QHBoxLayout;
+ work_layout->addWidget(work_button);
+ work_layout->addSpacing(30);
+ work_layout->addWidget(work_address);
+ work_layout->addStretch();
+
+ home_work_layout->addLayout(home_layout, 1);
+ home_work_layout->addSpacing(50);
+ home_work_layout->addLayout(work_layout, 1);
+ }
main_layout->addLayout(home_work_layout);
- main_layout->addSpacing(20);
main_layout->addWidget(horizontal_line());
- main_layout->addSpacing(20);
// Current route
{
@@ -81,7 +81,6 @@ MapPanel::MapPanel(QWidget* parent) : QWidget(parent) {
QLabel *recents_title = new QLabel(tr("Recent Destinations"));
recents_title->setStyleSheet("font-size: 55px");
main_layout->addWidget(recents_title);
- main_layout->addSpacing(20);
recent_layout = new QVBoxLayout;
QWidget *recent_widget = new LayoutWidget(recent_layout, this);
@@ -119,9 +118,6 @@ MapPanel::MapPanel(QWidget* parent) : QWidget(parent) {
stack->setCurrentIndex(prime_type ? 0 : 1);
});
- QVBoxLayout *wrapper = new QVBoxLayout(this);
- wrapper->addWidget(stack);
-
clear();
@@ -207,8 +203,9 @@ void MapPanel::refresh() {
prev_destinations = cur_destinations;
clear();
+ // add favorites before recents
bool has_recents = false;
- for (auto &save_type: {"favorite", "recent"}) {
+ for (auto &save_type: {NAV_TYPE_FAVORITE, NAV_TYPE_RECENT}) {
for (auto location : doc.array()) {
auto obj = location.toObject();
@@ -219,7 +216,7 @@ void MapPanel::refresh() {
if (type != save_type) continue;
- if (type == "favorite" && label == "home") {
+ if (type == NAV_TYPE_FAVORITE && label == NAV_FAVORITE_LABEL_HOME) {
home_address->setText(name);
home_address->setStyleSheet(R"(font-size: 50px; color: white;)");
home_button->setIcon(QPixmap("../assets/navigation/home.png"));
@@ -227,7 +224,7 @@ void MapPanel::refresh() {
navigateTo(obj);
emit closeSettings();
});
- } else if (type == "favorite" && label == "work") {
+ } else if (type == NAV_TYPE_FAVORITE && label == NAV_FAVORITE_LABEL_WORK) {
work_address->setText(name);
work_address->setStyleSheet(R"(font-size: 50px; color: white;)");
work_button->setIcon(QPixmap("../assets/navigation/work.png"));
@@ -245,7 +242,7 @@ void MapPanel::refresh() {
sp.setRetainSizeWhenHidden(true);
star->setSizePolicy(sp);
- star->setVisible(type == "favorite");
+ star->setVisible(type == NAV_TYPE_FAVORITE);
star->setStyleSheet(R"(font-size: 60px;)");
layout->addWidget(star);
layout->addSpacing(10);
@@ -284,7 +281,6 @@ void MapPanel::refresh() {
has_recents = true;
}
}
-
}
if (!has_recents) {
diff --git a/selfdrive/ui/qt/maps/map_settings.h b/selfdrive/ui/qt/maps/map_settings.h
index 165673b7c1..8dd044c374 100644
--- a/selfdrive/ui/qt/maps/map_settings.h
+++ b/selfdrive/ui/qt/maps/map_settings.h
@@ -11,6 +11,14 @@
#include "common/params.h"
#include "selfdrive/ui/qt/widgets/controls.h"
+const int MAP_PANEL_ICON_SIZE = 200;
+
+const QString NAV_TYPE_FAVORITE = "favorite";
+const QString NAV_TYPE_RECENT = "recent";
+
+const QString NAV_FAVORITE_LABEL_HOME = "home";
+const QString NAV_FAVORITE_LABEL_WORK = "work";
+
class MapPanel : public QWidget {
Q_OBJECT
public:
@@ -27,7 +35,6 @@ private:
Params params;
QString prev_destinations, cur_destinations;
- QStackedWidget *stack;
QPushButton *home_button, *work_button;
QLabel *home_address, *work_address;
QVBoxLayout *recent_layout;
diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts
index b751e9cf57..1936805aa5 100644
--- a/selfdrive/ui/translations/main_ko.ts
+++ b/selfdrive/ui/translations/main_ko.ts
@@ -1053,23 +1053,23 @@ This may take up to a minute.
Aggressive
-
+ 공격적
Standard
-
+ 표준
Relaxed
-
+ 편안한
Driving Personality
-
+ 주행 모드
Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars.
-
+ 표준 모드를 권장합니다. 공격적 모드에서는 openpilot은 앞차를 더 가까이 따라가며 가속과 감속을 더 공격적으로 사용합니다. 편안한 모드에서 openpilot은 선두 차량에서 더 멀리 떨어져 있습니다.
diff --git a/system/hardware/tici/tests/test_amplifier.py b/system/hardware/tici/tests/test_amplifier.py
index 5d5a86c512..4cacef4080 100755
--- a/system/hardware/tici/tests/test_amplifier.py
+++ b/system/hardware/tici/tests/test_amplifier.py
@@ -21,6 +21,7 @@ class TestAmplifier(unittest.TestCase):
# clear dmesg
subprocess.check_call("sudo dmesg -C", shell=True)
+ Panda.wait_for_panda(None, 30)
self.panda = Panda()
self.panda.reset()
diff --git a/tools/cabana/mainwin.cc b/tools/cabana/mainwin.cc
index 3ae26106cf..f424a3eecf 100644
--- a/tools/cabana/mainwin.cc
+++ b/tools/cabana/mainwin.cc
@@ -77,6 +77,7 @@ MainWindow::MainWindow() : QMainWindow() {
}
void MainWindow::createActions() {
+ // File menu
QMenu *file_menu = menuBar()->addMenu(tr("&File"));
file_menu->addAction(tr("Open Stream..."), this, &MainWindow::openStream);
close_stream_act = file_menu->addAction(tr("Close stream"), this, &MainWindow::closeStream);
@@ -124,6 +125,7 @@ void MainWindow::createActions() {
file_menu->addSeparator();
file_menu->addAction(tr("E&xit"), qApp, &QApplication::closeAllWindows)->setShortcuts(QKeySequence::Quit);
+ // Edit Menu
QMenu *edit_menu = menuBar()->addMenu(tr("&Edit"));
auto undo_act = UndoStack::instance()->createUndoAction(this, tr("&Undo"));
undo_act->setShortcuts(QKeySequence::Undo);
@@ -138,14 +140,22 @@ void MainWindow::createActions() {
commands_act->setDefaultWidget(new QUndoView(UndoStack::instance()));
commands_menu->addAction(commands_act);
- edit_menu->addSeparator();
- edit_menu->addAction(tr("Reset Window Layout"),
- [this]() { restoreState(default_state); });
-
+ // View Menu
+ QMenu *view_menu = menuBar()->addMenu(tr("&View"));
+ auto act = view_menu->addAction(tr("Full Screen"), this, &MainWindow::toggleFullScreen, QKeySequence::FullScreen);
+ addAction(act);
+ view_menu->addSeparator();
+ view_menu->addAction(messages_dock->toggleViewAction());
+ view_menu->addAction(video_dock->toggleViewAction());
+ view_menu->addSeparator();
+ view_menu->addAction(tr("Reset Window Layout"), [this]() { restoreState(default_state); });
+
+ // Tools Menu
tools_menu = menuBar()->addMenu(tr("&Tools"));
tools_menu->addAction(tr("Find &Similar Bits"), this, &MainWindow::findSimilarBits);
tools_menu->addAction(tr("&Find Signal"), this, &MainWindow::findSignal);
+ // Help Menu
QMenu *help_menu = menuBar()->addMenu(tr("&Help"));
help_menu->addAction(tr("Help"), this, &MainWindow::onlineHelp)->setShortcuts(QKeySequence::HelpContents);
help_menu->addAction(tr("About &Qt"), qApp, &QApplication::aboutQt);
@@ -155,13 +165,13 @@ void MainWindow::createDockWindows() {
messages_dock = new QDockWidget(tr("MESSAGES"), this);
messages_dock->setObjectName("MessagesPanel");
messages_dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea | Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
- messages_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
+ messages_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable);
addDockWidget(Qt::LeftDockWidgetArea, messages_dock);
video_dock = new QDockWidget("", this);
video_dock->setObjectName(tr("VideoPanel"));
video_dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
- video_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
+ video_dock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable);
addDockWidget(Qt::RightDockWidgetArea, video_dock);
}
@@ -206,8 +216,6 @@ void MainWindow::createStatusBar() {
void MainWindow::createShortcuts() {
auto shortcut = new QShortcut(QKeySequence(Qt::Key_Space), this, nullptr, nullptr, Qt::ApplicationShortcut);
QObject::connect(shortcut, &QShortcut::activated, []() { can->pause(!can->isPaused()); });
- shortcut = new QShortcut(QKeySequence(QKeySequence::FullScreen), this, nullptr, nullptr, Qt::ApplicationShortcut);
- QObject::connect(shortcut, &QShortcut::activated, this, &MainWindow::toggleFullScreen);
// TODO: add more shortcuts here.
}
diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc
index 3fda5796d4..46dfef1004 100644
--- a/tools/cabana/signalview.cc
+++ b/tools/cabana/signalview.cc
@@ -331,7 +331,7 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
if (item && item->type == SignalModel::Item::Sig) {
painter->setRenderHint(QPainter::Antialiasing);
if (option.state & QStyle::State_Selected) {
- painter->fillRect(option.rect, option.palette.highlight());
+ painter->fillRect(option.rect, option.palette.brush(QPalette::Normal, QPalette::Highlight));
}
int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1;
diff --git a/tools/cabana/util.cc b/tools/cabana/util.cc
index b0bba891db..7a606b133e 100644
--- a/tools/cabana/util.cc
+++ b/tools/cabana/util.cc
@@ -96,7 +96,7 @@ void MessageBytesDelegate::paint(QPainter *painter, const QStyleOptionViewItem &
int v_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameVMargin);
int h_margin = option.widget->style()->pixelMetric(QStyle::PM_FocusFrameHMargin);
if (option.state & QStyle::State_Selected) {
- painter->fillRect(option.rect, option.palette.highlight());
+ painter->fillRect(option.rect, option.palette.brush(QPalette::Normal, QPalette::Highlight));
}
const QPoint pt{option.rect.left() + h_margin, option.rect.top() + v_margin};
diff --git a/tools/ssh/README.md b/tools/ssh/README.md
index 67b5271a42..588ea71579 100644
--- a/tools/ssh/README.md
+++ b/tools/ssh/README.md
@@ -24,14 +24,12 @@ The `id_rsa` key in this directory only works while your device is in the setup
See the [community wiki](https://github.com/commaai/openpilot/wiki/SSH) for more detailed instructions and information.
# Connecting to ssh.comma.ai
-SSH into your comma device from anywhere with `ssh.comma.ai`.
+SSH into your comma device from anywhere with `ssh.comma.ai`. Requires a [comma prime subscription](https://comma.ai/connect).
## Setup
With software version 0.6.1 or newer, enter your GitHub username on your device under Developer Settings. Your GitHub authorized public keys will become your authorized SSH keys for `ssh.comma.ai`. You can add any additional keys in `/system/comma/home/.ssh/authorized_keys.persist`.
-Requires [comma SIM with comma prime](https://comma.ai/shop) activated with comma connect, available on iOS and Android. comma two and EON ship with a pre-inserted comma SIM.
-
## Recommended .ssh/config
With the below SSH configuration, you can type `ssh comma-{dongleid}` to connect to your device through `ssh.comma.ai`.