#!/usr/bin/env python3
import capnp
import copy
from dataclasses import dataclass , field
import struct
HKG: use platform codes to fuzzy fingerprint (#28531)
* get gas/ev/hev from FW (not all correct, poc)
* add test for essential ecus for fuzzy fingerprinting
* kinda works
* stash
* clean up
* add code
* simpler
* use the function
* test it with our cars
* no re
no re
no re
* debugging
* handle empty dict
* simpl
* this is promising
start on making existing fingerprinting functions use the config, instead of entirely replacing them
* needs to allow 1 match
* lay out how this should look
* changes
* executable
* some work
* use config
* fuzzy ecus
* config test
* comment and some clean up
* test platform codes
* use regex, simpler and fixes bug
* in func
* rm bad func
* typing for new func and remove old from dc
* todo done
* tested!
* remove fake platform codes
* thought we needed this, but actually...
* not needed
* not applicable any more
* use config for essential ecus
* first draft of test to make adding/removing fuzzy FP platform intentional
* compile
* clean up test
* even cleaner
* fix default ecus type
* temp fix
* this is mostly in tests now
* test every fuzzy ecu fw returns one platform code
* experiment with dates
* Revert "experiment with dates"
This reverts commit 3251b9cc5c3ca41ca92c8b75ad9b2234b720aa0b.
* clean that up
* comment
* test
* work on all cars
* fix fuzz_fw_fingerprint
* comment
* get first by search
* bit more clean up
* and more
* use compiled pattern for nicer syntax
* default
* flip dat around, much cleaner
* clean up hyundai test a bit
* flip order
same here
* rename test and flip subTest
* fix pylint
* revert fw changes
revert fw changes
* line
* add original functions to test
* needs to be a list
* cmt
* draft (need to count one ecu as a match)
* tiny clean up
* todo: date range
* only in notebook
* remove comment (still can be either list or set)
* same, only notebook
* more consistent signature
* copilot inspired
* copilot no good
* test for date parsing
* better name
* good, now we don't have to worry about the dates mismatching in another test/logic
* comment up+
* some stuff
* clean up
fix test
fix test
* test
* comment
* use utils
* clean up (utils are cleaner and less buggy)
* clean up (utils are cleaner and less buggy)
* fixup test
* use a dash (prettier) and remove some platforms that can fingerprint now!
* compile global pattern
* same as what we do in values
* remove comments
* fuzzy_get_platform_codes is one or none here
* more clean up
* sort imports
* woah woah woah
* add comment
* fix reassigning different types
* add types
* adapt fuzzy test recently added (nice it caught this!)
* update lock
* options
comments
* stash
* comments and fixes
* better comments
* better
* test: run on exact fuzzy matching logic, same results!
* use match_fw_to_car
* test all fw
* ex
* unused random
* this is a possibility
* this is more clear
* fix
* revert
* revert to needing both ECUs to match to reduce false positives, test
* fix excluded platform test :( but it's ok
* add comment
* we actually want to only test fuzzy ecus to make it explicit
* fix mypy
* comment for tomorrow
* just add matches with fuzzy FP
* add comment
* this was the cleanest I could think of, but still working on it. not very easy to understand
* think this is better, but also worse...
* comment: reframing how this works
* revert back to what we did before
* was swapped
* else set
* remove old comment
* fixes from merge
* remove fuzzy_min_match_count from this pr
* fix static analysis
* also unused
* different method first draft
* copy existing fuzzy func
* check all possible ecus exist, only platform codes, slightly refactor main loop
* fix
* Revert recent
Revert "fix"
This reverts commit 5cdb7bda835f1e48e750ab4195e891afe08e11ea.
Revert "check all possible ecus exist, only platform codes, slightly refactor main loop"
This reverts commit d3e918fa20fa4ce881445850f5f7428a3c11adf8.
Revert "copy existing fuzzy func"
This reverts commit 34c8c0545097c84f55f4b4f61907606c93760ddd.
Revert "different method first draft"
This reverts commit b91139055d7d1802c1eb726504798c156a183c9c.
* new func
* fixup test
* remove changes from v1 from fw_versions.py
* clean up a bit
* return part as part of code
* fix test
* add original fuzzy function
* add an ecu match if the date is within range (or date doesn't exist)
* add format for what we're going to do
* not working stash
* the exact matching function does more of what we want with less code and less custom logic
* we don't care about found versions, only codes and dates
* actually we do have an exception
* this works pretty nicely now
* up here
* this is better
* some minor clean up
* old function=now junk
* fix platform code test
* remove old platform code function
* now rename _new to
* use FW_QUERY_CONFIG
* clean up imports
* rename that too
* one line
* correct typing
correct typing
* draft tests
* so that works
* fixup excluded platform test now too
* this is tested by excluded platform test
* test parts and dates
* remove old comment
* old import
* take platform code stuff out of FwQueryConfig
* fix test
* revert debug script
* flip order
* make this a set by default
* revert this part
* correct typing
* clean up comments
* clean that test up too/pylint
* combine these three tests ina clean way
* not right
* more general
* be consistent with quotes
* comment
* comment
* comment in fw_versions
* flip order
* this is more readable
* could test all this, but it's tested in test_hyundai and doesn't do a lot here
* only assert brands which use this
* invalidate all CAN FD ICE and hybrid
* tuple
* can get away without filtering
* add comment reasons
* fix
* some review suggestions
* this works (first draft)
* this is better
* script to print platform codes and dates
* sanity check for dates are in correct ecus and platforms
* mypy
* better variable name and comment
* rename
* same
* slightly better name
* subset
* exclude platforms and live car without dates
* consistent
* self explan
* better name
* test to make sure the functions agree
* clean that up
* comment
* we get other responses from queries not in DB, only check any
* not used or typed
2 years ago
from typing import Callable , Dict , List , Optional , Set , Tuple
import panda . python . uds as uds
AddrType = Tuple [ int , Optional [ int ] ]
EcuAddrBusType = Tuple [ int , Optional [ int ] , int ]
EcuAddrSubAddr = Tuple [ int , int , Optional [ int ] ]
LiveFwVersions = Dict [ AddrType , Set [ bytes ] ]
OfflineFwVersions = Dict [ str , Dict [ EcuAddrSubAddr , List [ bytes ] ] ]
STANDARD_VIN_ADDRS = [ 0x7e0 , 0x7e2 , 0x18da10f1 , 0x18da0ef1 ] # engine, VMCU, 29-bit engine, PGM-FI
def p16 ( val ) :
return struct . pack ( " !H " , val )
class StdQueries :
# FW queries
TESTER_PRESENT_REQUEST = bytes ( [ uds . SERVICE_TYPE . TESTER_PRESENT , 0x0 ] )
TESTER_PRESENT_RESPONSE = bytes ( [ uds . SERVICE_TYPE . TESTER_PRESENT + 0x40 , 0x0 ] )
SHORT_TESTER_PRESENT_REQUEST = bytes ( [ uds . SERVICE_TYPE . TESTER_PRESENT ] )
SHORT_TESTER_PRESENT_RESPONSE = bytes ( [ uds . SERVICE_TYPE . TESTER_PRESENT + 0x40 ] )
DEFAULT_DIAGNOSTIC_REQUEST = bytes ( [ uds . SERVICE_TYPE . DIAGNOSTIC_SESSION_CONTROL ,
uds . SESSION_TYPE . DEFAULT ] )
DEFAULT_DIAGNOSTIC_RESPONSE = bytes ( [ uds . SERVICE_TYPE . DIAGNOSTIC_SESSION_CONTROL + 0x40 ,
uds . SESSION_TYPE . DEFAULT , 0x0 , 0x32 , 0x1 , 0xf4 ] )
EXTENDED_DIAGNOSTIC_REQUEST = bytes ( [ uds . SERVICE_TYPE . DIAGNOSTIC_SESSION_CONTROL ,
uds . SESSION_TYPE . EXTENDED_DIAGNOSTIC ] )
EXTENDED_DIAGNOSTIC_RESPONSE = bytes ( [ uds . SERVICE_TYPE . DIAGNOSTIC_SESSION_CONTROL + 0x40 ,
uds . SESSION_TYPE . EXTENDED_DIAGNOSTIC , 0x0 , 0x32 , 0x1 , 0xf4 ] )
MANUFACTURER_SOFTWARE_VERSION_REQUEST = bytes ( [ uds . SERVICE_TYPE . READ_DATA_BY_IDENTIFIER ] ) + \
p16 ( uds . DATA_IDENTIFIER_TYPE . VEHICLE_MANUFACTURER_ECU_SOFTWARE_NUMBER )
MANUFACTURER_SOFTWARE_VERSION_RESPONSE = bytes ( [ uds . SERVICE_TYPE . READ_DATA_BY_IDENTIFIER + 0x40 ] ) + \
p16 ( uds . DATA_IDENTIFIER_TYPE . VEHICLE_MANUFACTURER_ECU_SOFTWARE_NUMBER )
UDS_VERSION_REQUEST = bytes ( [ uds . SERVICE_TYPE . READ_DATA_BY_IDENTIFIER ] ) + \
p16 ( uds . DATA_IDENTIFIER_TYPE . APPLICATION_SOFTWARE_IDENTIFICATION )
UDS_VERSION_RESPONSE = bytes ( [ uds . SERVICE_TYPE . READ_DATA_BY_IDENTIFIER + 0x40 ] ) + \
p16 ( uds . DATA_IDENTIFIER_TYPE . APPLICATION_SOFTWARE_IDENTIFICATION )
OBD_VERSION_REQUEST = b ' \x09 \x04 '
OBD_VERSION_RESPONSE = b ' \x49 \x04 '
# VIN queries
OBD_VIN_REQUEST = b ' \x09 \x02 '
OBD_VIN_RESPONSE = b ' \x49 \x02 \x01 '
UDS_VIN_REQUEST = bytes ( [ uds . SERVICE_TYPE . READ_DATA_BY_IDENTIFIER ] ) + p16 ( uds . DATA_IDENTIFIER_TYPE . VIN )
UDS_VIN_RESPONSE = bytes ( [ uds . SERVICE_TYPE . READ_DATA_BY_IDENTIFIER + 0x40 ] ) + p16 ( uds . DATA_IDENTIFIER_TYPE . VIN )
GM_VIN_REQUEST = b ' \x1a \x90 '
GM_VIN_RESPONSE = b ' \x5a \x90 '
@dataclass
class Request :
request : List [ bytes ]
response : List [ bytes ]
whitelist_ecus : List [ int ] = field ( default_factory = list )
rx_offset : int = 0x8
bus : int = 1
# Whether this query should be run on the first auxiliary panda (CAN FD cars for example)
auxiliary : bool = False
# FW responses from these queries will not be used for fingerprinting
logging : bool = False
# boardd toggles OBD multiplexing on/off as needed
obd_multiplexing : bool = True
@dataclass
class FwQueryConfig :
requests : List [ Request ]
# TODO: make this automatic and remove hardcoded lists, or do fingerprinting with ecus
# Overrides and removes from essential ecus for specific models and ecus (exact matching)
non_essential_ecus : Dict [ capnp . lib . capnp . _EnumModule , List [ str ] ] = field ( default_factory = dict )
# Ecus added for data collection, not to be fingerprinted on
extra_ecus : List [ Tuple [ capnp . lib . capnp . _EnumModule , int , Optional [ int ] ] ] = field ( default_factory = list )
HKG: use platform codes to fuzzy fingerprint (#28531)
* get gas/ev/hev from FW (not all correct, poc)
* add test for essential ecus for fuzzy fingerprinting
* kinda works
* stash
* clean up
* add code
* simpler
* use the function
* test it with our cars
* no re
no re
no re
* debugging
* handle empty dict
* simpl
* this is promising
start on making existing fingerprinting functions use the config, instead of entirely replacing them
* needs to allow 1 match
* lay out how this should look
* changes
* executable
* some work
* use config
* fuzzy ecus
* config test
* comment and some clean up
* test platform codes
* use regex, simpler and fixes bug
* in func
* rm bad func
* typing for new func and remove old from dc
* todo done
* tested!
* remove fake platform codes
* thought we needed this, but actually...
* not needed
* not applicable any more
* use config for essential ecus
* first draft of test to make adding/removing fuzzy FP platform intentional
* compile
* clean up test
* even cleaner
* fix default ecus type
* temp fix
* this is mostly in tests now
* test every fuzzy ecu fw returns one platform code
* experiment with dates
* Revert "experiment with dates"
This reverts commit 3251b9cc5c3ca41ca92c8b75ad9b2234b720aa0b.
* clean that up
* comment
* test
* work on all cars
* fix fuzz_fw_fingerprint
* comment
* get first by search
* bit more clean up
* and more
* use compiled pattern for nicer syntax
* default
* flip dat around, much cleaner
* clean up hyundai test a bit
* flip order
same here
* rename test and flip subTest
* fix pylint
* revert fw changes
revert fw changes
* line
* add original functions to test
* needs to be a list
* cmt
* draft (need to count one ecu as a match)
* tiny clean up
* todo: date range
* only in notebook
* remove comment (still can be either list or set)
* same, only notebook
* more consistent signature
* copilot inspired
* copilot no good
* test for date parsing
* better name
* good, now we don't have to worry about the dates mismatching in another test/logic
* comment up+
* some stuff
* clean up
fix test
fix test
* test
* comment
* use utils
* clean up (utils are cleaner and less buggy)
* clean up (utils are cleaner and less buggy)
* fixup test
* use a dash (prettier) and remove some platforms that can fingerprint now!
* compile global pattern
* same as what we do in values
* remove comments
* fuzzy_get_platform_codes is one or none here
* more clean up
* sort imports
* woah woah woah
* add comment
* fix reassigning different types
* add types
* adapt fuzzy test recently added (nice it caught this!)
* update lock
* options
comments
* stash
* comments and fixes
* better comments
* better
* test: run on exact fuzzy matching logic, same results!
* use match_fw_to_car
* test all fw
* ex
* unused random
* this is a possibility
* this is more clear
* fix
* revert
* revert to needing both ECUs to match to reduce false positives, test
* fix excluded platform test :( but it's ok
* add comment
* we actually want to only test fuzzy ecus to make it explicit
* fix mypy
* comment for tomorrow
* just add matches with fuzzy FP
* add comment
* this was the cleanest I could think of, but still working on it. not very easy to understand
* think this is better, but also worse...
* comment: reframing how this works
* revert back to what we did before
* was swapped
* else set
* remove old comment
* fixes from merge
* remove fuzzy_min_match_count from this pr
* fix static analysis
* also unused
* different method first draft
* copy existing fuzzy func
* check all possible ecus exist, only platform codes, slightly refactor main loop
* fix
* Revert recent
Revert "fix"
This reverts commit 5cdb7bda835f1e48e750ab4195e891afe08e11ea.
Revert "check all possible ecus exist, only platform codes, slightly refactor main loop"
This reverts commit d3e918fa20fa4ce881445850f5f7428a3c11adf8.
Revert "copy existing fuzzy func"
This reverts commit 34c8c0545097c84f55f4b4f61907606c93760ddd.
Revert "different method first draft"
This reverts commit b91139055d7d1802c1eb726504798c156a183c9c.
* new func
* fixup test
* remove changes from v1 from fw_versions.py
* clean up a bit
* return part as part of code
* fix test
* add original fuzzy function
* add an ecu match if the date is within range (or date doesn't exist)
* add format for what we're going to do
* not working stash
* the exact matching function does more of what we want with less code and less custom logic
* we don't care about found versions, only codes and dates
* actually we do have an exception
* this works pretty nicely now
* up here
* this is better
* some minor clean up
* old function=now junk
* fix platform code test
* remove old platform code function
* now rename _new to
* use FW_QUERY_CONFIG
* clean up imports
* rename that too
* one line
* correct typing
correct typing
* draft tests
* so that works
* fixup excluded platform test now too
* this is tested by excluded platform test
* test parts and dates
* remove old comment
* old import
* take platform code stuff out of FwQueryConfig
* fix test
* revert debug script
* flip order
* make this a set by default
* revert this part
* correct typing
* clean up comments
* clean that test up too/pylint
* combine these three tests ina clean way
* not right
* more general
* be consistent with quotes
* comment
* comment
* comment in fw_versions
* flip order
* this is more readable
* could test all this, but it's tested in test_hyundai and doesn't do a lot here
* only assert brands which use this
* invalidate all CAN FD ICE and hybrid
* tuple
* can get away without filtering
* add comment reasons
* fix
* some review suggestions
* this works (first draft)
* this is better
* script to print platform codes and dates
* sanity check for dates are in correct ecus and platforms
* mypy
* better variable name and comment
* rename
* same
* slightly better name
* subset
* exclude platforms and live car without dates
* consistent
* self explan
* better name
* test to make sure the functions agree
* clean that up
* comment
* we get other responses from queries not in DB, only check any
* not used or typed
2 years ago
# Function a brand can implement to provide better fuzzy matching. Takes in FW versions,
# returns set of candidates. Only will match if one candidate is returned
match_fw_to_car_fuzzy : Optional [ Callable [ [ LiveFwVersions , OfflineFwVersions ] , Set [ str ] ] ] = None
def __post_init__ ( self ) :
for i in range ( len ( self . requests ) ) :
if self . requests [ i ] . auxiliary :
new_request = copy . deepcopy ( self . requests [ i ] )
new_request . bus + = 4
self . requests . append ( new_request )
def get_all_ecus ( self , offline_fw_versions : OfflineFwVersions ,
include_extra_ecus : bool = True ) - > set [ EcuAddrSubAddr ] :
# Add ecus in database + extra ecus
brand_ecus = { ecu for ecus in offline_fw_versions . values ( ) for ecu in ecus }
if include_extra_ecus :
brand_ecus | = set ( self . extra_ecus )
return brand_ecus