123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 |
- #!/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')
- parser.add_argument('--car', help='Force comparison fingerprint to known car')
- args = parser.parse_args()
- if os.path.exists(args.route):
- routes = list(open(args.route))
- else:
- routes = [args.route]
- mismatches = defaultdict(list)
- not_fingerprinted = 0
- solved_by_fuzzy = 0
- good_exact = 0
- wrong_fuzzy = 0
- good_fuzzy = 0
- dongles = []
- for route in tqdm(routes):
- route = route.rstrip()
- dongle_id, time = route.split('|')
- if dongle_id in dongles:
- continue
- if NO_API:
- qlog_path = f"cd:/{dongle_id}/{time}/0/qlog.bz2"
- else:
- route = Route(route)
- qlog_path = next((p for p in route.qlog_paths() if p is not None), None)
- if qlog_path is None:
- continue
- try:
- lr = LogReader(qlog_path)
- dongles.append(dongle_id)
- CP = None
- for msg in lr:
- if msg.which() == "pandaStates":
- if msg.pandaStates[0].pandaType in ('unknown', 'whitePanda', 'greyPanda', 'pedal'):
- print("wrong panda type")
- break
- elif msg.which() == "carParams":
- CP = msg.carParams
- car_fw = CP.carFw
- if len(car_fw) == 0:
- print("no fw")
- break
- live_fingerprint = CP.carFingerprint
- live_fingerprint = migration.get(live_fingerprint, live_fingerprint)
- if args.car is not None:
- live_fingerprint = args.car
- if live_fingerprint not in SUPPORTED_CARS:
- print("not in supported cars")
- break
- _, exact_matches = match_fw_to_car(car_fw, allow_exact=True, allow_fuzzy=False)
- _, fuzzy_matches = match_fw_to_car(car_fw, allow_exact=False, allow_fuzzy=True)
- if (len(exact_matches) == 1) and (list(exact_matches)[0] == live_fingerprint):
- good_exact += 1
- print(f"Correct! Live: {live_fingerprint} - Fuzzy: {fuzzy_matches}")
- # Check if fuzzy match was correct
- if len(fuzzy_matches) == 1:
- if list(fuzzy_matches)[0] != live_fingerprint:
- wrong_fuzzy += 1
- print(f"{dongle_id}|{time}")
- print("Fuzzy match wrong! Fuzzy:", fuzzy_matches, "Live:", live_fingerprint)
- else:
- good_fuzzy += 1
- break
- print(f"{dongle_id}|{time}")
- print("Old style:", live_fingerprint, "Vin", CP.carVin)
- print("New style (exact):", exact_matches)
- print("New style (fuzzy):", fuzzy_matches)
- padding = max([len(fw.brand or UNKNOWN_BRAND) for fw in car_fw])
- for version in sorted(car_fw, key=lambda fw: fw.brand):
- subaddr = None if version.subAddress == 0 else hex(version.subAddress)
- print(f" Brand: {version.brand or UNKNOWN_BRAND:{padding}}, bus: {version.bus} - (Ecu.{version.ecu}, {hex(version.address)}, {subaddr}): [{version.fwVersion}],")
- print("Mismatches")
- found = False
- for brand in SUPPORTED_BRANDS:
- car_fws = VERSIONS[brand]
- if live_fingerprint in car_fws:
- found = True
- expected = car_fws[live_fingerprint]
- for (_, expected_addr, expected_sub_addr), v in expected.items():
- for version in car_fw:
- if version.brand != brand and len(version.brand):
- continue
- sub_addr = None if version.subAddress == 0 else version.subAddress
- addr = version.address
- if (addr, sub_addr) == (expected_addr, expected_sub_addr):
- if version.fwVersion not in v:
- print(f"({hex(addr)}, {'None' if sub_addr is None else hex(sub_addr)}) - {version.fwVersion}")
- # Add to global list of mismatches
- mismatch = (addr, sub_addr, version.fwVersion)
- if mismatch not in mismatches[live_fingerprint]:
- mismatches[live_fingerprint].append(mismatch)
- # No FW versions for this car yet, add them all to mismatch list
- if not found:
- for version in car_fw:
- sub_addr = None if version.subAddress == 0 else version.subAddress
- addr = version.address
- mismatch = (addr, sub_addr, version.fwVersion)
- if mismatch not in mismatches[live_fingerprint]:
- mismatches[live_fingerprint].append(mismatch)
- print()
- not_fingerprinted += 1
- if len(fuzzy_matches) == 1:
- if list(fuzzy_matches)[0] == live_fingerprint:
- solved_by_fuzzy += 1
- else:
- wrong_fuzzy += 1
- print("Fuzzy match wrong! Fuzzy:", fuzzy_matches, "Live:", live_fingerprint)
- break
- if CP is None:
- print("no CarParams in logs")
- except Exception:
- traceback.print_exc()
- except KeyboardInterrupt:
- break
- print()
- # Print FW versions that need to be added separated out by car and address
- for car, m in sorted(mismatches.items()):
- print(car)
- addrs = defaultdict(list)
- for (addr, sub_addr, version) in m:
- addrs[(addr, sub_addr)].append(version)
- for (addr, sub_addr), versions in addrs.items():
- print(f" ({hex(addr)}, {'None' if sub_addr is None else hex(sub_addr)}): [")
- for v in versions:
- print(f" {v},")
- print(" ]")
- print()
- print()
- print(f"Number of dongle ids checked: {len(dongles)}")
- print(f"Fingerprinted: {good_exact}")
- print(f"Not fingerprinted: {not_fingerprinted}")
- print(f" of which had a fuzzy match: {solved_by_fuzzy}")
- print()
- print(f"Correct fuzzy matches: {good_fuzzy}")
- print(f"Wrong fuzzy matches: {wrong_fuzzy}")
- print()
|