|  |  |  | @ -2,24 +2,22 @@ import os | 
			
		
	
		
			
				
					|  |  |  |  | import math | 
			
		
	
		
			
				
					|  |  |  |  | import hypothesis.strategies as st | 
			
		
	
		
			
				
					|  |  |  |  | from hypothesis import Phase, given, settings | 
			
		
	
		
			
				
					|  |  |  |  | import importlib | 
			
		
	
		
			
				
					|  |  |  |  | from parameterized import parameterized | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | from cereal import car, messaging | 
			
		
	
		
			
				
					|  |  |  |  | from opendbc.car import DT_CTRL, gen_empty_fingerprint | 
			
		
	
		
			
				
					|  |  |  |  | from cereal import car | 
			
		
	
		
			
				
					|  |  |  |  | from opendbc.car import DT_CTRL | 
			
		
	
		
			
				
					|  |  |  |  | from opendbc.car.car_helpers import interfaces | 
			
		
	
		
			
				
					|  |  |  |  | from opendbc.car.structs import CarParams | 
			
		
	
		
			
				
					|  |  |  |  | from opendbc.car.tests.test_car_interfaces import get_fuzzy_car_interface_args | 
			
		
	
		
			
				
					|  |  |  |  | from opendbc.car.fingerprints import all_known_cars | 
			
		
	
		
			
				
					|  |  |  |  | from opendbc.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS | 
			
		
	
		
			
				
					|  |  |  |  | from opendbc.car.interfaces import get_interface_attr | 
			
		
	
		
			
				
					|  |  |  |  | from opendbc.car.mock.values import CAR as MOCK | 
			
		
	
		
			
				
					|  |  |  |  | from openpilot.selfdrive.car.card import convert_carControl, convert_to_capnp | 
			
		
	
		
			
				
					|  |  |  |  | from openpilot.selfdrive.controls.lib.latcontrol_angle import LatControlAngle | 
			
		
	
		
			
				
					|  |  |  |  | from openpilot.selfdrive.controls.lib.latcontrol_pid import LatControlPID | 
			
		
	
		
			
				
					|  |  |  |  | from openpilot.selfdrive.controls.lib.latcontrol_torque import LatControlTorque | 
			
		
	
		
			
				
					|  |  |  |  | from openpilot.selfdrive.controls.lib.longcontrol import LongControl | 
			
		
	
		
			
				
					|  |  |  |  | from openpilot.selfdrive.pandad import can_capnp_to_list | 
			
		
	
		
			
				
					|  |  |  |  | from openpilot.selfdrive.test.fuzzy_generation import DrawType, FuzzyGenerator | 
			
		
	
		
			
				
					|  |  |  |  | from openpilot.selfdrive.test.fuzzy_generation import FuzzyGenerator | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | ALL_ECUS = {ecu for ecus in FW_VERSIONS.values() for ecu in ecus.keys()} | 
			
		
	
		
			
				
					|  |  |  |  | ALL_ECUS |= {ecu for config in FW_QUERY_CONFIGS.values() for ecu in config.extra_ecus} | 
			
		
	
	
		
			
				
					|  |  |  | @ -29,28 +27,6 @@ ALL_REQUESTS = {tuple(r.request) for config in FW_QUERY_CONFIGS.values() for r i | 
			
		
	
		
			
				
					|  |  |  |  | MAX_EXAMPLES = int(os.environ.get('MAX_EXAMPLES', '60')) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | def get_fuzzy_car_interface_args(draw: DrawType) -> dict: | 
			
		
	
		
			
				
					|  |  |  |  |   # Fuzzy CAN fingerprints and FW versions to test more states of the CarInterface | 
			
		
	
		
			
				
					|  |  |  |  |   fingerprint_strategy = st.fixed_dictionaries({key: st.dictionaries(st.integers(min_value=0, max_value=0x800), | 
			
		
	
		
			
				
					|  |  |  |  |                                                                      st.integers(min_value=0, max_value=64)) for key in | 
			
		
	
		
			
				
					|  |  |  |  |                                                 gen_empty_fingerprint()}) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   # only pick from possible ecus to reduce search space | 
			
		
	
		
			
				
					|  |  |  |  |   car_fw_strategy = st.lists(st.sampled_from(sorted(ALL_ECUS))) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   params_strategy = st.fixed_dictionaries({ | 
			
		
	
		
			
				
					|  |  |  |  |     'fingerprints': fingerprint_strategy, | 
			
		
	
		
			
				
					|  |  |  |  |     'car_fw': car_fw_strategy, | 
			
		
	
		
			
				
					|  |  |  |  |     'experimental_long': st.booleans(), | 
			
		
	
		
			
				
					|  |  |  |  |   }) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   params: dict = draw(params_strategy) | 
			
		
	
		
			
				
					|  |  |  |  |   params['car_fw'] = [CarParams.CarFw(ecu=fw[0], address=fw[1], subAddress=fw[2] or 0, | 
			
		
	
		
			
				
					|  |  |  |  |                                       request=draw(st.sampled_from(sorted(ALL_REQUESTS)))) | 
			
		
	
		
			
				
					|  |  |  |  |                       for fw in params['car_fw']] | 
			
		
	
		
			
				
					|  |  |  |  |   return params | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | class TestCarInterfaces: | 
			
		
	
		
			
				
					|  |  |  |  |   # FIXME: Due to the lists used in carParams, Phase.target is very slow and will cause | 
			
		
	
		
			
				
					|  |  |  |  |   #  many generated examples to overrun when max_examples > ~20, don't use it | 
			
		
	
	
		
			
				
					|  |  |  | @ -121,45 +97,3 @@ class TestCarInterfaces: | 
			
		
	
		
			
				
					|  |  |  |  |       LatControlPID(car_params_capnp, car_interface) | 
			
		
	
		
			
				
					|  |  |  |  |     elif car_params.lateralTuning.which() == 'torque': | 
			
		
	
		
			
				
					|  |  |  |  |       LatControlTorque(car_params_capnp, car_interface) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     # Test radar interface | 
			
		
	
		
			
				
					|  |  |  |  |     RadarInterface = importlib.import_module(f'opendbc.car.{car_params.carName}.radar_interface').RadarInterface | 
			
		
	
		
			
				
					|  |  |  |  |     radar_interface = RadarInterface(car_params) | 
			
		
	
		
			
				
					|  |  |  |  |     assert radar_interface | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     # Run radar interface once | 
			
		
	
		
			
				
					|  |  |  |  |     radar_interface.update([]) | 
			
		
	
		
			
				
					|  |  |  |  |     if not car_params.radarUnavailable and radar_interface.rcp is not None and \ | 
			
		
	
		
			
				
					|  |  |  |  |        hasattr(radar_interface, '_update') and hasattr(radar_interface, 'trigger_msg'): | 
			
		
	
		
			
				
					|  |  |  |  |       radar_interface._update([radar_interface.trigger_msg]) | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     # Test radar fault | 
			
		
	
		
			
				
					|  |  |  |  |     if not car_params.radarUnavailable and radar_interface.rcp is not None: | 
			
		
	
		
			
				
					|  |  |  |  |       cans = can_capnp_to_list([messaging.new_message('can', 1).to_bytes() for _ in range(5)]) | 
			
		
	
		
			
				
					|  |  |  |  |       rr = radar_interface.update(cans) | 
			
		
	
		
			
				
					|  |  |  |  |       assert rr is None or len(rr.errors) > 0 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |   def test_interface_attrs(self): | 
			
		
	
		
			
				
					|  |  |  |  |     """Asserts basic behavior of interface attribute getter""" | 
			
		
	
		
			
				
					|  |  |  |  |     num_brands = len(get_interface_attr('CAR')) | 
			
		
	
		
			
				
					|  |  |  |  |     assert num_brands >= 12 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     # Should return value for all brands when not combining, even if attribute doesn't exist | 
			
		
	
		
			
				
					|  |  |  |  |     ret = get_interface_attr('FAKE_ATTR') | 
			
		
	
		
			
				
					|  |  |  |  |     assert len(ret) == num_brands | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     # Make sure we can combine dicts | 
			
		
	
		
			
				
					|  |  |  |  |     ret = get_interface_attr('DBC', combine_brands=True) | 
			
		
	
		
			
				
					|  |  |  |  |     assert len(ret) >= 160 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     # We don't support combining non-dicts | 
			
		
	
		
			
				
					|  |  |  |  |     ret = get_interface_attr('CAR', combine_brands=True) | 
			
		
	
		
			
				
					|  |  |  |  |     assert len(ret) == 0 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     # If brand has None value, it shouldn't return when ignore_none=True is specified | 
			
		
	
		
			
				
					|  |  |  |  |     none_brands = {b for b, v in get_interface_attr('FINGERPRINTS').items() if v is None} | 
			
		
	
		
			
				
					|  |  |  |  |     assert len(none_brands) >= 1 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     ret = get_interface_attr('FINGERPRINTS', ignore_none=True) | 
			
		
	
		
			
				
					|  |  |  |  |     none_brands_in_ret = none_brands.intersection(ret) | 
			
		
	
		
			
				
					|  |  |  |  |     assert len(none_brands_in_ret) == 0, f'Brands with None values in ignore_none=True result: {none_brands_in_ret}' | 
			
		
	
	
		
			
				
					|  |  |  | 
 |