@ -2,7 +2,7 @@ import re 
			
		
	
		
		
			
				
					
					from  collections  import  defaultdict from  collections  import  defaultdict  
			
		
	
		
		
			
				
					
					from  dataclasses  import  dataclass ,  field from  dataclasses  import  dataclass ,  field  
			
		
	
		
		
			
				
					
					from  enum  import  Enum ,  IntFlag from  enum  import  Enum ,  IntFlag  
			
		
	
		
		
			
				
					
					from  typing  import  Dict ,  List ,  Set ,  Tuple ,  Union from  typing  import  Dict ,  List ,  Set ,  Union  
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					from  cereal  import  car from  cereal  import  car  
			
		
	
		
		
			
				
					
					from  openpilot . common . conversions  import  Conversions  as  CV from  openpilot . common . conversions  import  Conversions  as  CV  
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -236,8 +236,9 @@ STATIC_DSU_MSGS = [ 
			
		
	
		
		
			
				
					
					] ]  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					def  get_platform_codes ( fw_versions :  List [ bytes ] )  - >  Set [ Tuple [ bytes ,  bytes ] ] : def  get_platform_codes ( fw_versions :  List [ bytes ] )  - >  Dict [ bytes ,  Set [ bytes ] ] :  
			
				
				
			
		
	
		
		
			
				
					
					  codes  =  set ( )   # (Optional[part]-platform-major_version, minor_version)    # Returns sub versions in a dict so comparisons can be made within part-platform-major_version combos   
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					  codes  =  defaultdict ( set )   # Optional[part]-platform-major_version: set of sub_version   
			
		
	
		
		
			
				
					
					  for  fw  in  fw_versions :    for  fw  in  fw_versions :   
			
		
	
		
		
			
				
					
					    # FW versions returned from UDS queries can return multiple fields/chunks of data (different ECU calibrations, different data?)      # FW versions returned from UDS queries can return multiple fields/chunks of data (different ECU calibrations, different data?)   
			
		
	
		
		
			
				
					
					    #  and are prefixed with a byte that describes how many chunks of data there are.      #  and are prefixed with a byte that describes how many chunks of data there are.   
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -262,42 +263,49 @@ def get_platform_codes(fw_versions: List[bytes]) -> Set[Tuple[bytes, bytes]]: 
			
		
	
		
		
			
				
					
					      fw_match  =  SHORT_FW_PATTERN . search ( first_chunk )        fw_match  =  SHORT_FW_PATTERN . search ( first_chunk )   
			
		
	
		
		
			
				
					
					      if  fw_match  is  not  None :        if  fw_match  is  not  None :   
			
		
	
		
		
			
				
					
					        platform ,  major_version ,  sub_version  =  fw_match . groups ( )          platform ,  major_version ,  sub_version  =  fw_match . groups ( )   
			
		
	
		
		
			
				
					
					        # codes.add((platform + b'-' + major_version, sub_version))          codes [ b ' - ' . join ( ( platform ,  major_version ) ) ] . add ( sub_version )   
			
				
				
			
		
	
		
		
			
				
					
					        codes . add ( ( b ' - ' . join ( ( platform ,  major_version ) ) ,  sub_version ) )   
			
		
	
		
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    elif  len ( first_chunk )  ==  10 :      elif  len ( first_chunk )  ==  10 :   
			
		
	
		
		
			
				
					
					      fw_match  =  MEDIUM_FW_PATTERN . search ( first_chunk )        fw_match  =  MEDIUM_FW_PATTERN . search ( first_chunk )   
			
		
	
		
		
			
				
					
					      if  fw_match  is  not  None :        if  fw_match  is  not  None :   
			
		
	
		
		
			
				
					
					        part ,  platform ,  major_version ,  sub_version  =  fw_match . groups ( )          part ,  platform ,  major_version ,  sub_version  =  fw_match . groups ( )   
			
		
	
		
		
			
				
					
					        codes . add ( ( b ' - ' . join ( ( part ,  platform ,  major_version ) ) ,  sub_version ) )          codes [ b ' - ' . join ( ( part ,  platform ,  major_version ) ) ] . add ( sub_version )   
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					    elif  len ( first_chunk )  ==  12 :      elif  len ( first_chunk )  ==  12 :   
			
		
	
		
		
			
				
					
					      fw_match  =  LONG_FW_PATTERN . search ( first_chunk )        fw_match  =  LONG_FW_PATTERN . search ( first_chunk )   
			
		
	
		
		
			
				
					
					      if  fw_match  is  not  None :        if  fw_match  is  not  None :   
			
		
	
		
		
			
				
					
					        part ,  platform ,  major_version ,  sub_version  =  fw_match . groups ( )          part ,  platform ,  major_version ,  sub_version  =  fw_match . groups ( )   
			
		
	
		
		
			
				
					
					        codes . add ( ( b ' - ' . join ( ( part ,  platform ,  major_version ) ) ,  sub_version ) )          codes [ b ' - ' . join ( ( part ,  platform ,  major_version ) ) ] . add ( sub_version )   
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					  return  codes    return  dict ( codes )   
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					# Regex patterns for parsing more general platform-specific identifiers from FW versions. # Regex patterns for parsing more general platform-specific identifiers from FW versions.  
			
		
	
		
		
			
				
					
					# - Part number: Toyota part number (usually last character needs to be ignored to find a match). # - Part number: Toyota part number (usually last character needs to be ignored to find a match).  
			
		
	
		
		
			
				
					
					# - Platform: usually multiple codes per an openpilot platform, however this has the less variability and #    Each ECU address has just one part number.  
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					# - Platform: usually multiple codes per an openpilot platform, however this is the least variable and  
			
		
	
		
		
			
				
					
					#    is usually shared across ECUs and model years signifying this describes something about the specific platform. #    is usually shared across ECUs and model years signifying this describes something about the specific platform.  
			
		
	
		
		
			
				
					
					# - Major version: second least variable part of the FW version. Seen splitting cars by model year such as RAV4 2022/2023 and Prius. #    This describes more generational changes (TSS-P vs TSS2), or manufacture region.  
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					# - Major version: second least variable part of the FW version. Seen splitting cars by model year/API such as  
			
		
	
		
		
			
				
					
					#    RAV4 2022/2023 and Avalon. Used to differentiate cars where API has changed slightly, but is not a generational change.  
			
		
	
		
		
			
				
					
					#    It is important to note that these aren't always consecutive, for example: #    It is important to note that these aren't always consecutive, for example:  
			
		
	
		
		
			
				
					
					#    Prius TSS-P has these major versions over 16 FW: 2, 3, 4, 6, 8 while Prius TSS2 has: 5 #    Avalon 2016-18's fwdCamera has these major versions: 01, 03 while 2019 has: 02   
			
				
				
			
		
	
		
		
			
				
					
					# - Sub version: exclusive to major version, but shared with other cars. Should only be used for further filtering,  # - Sub version: exclusive to major version, but shared with other cars. Should only be used for further filtering.   
			
				
				
			
		
	
		
		
			
				
					
					#    more exploration is needed . #    Seen bumped in TSB FW updates, and describes other minor differences .  
			
				
				
			
		
	
		
		
			
				
					
					SHORT_FW_PATTERN  =  re . compile ( b ' (?P<platform>[A-Z0-9] {2} )(?P<major_version>[A-Z0-9] {2} )(?P<sub_version>[A-Z0-9] {4 } ) ' ) SHORT_FW_PATTERN  =  re . compile ( b ' [A-Z0-9] (?P<platform>[A-Z0-9]{2} )(?P<major_version>[A-Z0-9] {2} )(?P<sub_version>[A-Z0-9] {3 } ) ' )  
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					MEDIUM_FW_PATTERN  =  re . compile ( b ' (?P<part>[A-Z0-9] {5} )(?P<platform>[A-Z0-9] {2} )(?P<major_version>[A-Z0-9] {1} )(?P<sub_version>[A-Z0-9] {2} ) ' ) MEDIUM_FW_PATTERN  =  re . compile ( b ' (?P<part>[A-Z0-9] {5} )(?P<platform>[A-Z0-9] {2} )(?P<major_version>[A-Z0-9] {1} )(?P<sub_version>[A-Z0-9] {2} ) ' )  
			
		
	
		
		
			
				
					
					LONG_FW_PATTERN  =  re . compile ( b ' (?P<part>[A-Z0-9] {5} )(?P<platform>[A-Z0-9] {2} )(?P<major_version>[A-Z0-9] {2} )(?P<sub_version>[A-Z0-9] {3} ) ' ) LONG_FW_PATTERN  =  re . compile ( b ' (?P<part>[A-Z0-9] {5} )(?P<platform>[A-Z0-9] {2} )(?P<major_version>[A-Z0-9] {2} )(?P<sub_version>[A-Z0-9] {3} ) ' )  
			
		
	
		
		
			
				
					
					FW_LEN_CODE  =  re . compile ( b ' ^[ \x01 - \x05  ] ' )   # 5 chunks max.  highest seen is 3 chunks, 16 bytes each FW_LEN_CODE  =  re . compile ( b ' ^[ \x01 - \x03  ] ' )   # highest seen is 3 chunks, 16 bytes each  
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					FW_CHUNK_LEN  =  16 FW_CHUNK_LEN  =  16  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					# List of ECUs expected to have platform codes # List of ECUs that are most unique across openpilot platforms  
			
				
				
			
		
	
		
		
			
				
					
					# TODO: use hybrid ECU, splits many similar ICE and hybrid variants # TODO: use hybrid ECU, splits similar ICE and hybrid variants  
			
				
				
			
		
	
		
		
			
				
					
					PLATFORM_CODE_ECUS  =  [ Ecu . abs ,  Ecu . engine ,  Ecu . eps ,  Ecu . dsu ,  Ecu . fwdCamera ,  Ecu . fwdRadar ] # - fwdCamera: describes actual features related to ADAS. For example, on the Avalon it describes  
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					#    when TSS-P became standard, whether the car supports stop and go, and whether it's TSS2.  
			
		
	
		
		
			
				
					
					#    On the RAV4, it describes the move to the radar doing ACC, and the use of LTA for lane keeping.  
			
		
	
		
		
			
				
					
					# - abs: differentiates hybrid/ICE on most cars (Corolla TSS2 is an exception)  
			
		
	
		
		
			
				
					
					# - eps: describes lateral API changes for the EPS, such as using LTA for lane keeping and rejecting LKA messages  
			
		
	
		
		
			
				
					
					PLATFORM_CODE_ECUS  =  [ Ecu . fwdCamera ,  Ecu . abs ,  Ecu . eps ]  
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					
 
			
		
	
		
		
			
				
					
					# Some ECUs that use KWP2000 have their FW versions on non-standard data identifiers. # Some ECUs that use KWP2000 have their FW versions on non-standard data identifiers.