this was the cleanest I could think of, but still working on it. not very easy to understand

pull/26939/head
Shane Smiskol 2 years ago
parent 7a29bad18a
commit 16f490bdcd
  1. 26
      selfdrive/car/fw_versions.py

@ -54,11 +54,13 @@ def get_brand_addrs() -> Dict[str, Set[Tuple[int, Optional[int]]]]:
return dict(brand_addrs)
def match_fw_to_car_fuzzy(fw_versions_dict, config, log=True, exclude=None):
def match_fw_to_car_fuzzy(fw_versions_dict, config=None, log=True, exclude=None):
"""Do a fuzzy FW match. This function will return a match, and the number of firmware version
that were matched uniquely to that specific car. If multiple ECUs uniquely match to different cars
the match is rejected."""
use_config = config is not None and config.fuzzy_get_platform_codes is not None
# Build lookup table from (addr, sub_addr, fw) to list of candidate cars
all_fw_versions = defaultdict(list)
# Platform codes are brand-specific unique identifiers for each platform, less specific than a FW version
@ -77,7 +79,7 @@ def match_fw_to_car_fuzzy(fw_versions_dict, config, log=True, exclude=None):
all_fw_versions[(addr[1], addr[2], f)].append(candidate)
# Add platform codes to lookup dict if config specifies a function
if addr[0] in config.fuzzy_ecus and config.fuzzy_get_platform_codes is not None:
if use_config and addr[0] in config.fuzzy_ecus:
for platform_code in config.fuzzy_get_platform_codes(fws):
all_platform_codes[(addr[1], addr[2], platform_code)].append(candidate)
@ -90,11 +92,11 @@ def match_fw_to_car_fuzzy(fw_versions_dict, config, log=True, exclude=None):
for addr, versions in fw_versions_dict.items():
ecu_key = (addr[0], addr[1])
for version in versions:
# All cars that have this FW response on the specified address
# Fall back to matching with full FW versions if brand does not implement platform codes
candidates = set()
if not use_config:
candidates = all_fw_versions[(*ecu_key, version)]
# If no exact FW matches, try brand-specific fuzzy fingerprinting
if len(candidates) != 1 and config.fuzzy_get_platform_codes is not None:
else:
# Returns one or none, all cars that have this platform code
for platform_code in config.fuzzy_get_platform_codes([version]):
candidates = all_platform_codes[(*ecu_key, platform_code)]
@ -109,7 +111,8 @@ def match_fw_to_car_fuzzy(fw_versions_dict, config, log=True, exclude=None):
# Note that it is possible to match to a candidate without all its ECUs being present
# if there are enough matches. FIXME: parameterize this or require all ECUs to exist like exact matching
if len(matched_ecus) >= config.fuzzy_min_match_count:
fuzzy_min_match_count = config.fuzzy_min_match_count if use_config else 2
if len(matched_ecus) >= fuzzy_min_match_count:
if log:
cloudlog.error(f"Fingerprinted {candidate} using fuzzy match. {len(matched_ecus)} matching ECUs")
return {candidate}
@ -158,14 +161,17 @@ def match_fw_to_car(fw_versions, allow_exact=True, allow_fuzzy=True, log=True):
if allow_exact:
exact_matches = [(True, match_fw_to_car_exact)]
if allow_fuzzy:
exact_matches.append((False, match_fw_to_car_fuzzy))
# Try first with standard fuzzy fingerprinting, then with config
exact_matches.extend([(False, False, match_fw_to_car_fuzzy),
(False, True, match_fw_to_car_fuzzy)])
for exact_match, match_func in exact_matches:
for exact_match, use_config, match_func in exact_matches:
# For each brand, attempt to fingerprint using all FW returned from its queries
matches = set()
for brand in VERSIONS.keys():
fw_versions_dict = build_fw_dict(fw_versions, filter_brand=brand)
matches |= match_func(fw_versions_dict, FW_QUERY_CONFIGS[brand], log=log)
config = FW_QUERY_CONFIGS[brand] if use_config else None
matches |= match_func(fw_versions_dict, config, log=log)
if len(matches):
return exact_match, matches

Loading…
Cancel
Save