diff --git a/selfdrive/car/hyundai/tests/test_hyundai.py b/selfdrive/car/hyundai/tests/test_hyundai.py index f2e27788a6..8bac256935 100755 --- a/selfdrive/car/hyundai/tests/test_hyundai.py +++ b/selfdrive/car/hyundai/tests/test_hyundai.py @@ -3,7 +3,7 @@ import unittest from cereal import 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 + FW_VERSIONS, LEGACY_SAFETY_MODE_CAR, PART_NUMBER_FW_PATTERN Ecu = car.CarParams.Ecu ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()} @@ -39,6 +39,22 @@ class TestHyundaiFingerprint(unittest.TestCase): continue self.assertIn(fuzzy_ecu, [e[0] for e in ecus]) + def test_fw_part_number(self): + # Hyundai places the ECU part number in their FW versions, assert all parsable + # Some examples of valid formats: '56310-L0010', '56310L0010', '56310/M6300' + for car_model, ecus in FW_VERSIONS.items(): + with self.subTest(car_model=car_model): + if car_model == CAR.HYUNDAI_GENESIS: + raise unittest.SkipTest("No part numbers for car model") + + for ecu, fws in ecus.items(): + if ecu[0] not in FW_QUERY_CONFIG.platform_code_ecus: + continue + + for fw in fws: + match = PART_NUMBER_FW_PATTERN.search(fw) + self.assertIsNotNone(match, fw) + 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 for all FW across each platform diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 6513792f7c..2a15925ebb 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -351,7 +351,7 @@ FINGERPRINTS = { def get_platform_codes(fw_versions: List[bytes]) -> Set[bytes]: codes: DefaultDict[bytes, Set[bytes]] = defaultdict(set) for fw in fw_versions: - match = PLATFORM_CODE_PATTERN.search(fw) + match = PLATFORM_CODE_FW_PATTERN.search(fw) if match is not None: code, date = match.groups() codes[code].add(date) @@ -390,8 +390,10 @@ HYUNDAI_VERSION_REQUEST_MULTI = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER] HYUNDAI_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) -PLATFORM_CODE_PATTERN = re.compile(b'((?<=' + HYUNDAI_VERSION_REQUEST_LONG[1:] + - b')[A-Z]{2}[A-Za-z0-9]{0,2})(?:.*([0-9]{6}))?') +# Regex patterns for parsing platform code, FW date, and part number from FW versions +PLATFORM_CODE_FW_PATTERN = re.compile(b'((?<=' + HYUNDAI_VERSION_REQUEST_LONG[1:] + + b')[A-Z]{2}[A-Za-z0-9]{0,2})(?:.*([0-9]{6}))?') +PART_NUMBER_FW_PATTERN = re.compile(b'(?<=[0-9][.,][0-9]{2} )([0-9]{5}[-/]?[A-Z][A-Z0-9]{3}[0-9])') FW_QUERY_CONFIG = FwQueryConfig( requests=[ @@ -451,6 +453,7 @@ FW_QUERY_CONFIG = FwQueryConfig( ], fuzzy_get_platform_codes=get_platform_codes, # Camera and radar should exist on all cars + # TODO: use abs, it has the platform code and part number on many platforms platform_code_ecus=[Ecu.fwdRadar, Ecu.fwdCamera, Ecu.eps], )