check all possible ecus exist, only platform codes, slightly refactor main loop

pull/26939/head
Shane Smiskol 2 years ago
parent 34c8c05450
commit d3e918fa20
  1. 54
      selfdrive/car/hyundai/values.py

@ -358,66 +358,42 @@ def parse_platform_code(fw_version: bytes) -> Tuple[Optional[bytes], Optional[by
return code, date
def hyundai_fuzzy(fw_versions_dict) -> Set[str]:
"""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."""
# Build lookup table from (addr, sub_addr, fw) to list of candidate cars
all_fw_versions = defaultdict(list)
def hyundai_fuzzy(fw_versions_dict, config, log=True, exclude=None) -> Set[str]:
# Platform codes are brand-specific unique identifiers for each platform, less specific than a FW version
all_platform_codes = defaultdict(list)
for candidate, fw_by_addr in FW_VERSIONS.items():
if candidate == exclude:
continue
for addr, fws in fw_by_addr.items():
# 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] not in FUZZY_EXCLUDE_ECUS:
for f in fws:
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.platform_code_ecus and config.fuzzy_get_platform_codes is not None:
for platform_code in config.fuzzy_get_platform_codes(fws):
if addr[0] in FW_QUERY_CONFIG.platform_code_ecus and FW_QUERY_CONFIG.fuzzy_get_platform_codes is not None:
for platform_code in FW_QUERY_CONFIG.fuzzy_get_platform_codes(fws):
all_platform_codes[(addr[1], addr[2], platform_code)].append(candidate)
matched_ecus = set()
candidate = None
seen_ecus = set()
all_candidates = set()
for addr, versions in fw_versions_dict.items():
ecu_key = (addr[0], addr[1])
seen_ecus.add(ecu_key)
for version in versions:
# All cars that have this FW response on the specified address
candidates = all_fw_versions[(*ecu_key, version)]
# If not one candidate for this ECU and version, try platform codes + dates
if len(candidates) != 1 and config.fuzzy_get_platform_codes is not None:
# All cars that have this platform code on the specified address
candidates = set()
# 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)]
if len(candidates) == 1:
all_candidates |= candidates
matched_ecus.add(ecu_key)
if candidate is None:
candidate = candidates[0]
# We uniquely matched two different cars. No fuzzy match possible
elif candidate != candidates[0]:
return set()
# 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) >= 2:
if log:
cloudlog.error(f"Fingerprinted {candidate} using fuzzy match. {len(matched_ecus)} matching ECUs")
return {candidate}
else:
if len(all_candidates) == 1:
candidate = list(all_candidates)[0]
candidate_ecus = {(addr[1], addr[2]) for addr in FW_VERSIONS[candidate] if
addr[0] in FW_QUERY_CONFIG.platform_code_ecus}
if len(candidate_ecus - seen_ecus) == 0:
return all_candidates
return set()
def get_platform_codes(fw_versions: List[bytes]) -> Set[bytes]:
codes: DefaultDict[bytes, Set[bytes]] = defaultdict(set)
for fw in fw_versions:

Loading…
Cancel
Save