openpilot is an open source driver assistance system. openpilot performs the functions of Automated Lane Centering and Adaptive Cruise Control for over 200 supported car makes and models.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

111 lines
5.0 KiB

#!/usr/bin/env python3
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, PART_NUMBER_FW_PATTERN, PLATFORM_CODE_ECUS, \
get_platform_codes
Ecu = car.CarParams.Ecu
ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()}
class TestHyundaiFingerprint(unittest.TestCase):
def test_canfd_not_in_can_features(self):
can_specific_feature_list = set.union(*CAN_GEARS.values(), *CHECKSUM.values(), LEGACY_SAFETY_MODE_CAR, CAMERA_SCC_CAR)
for car_model in CANFD_CAR:
self.assertNotIn(car_model, can_specific_feature_list, "CAN FD car unexpectedly found in a CAN feature list")
def test_auxiliary_request_ecu_whitelist(self):
# Asserts only auxiliary Ecus can exist in database for CAN-FD cars
whitelisted_ecus = {ecu for r in FW_QUERY_CONFIG.requests for ecu in r.whitelist_ecus if r.auxiliary}
for car_model in CANFD_CAR:
ecus = {fw[0] for fw in FW_VERSIONS[car_model].keys()}
ecus_not_in_whitelist = ecus - whitelisted_ecus
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}")
# Tests for platform codes, part numbers, and FW dates which Hyundai will use to fuzzy
# fingerprint in the absence of full FW matches:
def test_platform_code_ecus_available(self):
# TODO: add queries for these non-CAN FD cars to get EPS
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 platform_code_ecu in PLATFORM_CODE_ECUS:
if platform_code_ecu in (Ecu.fwdRadar, Ecu.eps) and car_model == CAR.HYUNDAI_GENESIS:
continue
if platform_code_ecu == Ecu.eps and car_model in no_eps_platforms:
continue
self.assertIn(platform_code_ecu, [e[0] for e in ecus])
def test_fw_format(self):
# Asserts:
# - every supported ECU FW version returns one platform code
# - every supported ECU FW version has a part number
# - expected parsing of ECU FW dates
for car_model, ecus in FW_VERSIONS.items():
with self.subTest(car_model=car_model):
for ecu, fws in ecus.items():
if ecu[0] not in PLATFORM_CODE_ECUS:
continue
codes = set()
for fw in fws:
result = get_platform_codes([fw])
self.assertEqual(1, len(result), f"Unable to parse FW: {fw}")
codes |= result
# Some newer platforms have date codes in a different format we don't yet parse,
# for now assert we can parse all FW or none
self.assertEqual(len({b"-" in code for code in codes}), 1,
"Not all FW dates are parsable")
if car_model == CAR.HYUNDAI_GENESIS:
raise unittest.SkipTest("No part numbers for car model")
# Hyundai places the ECU part number in their FW versions, assert all parsable
# Some examples of valid formats: b"56310-L0010", b"56310L0010", b"56310/M6300"
for fw in fws:
match = PART_NUMBER_FW_PATTERN.search(fw)
self.assertIsNotNone(match, fw)
def test_platform_codes_spot_check(self):
# Asserts basic platform code parsing behavior for a few cases
codes = get_platform_codes([b"\xf1\x00DH LKAS 1.1 -150210"])
self.assertEqual(codes, {b"DH-1502"})
# Some cameras and all radars do not have dates
codes = get_platform_codes([b"\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 "])
self.assertEqual(codes, {b"AEhe"})
codes = get_platform_codes([b"\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 "])
self.assertEqual(codes, {b"CV1"})
codes = get_platform_codes([
b"\xf1\x00DH LKAS 1.1 -150210",
b"\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2000 ",
b"\xf1\x00CV1_ RDR ----- 1.00 1.01 99110-CV000 ",
])
self.assertEqual(codes, {b"DH-1502", b"AEhe", b"CV1"})
# Returned platform codes must inclusively contain start/end dates
codes = get_platform_codes([
b"\xf1\x00LX2 MFC AT USA LHD 1.00 1.07 99211-S8100 220222",
b"\xf1\x00LX2 MFC AT USA LHD 1.00 1.08 99211-S8100 211103",
b"\xf1\x00ON MFC AT USA LHD 1.00 1.01 99211-S9100 190405",
b"\xf1\x00ON MFC AT USA LHD 1.00 1.03 99211-S9100 190720",
])
self.assertEqual(codes, {b"LX2-2111", b"LX2-2112", b"LX2-2201", b"LX2-2202",
b"ON-1904", b"ON-1905", b"ON-1906", b"ON-1907"})
if __name__ == "__main__":
unittest.main()