diff --git a/selfdrive/car/hyundai/values.py b/selfdrive/car/hyundai/values.py index 491fb58202..49c68fbd26 100644 --- a/selfdrive/car/hyundai/values.py +++ b/selfdrive/car/hyundai/values.py @@ -358,64 +358,40 @@ 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: - # 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)] + # 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: - return set() + 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]: