#!/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 selfdrive . car . fw_versions import match_fw_to_car
from selfdrive . car . toyota . values import FW_VERSIONS as TOYOTA_FW_VERSIONS
from selfdrive . car . honda . values import FW_VERSIONS as HONDA_FW_VERSIONS
from selfdrive . car . hyundai . values import FW_VERSIONS as HYUNDAI_FW_VERSIONS
from selfdrive . car . toyota . values import FINGERPRINTS as TOYOTA_FINGERPRINTS
from selfdrive . car . honda . values import FINGERPRINTS as HONDA_FINGERPRINTS
from selfdrive . car . hyundai . values import FINGERPRINTS as HYUNDAI_FINGERPRINTS
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 )
wrong = 0
good = 0
dongles = [ ]
for route in tqdm ( routes ) :
route = route . rstrip ( )
dongle_id , time = route . split ( ' | ' )
qlog_path = f " cd:/ { dongle_id } / { time } /0/qlog.bz2 "
if dongle_id in dongles :
continue
try :
lr = LogReader ( qlog_path )
for msg in lr :
if msg . which ( ) == " health " :
if msg . health . pandaType not in [ ' uno ' , ' blackPanda ' ] :
dongles . append ( dongle_id )
break
elif msg . which ( ) == " carParams " :
bts = msg . carParams . as_builder ( ) . to_bytes ( )
car_fw = msg . carParams . carFw
if len ( car_fw ) == 0 :
break
dongles . append ( dongle_id )
live_fingerprint = msg . carParams . carFingerprint
if args . car is not None :
live_fingerprint = args . car
if live_fingerprint not in list ( TOYOTA_FINGERPRINTS . keys ( ) ) + list ( HONDA_FINGERPRINTS . keys ( ) ) + list ( HYUNDAI_FINGERPRINTS . keys ( ) ) :
break
candidates = match_fw_to_car ( car_fw )
if ( len ( candidates ) == 1 ) and ( list ( candidates ) [ 0 ] == live_fingerprint ) :
good + = 1
print ( " Correct " , live_fingerprint , dongle_id )
break
print ( f " { dongle_id } | { time } " )
print ( " Old style: " , live_fingerprint , " Vin " , msg . carParams . carVin )
print ( " New style: " , candidates )
for version in car_fw :
subaddr = None if version . subAddress == 0 else hex ( version . subAddress )
print ( f " (Ecu. { version . ecu } , { hex ( version . address ) } , { subaddr } ): [ { version . fwVersion } ], " )
print ( " Mismatches " )
found = False
for car_fws in [ TOYOTA_FW_VERSIONS , HONDA_FW_VERSIONS , HYUNDAI_FW_VERSIONS ] :
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 :
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 ( )
wrong + = 1
break
except Exception :
traceback . print_exc ( )
except KeyboardInterrupt :
break
print ( f " Fingerprinted: { good } - Not fingerprinted: { wrong } " )
print ( f " Number of dongle ids checked: { len ( dongles ) } " )
print ( )
# Print FW versions that need to be added seperated out by car and address
for car , m in 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 ( )