@ -3,7 +3,8 @@ import unittest
from cereal import car
from cereal import car
from selfdrive . car . hyundai . values import CAMERA_SCC_CAR , CANFD_CAR , CAN_GEARS , CAR , CHECKSUM , FW_QUERY_CONFIG , \
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
FW_VERSIONS , LEGACY_SAFETY_MODE_CAR , PART_NUMBER_FW_PATTERN , PLATFORM_CODE_ECUS , \
get_platform_codes
Ecu = car . CarParams . Ecu
Ecu = car . CarParams . Ecu
ECU_NAME = { v : k for k , v in Ecu . schema . enumerants . items ( ) }
ECU_NAME = { v : k for k , v in Ecu . schema . enumerants . items ( ) }
@ -25,21 +26,24 @@ class TestHyundaiFingerprint(unittest.TestCase):
ecu_strings = " , " . join ( [ f ' Ecu. { ECU_NAME [ ecu ] } ' for ecu in ecus_not_in_whitelist ] )
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 } ' )
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 ) :
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 ,
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 }
CAR . SONATA_LF , CAR . TUCSON , CAR . GENESIS_G90 , CAR . GENESIS_G80 }
# Asserts ECU keys essential for fuzzy fingerprinting are available on all platforms
# Asserts ECU keys essential for fuzzy fingerprinting are available on all platforms
for car_model , ecus in FW_VERSIONS . items ( ) :
for car_model , ecus in FW_VERSIONS . items ( ) :
with self . subTest ( car_model = car_model ) :
with self . subTest ( car_model = car_model ) :
for fuzzy_ecu in FW_QUERY_CONFIG . platform_code_ecus :
for platform_code_ecu in PLATFORM_CODE_ECUS :
if fuzzy _ecu in ( Ecu . fwdRadar , Ecu . eps ) and car_model == CAR . HYUNDAI_GENESIS :
if platform_code _ecu in ( Ecu . fwdRadar , Ecu . eps ) and car_model == CAR . HYUNDAI_GENESIS :
continue
continue
if fuzzy _ecu == Ecu . eps and car_model in no_eps_platforms :
if platform_code _ecu == Ecu . eps and car_model in no_eps_platforms :
continue
continue
self . assertIn ( fuzzy _ecu, [ e [ 0 ] for e in ecus ] )
self . assertIn ( platform_code _ecu, [ e [ 0 ] for e in ecus ] )
def test_fw_part_number ( self ) :
def test_fw_part_numbers ( self ) :
# Hyundai places the ECU part number in their FW versions, assert all parsable
# Hyundai places the ECU part number in their FW versions, assert all parsable
# Some examples of valid formats: '56310-L0010', '56310L0010', '56310/M6300'
# Some examples of valid formats: '56310-L0010', '56310L0010', '56310/M6300'
for car_model , ecus in FW_VERSIONS . items ( ) :
for car_model , ecus in FW_VERSIONS . items ( ) :
@ -48,42 +52,50 @@ class TestHyundaiFingerprint(unittest.TestCase):
raise unittest . SkipTest ( " No part numbers for car model " )
raise unittest . SkipTest ( " No part numbers for car model " )
for ecu , fws in ecus . items ( ) :
for ecu , fws in ecus . items ( ) :
if ecu [ 0 ] not in FW_QUERY_CONFIG . platform_code_ecus :
if ecu [ 0 ] not in PLATFORM_CODE_ECUS :
continue
continue
for fw in fws :
for fw in fws :
match = PART_NUMBER_FW_PATTERN . search ( fw )
match = PART_NUMBER_FW_PATTERN . search ( fw )
self . assertIsNotNone ( match , fw )
self . assertIsNotNone ( match , fw )
def test_fuzzy_f w_dates ( self ) :
def test_fw_dates ( self ) :
# Some newer platforms have date codes in a different format we don't yet parse,
# 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
# for now assert date format is consistent for all FW across each platform
for car_model , ecus in FW_VERSIONS . items ( ) :
for car_model , ecus in FW_VERSIONS . items ( ) :
with self . subTest ( car_model = car_model ) :
with self . subTest ( car_model = car_model ) :
for ecu , fws in ecus . items ( ) :
for ecu , fws in ecus . items ( ) :
if ecu [ 0 ] not in FW_QUERY_CONFIG . platform_code_ecus :
if ecu [ 0 ] not in PLATFORM_CODE_ECUS :
continue
continue
codes = set ( )
codes = set ( )
for fw in fws :
for fw in fws :
codes | = FW_QUERY_CONFIG . fuzzy_ get_platform_codes( [ fw ] )
codes | = get_platform_codes ( [ fw ] )
# Either no dates should be parsed or all dates should be parsed
# Either no dates should be parsed or all dates should be parsed
self . assertEqual ( len ( { b ' - ' in code for code in codes } ) , 1 )
self . assertEqual ( len ( { b ' - ' in code for code in codes } ) , 1 )
def test_fuzzy_platform_codes ( self ) :
def test_platform_codes_all_parsable ( self ) :
# Asserts basic platform code parsing behavior
# Assert every supported ECU FW version returns one platform code
codes = FW_QUERY_CONFIG . fuzzy_get_platform_codes ( [ b ' \xf1 \x00 DH LKAS 1.1 -150210 ' ] )
for fw_by_addr in FW_VERSIONS . values ( ) :
for addr , fws in fw_by_addr . items ( ) :
if addr [ 0 ] in PLATFORM_CODE_ECUS :
for f in fws :
self . assertEqual ( 1 , len ( get_platform_codes ( [ f ] ) ) , f " Unable to parse FW: { f } " )
def test_platform_codes_spot_check ( self ) :
# Asserts basic platform code parsing behavior for a few cases
codes = get_platform_codes ( [ b ' \xf1 \x00 DH LKAS 1.1 -150210 ' ] )
self . assertEqual ( codes , { b " DH-1502 " } )
self . assertEqual ( codes , { b " DH-1502 " } )
# Some cameras and all radars do not have dates
# Some cameras and all radars do not have dates
codes = FW_QUERY_CONFIG . fuzzy_get_platform_codes ( [ b ' \xf1 \x00 AEhe SCC H-CUP 1.01 1.01 96400-G2000 ' ] )
codes = get_platform_codes ( [ b ' \xf1 \x00 AEhe SCC H-CUP 1.01 1.01 96400-G2000 ' ] )
self . assertEqual ( codes , { b " AEhe " } )
self . assertEqual ( codes , { b " AEhe " } )
codes = FW_QUERY_CONFIG . fuzzy_get_platform_codes ( [ b ' \xf1 \x00 CV1_ RDR ----- 1.00 1.01 99110-CV000 ' ] )
codes = get_platform_codes ( [ b ' \xf1 \x00 CV1_ RDR ----- 1.00 1.01 99110-CV000 ' ] )
self . assertEqual ( codes , { b " CV1 " } )
self . assertEqual ( codes , { b " CV1 " } )
codes = FW_QUERY_CONFIG . fuzzy_ get_platform_codes( [
codes = get_platform_codes ( [
b ' \xf1 \x00 DH LKAS 1.1 -150210 ' ,
b ' \xf1 \x00 DH LKAS 1.1 -150210 ' ,
b ' \xf1 \x00 AEhe SCC H-CUP 1.01 1.01 96400-G2000 ' ,
b ' \xf1 \x00 AEhe SCC H-CUP 1.01 1.01 96400-G2000 ' ,
b ' \xf1 \x00 CV1_ RDR ----- 1.00 1.01 99110-CV000 ' ,
b ' \xf1 \x00 CV1_ RDR ----- 1.00 1.01 99110-CV000 ' ,
@ -91,7 +103,7 @@ class TestHyundaiFingerprint(unittest.TestCase):
self . assertEqual ( codes , { b " DH-1502 " , b " AEhe " , b " CV1 " } )
self . assertEqual ( codes , { b " DH-1502 " , b " AEhe " , b " CV1 " } )
# Returned platform codes must inclusively contain start/end dates
# Returned platform codes must inclusively contain start/end dates
codes = FW_QUERY_CONFIG . fuzzy_ get_platform_codes( [
codes = get_platform_codes ( [
b ' \xf1 \x00 LX2 MFC AT USA LHD 1.00 1.07 99211-S8100 220222 ' ,
b ' \xf1 \x00 LX2 MFC AT USA LHD 1.00 1.07 99211-S8100 220222 ' ,
b ' \xf1 \x00 LX2 MFC AT USA LHD 1.00 1.08 99211-S8100 211103 ' ,
b ' \xf1 \x00 LX2 MFC AT USA LHD 1.00 1.08 99211-S8100 211103 ' ,
b ' \xf1 \x00 ON MFC AT USA LHD 1.00 1.01 99211-S9100 190405 ' ,
b ' \xf1 \x00 ON MFC AT USA LHD 1.00 1.01 99211-S9100 190405 ' ,