def get_present_ecus(logcan, sendcan): queries = list() parallel_queries = list() responses = set() versions = get_interface_attr('FW_VERSIONS', ignore_none=True) for r in REQUESTS: if r.brand not in versions: continue for brand_versions in versions[r.brand].values(): for ecu_type, addr, sub_addr in brand_versions: # Only query ecus in whitelist if whitelist is not empty if len(r.whitelist_ecus) == 0 or ecu_type in r.whitelist_ecus: a = (addr, sub_addr, r.bus) # Build set of queries if sub_addr is None: if a not in parallel_queries: parallel_queries.append(a) else: # subaddresses must be queried one by one if [a] not in queries: queries.append([a]) # Build set of expected responses to filter response_addr = uds.get_rx_addr_for_tx_addr( addr, r.rx_offset) responses.add((response_addr, sub_addr, r.bus)) queries.insert(0, parallel_queries) ecu_responses: Set[Tuple[int, Optional[int], int]] = set() for query in queries: ecu_responses.update( get_ecu_addrs(logcan, sendcan, set(query), responses, timeout=0.1)) return ecu_responses
def get_fw_versions(logcan, sendcan, extra=None, timeout=0.1, debug=False, progress=False): ecu_types = {} # Extract ECU addresses to query from fingerprints # ECUs using a subaddress need be queried one by one, the rest can be done in parallel addrs = [] parallel_addrs = [] versions = get_interface_attr('FW_VERSIONS', ignore_none=True) if extra is not None: versions.update(extra) for brand, brand_versions in versions.items(): for c in brand_versions.values(): for ecu_type, addr, sub_addr in c.keys(): a = (brand, addr, sub_addr) if a not in ecu_types: ecu_types[(addr, sub_addr)] = ecu_type if sub_addr is None: if a not in parallel_addrs: parallel_addrs.append(a) else: if [a] not in addrs: addrs.append([a]) addrs.insert(0, parallel_addrs) fw_versions = {} for i, addr in enumerate(tqdm(addrs, disable=not progress)): for addr_chunk in chunks(addr): for r in REQUESTS: try: addrs = [(a, s) for (b, a, s) in addr_chunk if b in (r.brand, 'any') and (len(r.whitelist_ecus) == 0 or ecu_types[(a, s)] in r.whitelist_ecus)] if addrs: query = IsoTpParallelQuery(sendcan, logcan, r.bus, addrs, r.request, r.response, r.rx_offset, debug=debug) t = 2 * timeout if i == 0 else timeout fw_versions.update({addr: (version, r.request, r.rx_offset) for addr, version in query.get_data(t).items()}) except Exception: cloudlog.warning(f"FW query exception: {traceback.format_exc()}") # Build capnp list to put into CarParams car_fw = [] for addr, (version, request, rx_offset) in fw_versions.items(): f = car.CarParams.CarFw.new_message() f.ecu = ecu_types[addr] f.fwVersion = version f.address = addr[0] f.responseAddress = uds.get_rx_addr_for_tx_addr(addr[0], rx_offset) f.request = request if addr[1] is not None: f.subAddress = addr[1] car_fw.append(f) return car_fw
def get_brand_addrs(): versions = get_interface_attr('FW_VERSIONS', ignore_none=True) brand_addrs = defaultdict(set) for brand, cars in versions.items(): for fw in cars.values(): brand_addrs[brand] |= {(addr, sub_addr) for _, addr, sub_addr in fw.keys()} return brand_addrs
def _get_interface_names() -> Dict[str, List[str]]: # returns a dict of brand name and its respective models brand_names = {} for brand_name, model_names in get_interface_attr("CAR").items(): model_names = [getattr(model_names, c) for c in model_names.__dict__.keys() if not c.startswith("__")] brand_names[brand_name] = model_names return brand_names
def match_fw_to_car(fw_versions, allow_exact=True, allow_fuzzy=True): # Try exact matching first exact_matches = [] if allow_exact: exact_matches = [(True, match_fw_to_car_exact)] if allow_fuzzy: exact_matches.append((False, match_fw_to_car_fuzzy)) brands = get_interface_attr('FW_VERSIONS', ignore_none=True).keys() for exact_match, match_func in exact_matches: # For each brand, attempt to fingerprint using all FW returned from its queries matches = set() for brand in brands: fw_versions_dict = build_fw_dict(fw_versions, filter_brand=brand) matches |= match_func(fw_versions_dict) if len(matches): return exact_match, matches return True, set()
def match_fw_to_car(fw_versions, allow_fuzzy=True): versions = get_interface_attr('FW_VERSIONS', ignore_none=True) # Try exact matching first exact_matches = [True] if allow_fuzzy: exact_matches.append(False) for exact_match in exact_matches: # For each brand, attempt to fingerprint using FW returned from its queries for brand in versions.keys(): fw_versions_dict = build_fw_dict(fw_versions, filter_brand=brand) if exact_match: matches = match_fw_to_car_exact(fw_versions_dict) else: matches = match_fw_to_car_fuzzy(fw_versions_dict) if len(matches) == 1: return exact_match, matches return True, []
def get_fw_versions(logcan, sendcan, query_brand=None, extra=None, timeout=0.1, debug=False, progress=False): versions = get_interface_attr('FW_VERSIONS', ignore_none=True) if query_brand is not None: versions = {query_brand: versions[query_brand]} if extra is not None: versions.update(extra) # Extract ECU addresses to query from fingerprints # ECUs using a subaddress need be queried one by one, the rest can be done in parallel addrs = [] parallel_addrs = [] ecu_types = {} for brand, brand_versions in versions.items(): for c in brand_versions.values(): for ecu_type, addr, sub_addr in c.keys(): a = (brand, addr, sub_addr) if a not in ecu_types: ecu_types[a] = ecu_type if sub_addr is None: if a not in parallel_addrs: parallel_addrs.append(a) else: if [a] not in addrs: addrs.append([a]) addrs.insert(0, parallel_addrs) # Get versions and build capnp list to put into CarParams car_fw = [] requests = [ r for r in REQUESTS if query_brand is None or r.brand == query_brand ] for addr in tqdm(addrs, disable=not progress): for addr_chunk in chunks(addr): for r in requests: try: addrs = [(a, s) for (b, a, s) in addr_chunk if b in (r.brand, 'any') and ( len(r.whitelist_ecus) == 0 or ecu_types[ (b, a, s)] in r.whitelist_ecus)] if addrs: query = IsoTpParallelQuery(sendcan, logcan, r.bus, addrs, r.request, r.response, r.rx_offset, debug=debug) for (addr, rx_addr ), version in query.get_data(timeout).items(): f = car.CarParams.CarFw.new_message() f.ecu = ecu_types.get((r.brand, addr[0], addr[1]), Ecu.unknown) f.fwVersion = version f.address = addr[0] f.responseAddress = rx_addr f.request = r.request f.brand = r.brand f.bus = r.bus if addr[1] is not None: f.subAddress = addr[1] car_fw.append(f) except Exception: cloudlog.warning( f"FW query exception: {traceback.format_exc()}") return car_fw
from selfdrive.car.interfaces import get_interface_attr FW_VERSIONS = get_interface_attr('FW_VERSIONS', combine_brands=True, ignore_none=True) _FINGERPRINTS = get_interface_attr('FINGERPRINTS', combine_brands=True, ignore_none=True) _DEBUG_ADDRESS = {1880: 8} # reserved for debug purposes def is_valid_for_fingerprint(msg, car_fingerprint): adr = msg.address # ignore addresses that are more than 11 bits return (adr in car_fingerprint and car_fingerprint[adr] == len(msg.dat)) or adr >= 0x800 def eliminate_incompatible_cars(msg, candidate_cars): """Removes cars that could not have sent msg. Inputs: msg: A cereal/log CanData message from the car. candidate_cars: A list of cars to consider. Returns: A list containing the subset of candidate_cars that could have sent msg. """ compatible_cars = []
#!/usr/bin/env python3 # type: ignore from collections import defaultdict import argparse import os import traceback from tqdm import tqdm from tools.lib.logreader import LogReader from tools.lib.route import Route from selfdrive.car.interfaces import get_interface_attr from selfdrive.car.car_helpers import interface_names from selfdrive.car.fw_versions import match_fw_to_car NO_API = "NO_API" in os.environ VERSIONS = get_interface_attr('FW_VERSIONS', ignore_none=True) SUPPORTED_BRANDS = VERSIONS.keys() SUPPORTED_CARS = [ brand for brand in SUPPORTED_BRANDS for brand in interface_names[brand] ] UNKNOWN_BRAND = "unknown" try: from xx.pipeline.c.CarState import migration except ImportError: migration = {} if __name__ == "__main__": parser = argparse.ArgumentParser( description='Run FW fingerprint on Qlog of route or list of routes') parser.add_argument('route', help='Route or file with list of routes')