def __init__(self, sendcan, logcan, bus, addrs, request, response, response_offset=0x8, functional_addr=False, debug=False, response_pending_timeout=10): self.sendcan = sendcan self.logcan = logcan self.bus = bus self.request = request self.response = response self.debug = debug self.functional_addr = functional_addr self.response_pending_timeout = response_pending_timeout self.real_addrs = [] for a in addrs: if isinstance(a, tuple): self.real_addrs.append(a) else: self.real_addrs.append((a, None)) self.msg_addrs = { tx_addr: get_rx_addr_for_tx_addr(tx_addr[0], rx_offset=response_offset) for tx_addr in self.real_addrs } self.msg_buffer = defaultdict(list)
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_ecu_matches(ecu_rx_addrs): """Returns dictionary of brands and matches with ECUs in their FW versions""" brand_addrs = get_brand_addrs() brand_matches = {r.brand: set() for r in REQUESTS} brand_rx_offsets = set((r.brand, r.rx_offset) for r in REQUESTS) for addr, sub_addr, _ in ecu_rx_addrs: # Since we can't know what request an ecu responded to, add matches for all possible rx offsets for brand, rx_offset in brand_rx_offsets: a = (uds.get_rx_addr_for_tx_addr(addr, -rx_offset), sub_addr) if a in brand_addrs[brand]: brand_matches[brand].add(a) return brand_matches