FPv2: test minimum fuzzy fingerprint ECUs (#28433)

* basic messy test

* draft

* clean up

* clean up

* clean up

* clean up

* never was fuzzy, but be explicit

* switch it up
old-commit-hash: 0acc30d264
beeps
Shane Smiskol 2 years ago committed by GitHub
parent 9feba19670
commit 5cbd015f3a
  1. 13
      selfdrive/car/fw_versions.py
  2. 29
      selfdrive/car/tests/test_fw_fingerprint.py

@ -15,6 +15,7 @@ from system.swaglog import cloudlog
Ecu = car.CarParams.Ecu Ecu = car.CarParams.Ecu
ESSENTIAL_ECUS = [Ecu.engine, Ecu.eps, Ecu.abs, Ecu.fwdRadar, Ecu.fwdCamera, Ecu.vsa] ESSENTIAL_ECUS = [Ecu.engine, Ecu.eps, Ecu.abs, Ecu.fwdRadar, Ecu.fwdCamera, Ecu.vsa]
FUZZY_EXCLUDE_ECUS = [Ecu.fwdCamera, Ecu.fwdRadar, Ecu.eps, Ecu.debug]
FW_QUERY_CONFIGS = get_interface_attr('FW_QUERY_CONFIG', ignore_none=True) FW_QUERY_CONFIGS = get_interface_attr('FW_QUERY_CONFIG', ignore_none=True)
VERSIONS = get_interface_attr('FW_VERSIONS', ignore_none=True) VERSIONS = get_interface_attr('FW_VERSIONS', ignore_none=True)
@ -58,12 +59,6 @@ def match_fw_to_car_fuzzy(fw_versions_dict, log=True, exclude=None):
that were matched uniquely to that specific car. If multiple ECUs uniquely match to different cars that were matched uniquely to that specific car. If multiple ECUs uniquely match to different cars
the match is rejected.""" the match is rejected."""
# These ECUs are known to be shared between models (EPS only between hybrid/ICE version)
# Getting this exactly right isn't crucial, but excluding camera and radar makes it almost
# impossible to get 3 matching versions, even if two models with shared parts are released at the same
# time and only one is in our database.
exclude_types = [Ecu.fwdCamera, Ecu.fwdRadar, Ecu.eps, Ecu.debug]
# Build lookup table from (addr, sub_addr, fw) to list of candidate cars # Build lookup table from (addr, sub_addr, fw) to list of candidate cars
all_fw_versions = defaultdict(list) all_fw_versions = defaultdict(list)
for candidate, fw_by_addr in FW_VERSIONS.items(): for candidate, fw_by_addr in FW_VERSIONS.items():
@ -71,7 +66,11 @@ def match_fw_to_car_fuzzy(fw_versions_dict, log=True, exclude=None):
continue continue
for addr, fws in fw_by_addr.items(): for addr, fws in fw_by_addr.items():
if addr[0] in exclude_types: # These ECUs are known to be shared between models (EPS only between hybrid/ICE version)
# Getting this exactly right isn't crucial, but excluding camera and radar makes it almost
# impossible to get 3 matching versions, even if two models with shared parts are released at the same
# time and only one is in our database.
if addr[0] in FUZZY_EXCLUDE_ECUS:
continue continue
for f in fws: for f in fws:
all_fw_versions[(addr[1], addr[2], f)].append(candidate) all_fw_versions[(addr[1], addr[2], f)].append(candidate)

@ -10,7 +10,7 @@ from cereal import car
from common.params import Params from common.params import Params
from selfdrive.car.car_helpers import interfaces from selfdrive.car.car_helpers import interfaces
from selfdrive.car.fingerprints import FW_VERSIONS from selfdrive.car.fingerprints import FW_VERSIONS
from selfdrive.car.fw_versions import FW_QUERY_CONFIGS, VERSIONS, match_fw_to_car, get_fw_versions from selfdrive.car.fw_versions import FW_QUERY_CONFIGS, FUZZY_EXCLUDE_ECUS, VERSIONS, match_fw_to_car, get_fw_versions
CarFw = car.CarParams.CarFw CarFw = car.CarParams.CarFw
Ecu = car.CarParams.Ecu Ecu = car.CarParams.Ecu
@ -33,7 +33,7 @@ class TestFwFingerprint(unittest.TestCase):
self.assertEqual(candidates[0], expected) self.assertEqual(candidates[0], expected)
@parameterized.expand([(b, c, e[c]) for b, e in VERSIONS.items() for c in e]) @parameterized.expand([(b, c, e[c]) for b, e in VERSIONS.items() for c in e])
def test_fw_fingerprint(self, brand, car_model, ecus): def test_exact_match(self, brand, car_model, ecus):
CP = car.CarParams.new_message() CP = car.CarParams.new_message()
for _ in range(200): for _ in range(200):
fw = [] fw = []
@ -44,9 +44,32 @@ class TestFwFingerprint(unittest.TestCase):
fw.append({"ecu": ecu_name, "fwVersion": random.choice(fw_versions), 'brand': brand, fw.append({"ecu": ecu_name, "fwVersion": random.choice(fw_versions), 'brand': brand,
"address": addr, "subAddress": 0 if sub_addr is None else sub_addr}) "address": addr, "subAddress": 0 if sub_addr is None else sub_addr})
CP.carFw = fw CP.carFw = fw
_, matches = match_fw_to_car(CP.carFw) _, matches = match_fw_to_car(CP.carFw, allow_fuzzy=False)
self.assertFingerprints(matches, car_model) self.assertFingerprints(matches, car_model)
@parameterized.expand([(b, c, e[c]) for b, e in VERSIONS.items() for c in e])
def test_fuzzy_match(self, brand, car_model, ecus):
# TODO: speed up fuzzy matching and test more
CP = car.CarParams.new_message()
for _ in range(5):
fw = []
for ecu, fw_versions in ecus.items():
if not len(fw_versions):
raise unittest.SkipTest("Car model has no FW versions")
ecu_name, addr, sub_addr = ecu
fw.append({"ecu": ecu_name, "fwVersion": random.choice(fw_versions), 'brand': brand,
"address": addr, "subAddress": 0 if sub_addr is None else sub_addr})
CP.carFw = fw
_, matches = match_fw_to_car(CP.carFw, allow_exact=False, log=False)
# Assert no match if there are not enough valid ECUs
valid_ecus = [f['ecu'] for f in fw if f['ecu'] not in FUZZY_EXCLUDE_ECUS]
if len(valid_ecus) < 2:
self.assertEqual(len(matches), 0, valid_ecus)
# There won't always be a match due to shared FW, but if there is it should be correct
elif len(matches):
self.assertFingerprints(matches, car_model)
def test_no_duplicate_fw_versions(self): def test_no_duplicate_fw_versions(self):
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):

Loading…
Cancel
Save