Files

204 lines
10 KiB
Python

"""Saved generic runtime startup does not replace live driving authority."""
from pathlib import Path
import json
from tempfile import TemporaryDirectory
from openpilot.starpilot.conditional_mode.policy import ModeChoice
from openpilot.starpilot.conditional_mode.preferences import SavedPreferences, encode_preferences
from openpilot.starpilot.feature_runtime import enabled, requested
from openpilot.starpilot.longitudinal.profile_document import default_personality_profiles, profile_document
from openpilot.starpilot.speed_limits.vision_gate import diagnostic_choice_enabled
def long_cp():
from opendbc.car.toyota.interface import CarInterface
from opendbc.car.toyota.values import CAR
cp = CarInterface.get_non_essential_params(CAR.TOYOTA_RAV4_TSS2)
assert cp.openpilotLongitudinalControl and cp.pcmCruise
return cp
def stock_cp():
from opendbc.car.honda.interface import CarInterface
from opendbc.car.honda.values import CAR
cp = CarInterface.get_non_essential_params(CAR.HONDA_CIVIC_BOSCH)
assert not cp.openpilotLongitudinalControl
return cp
class Files:
def __init__(self, root: Path):
self.root = root
def get_param_path(self, key: str) -> str:
return str(self.root / key)
def get_default_value(self, key: str):
assert key in ('CustomPersonalities', 'LongitudinalPersonalityProfiles')
return b'0' if key == 'CustomPersonalities' else {}
def test_readable_absence_starts_factory_cem_only_on_native_long_cp():
with TemporaryDirectory() as temporary:
params = Files(Path(temporary))
assert requested(params, 'conditional')
assert enabled(params, long_cp(), 'conditional', {})
assert not enabled(params, stock_cp(), 'conditional', {})
for name in ('curve', 'slc', 'vision', 'profile'):
assert not enabled(params, object(), name, {})
(params.root / 'SafeMode').write_bytes(b'1')
assert not requested(params, 'conditional')
(params.root / 'SafeMode').write_bytes(b'0')
(params.root / 'ConditionalModeConfig').write_bytes(b'{broken')
(params.root / 'CurveSpeedController').write_bytes(b'true')
assert not requested(params, 'conditional')
assert not requested(params, 'curve')
(params.root / 'ConditionalModeConfig').unlink()
(params.root / 'ConditionalModeConfig').mkdir()
assert not requested(params, 'conditional') # Read error is never factory absence.
def test_native_long_cp_and_saved_document_start_owner_without_granting_stock_control():
with TemporaryDirectory() as temporary:
params = Files(Path(temporary))
(params.root / 'ConditionalModeConfig').write_bytes(encode_preferences(SavedPreferences(mode=ModeChoice.STOCK)))
(params.root / 'CurveSpeedController').write_bytes(b'1')
for name in ('conditional', 'curve'):
assert enabled(params, long_cp(), name, {})
assert not enabled(params, stock_cp(), name, {})
(params.root / 'SafeMode').write_bytes(b'1')
assert not enabled(params, long_cp(), 'conditional', {})
def test_global_braking_choice_starts_only_qualified_profile_owner_without_custom_master():
with TemporaryDirectory() as temporary:
params = Files(Path(temporary))
source = params.root / 'LongitudinalPersonalityProfiles'
assert requested(params, 'profile')
assert enabled(params, long_cp(), 'profile', {})
assert not enabled(params, stock_cp(), 'profile', {})
for response in ('eco', 'sport'):
source.write_text(json.dumps(profile_document(default_personality_profiles(False), enabled=False,
global_braking_response=response)))
assert requested(params, 'profile')
assert enabled(params, long_cp(), 'profile', {})
assert not enabled(params, stock_cp(), 'profile', {})
source.write_text(json.dumps(profile_document(default_personality_profiles(False), enabled=False,
selected_deceleration_profile='dom_default')))
assert not requested(params, 'profile')
bad = profile_document(default_personality_profiles(False), enabled=False)
bad['globalBrakingResponse'] = 'unsupported'
source.write_text(json.dumps(bad))
assert not requested(params, 'profile')
source.write_text('{invalid')
assert not requested(params, 'profile')
(params.root / 'SafeMode').write_bytes(b'corrupt')
assert not enabled(params, long_cp(), 'conditional', {})
def test_vision_control_needs_saved_master_and_vision_source_on_native_long_cp():
with TemporaryDirectory() as temporary:
params = Files(Path(temporary))
(params.root / 'SpeedLimitController').write_bytes(b'1')
(params.root / 'SLCPriority1').write_bytes(b'Dashboard')
(params.root / 'SLCPriority2').write_bytes(b'Vision')
from openpilot.starpilot.feature_runtime import vision_control_enabled
assert requested(params, 'vision')
assert enabled(params, long_cp(), 'vision', {})
assert enabled(params, stock_cp(), 'vision', {}) # Stock owner may display selected Vision.
assert vision_control_enabled(params, long_cp())
assert not vision_control_enabled(params, stock_cp())
(params.root / 'SpeedLimitController').write_bytes(b'0')
assert enabled(params, long_cp(), 'vision', {}) # Default-on display still needs its selected Vision producer.
assert not vision_control_enabled(params, long_cp())
def test_explicit_replay_flags_remain_available_for_existing_replay_fixtures():
with TemporaryDirectory() as temporary:
params = Files(Path(temporary))
assert enabled(params, None, 'conditional', {'CONDITIONAL_MODE_REPLAY_RUNTIME': '1'})
assert enabled(params, None, 'curve', {'CURVE_REPLAY_RUNTIME': '1'})
assert enabled(params, None, 'slc', {'SLC_REPLAY_RUNTIME': '1'})
assert enabled(params, None, 'vision', {'SLC_REPLAY_RUNTIME': '1', 'SLC_VISION_DEVELOPMENT': '1'})
assert not enabled(params, None, 'vision', {'SLC_VISION_DEVELOPMENT': '1'})
def test_saved_vision_choice_is_offered_for_native_display_vehicle_or_explicit_replay():
assert diagnostic_choice_enabled({}, long_cp())
assert diagnostic_choice_enabled({}, stock_cp()) # Source visibility grants no speed authority.
assert not diagnostic_choice_enabled({})
assert diagnostic_choice_enabled({'SLC_REPLAY_RUNTIME': '1', 'SLC_VISION_DEVELOPMENT': '1'})
def test_gm_saved_profiles_require_existing_longitudinal_owner():
from opendbc.car.gm.tests.test_bolt_pedal import params as pedal_params
from opendbc.car.gm.tests.test_ascm_intercept import params as ascm_params
from opendbc.car.gm.values import CAR, PEDAL_BOLT_CAR, GMSafetyFlags
from opendbc.car.gm.profiles import profiles_supported
from openpilot.common.params import Params
with TemporaryDirectory() as temporary:
params = Params(temporary)
root = Path(params.get_param_path('CustomPersonalities')).parent
(root / 'CustomPersonalities').write_bytes(b'1')
(root / 'LongitudinalPersonalityProfiles').write_text(json.dumps(
profile_document(default_personality_profiles(True), enabled=True)))
for alpha in (False, True):
for candidate in PEDAL_BOLT_CAR:
cp = pedal_params(candidate, setting=True, pedal=True, alpha_long=alpha)
assert enabled(params, cp, 'profile', {})
assert enabled(params, cp, 'conditional', {})
for field in ('passive', 'dashcamOnly', 'notCar'):
setattr(cp, field, True)
assert not enabled(params, cp, 'profile', {})
setattr(cp, field, False)
cp.openpilotLongitudinalControl = False
assert not enabled(params, cp, 'profile', {})
assert enabled(params, pedal_params(candidate, setting=False, pedal=True, alpha_long=alpha), 'profile', {})
assert enabled(params, ascm_params(CAR.CHEVROLET_BOLT_EUV, alpha=alpha), 'profile', {}) == alpha
assert enabled(params, ascm_params(CAR.CHEVROLET_BOLT_ACC_2022_2023, alpha=alpha), 'profile', {}) == alpha
cp = ascm_params(CAR.CHEVROLET_VOLT_ASCM, sascm=True, alpha=alpha)
assert enabled(params, cp, 'profile', {}) == alpha
assert not enabled(params, ascm_params(CAR.CHEVROLET_VOLT_ASCM, sascm=False, alpha=alpha), 'profile', {})
cp = ascm_params(CAR.CHEVROLET_VOLT, radar=True)
assert profiles_supported(cp)
assert enabled(params, cp, 'profile', {})
cp.safetyConfigs[0].safetyParam |= int(GMSafetyFlags.NO_ACC)
assert not profiles_supported(cp)
assert not enabled(params, ascm_params(CAR.CHEVROLET_VOLT_CAMERA), 'profile', {})
assert not enabled(params, ascm_params(CAR.CHEVROLET_VOLT_2019), 'profile', {})
(root / 'CustomPersonalities').write_bytes(b'0')
(root / 'LongitudinalPersonalityProfiles').write_text(json.dumps(
profile_document(default_personality_profiles(True), enabled=True, selected_deceleration_profile='dom_default')))
assert not enabled(params, ascm_params(CAR.CHEVROLET_VOLT, radar=True), 'profile', {})
(root / 'CustomPersonalities').write_bytes(b'1')
(root / 'LongitudinalPersonalityProfiles').write_text('{broken')
assert not enabled(params, ascm_params(CAR.CHEVROLET_VOLT, radar=True), 'profile', {})
def test_honda_slc_controls_only_with_openpilot_long():
from types import SimpleNamespace
from openpilot.starpilot.feature_runtime import slc_runtime_settings, slc_transport_capable, vision_control_enabled
def honda(**overrides):
return SimpleNamespace(**{'brand': 'honda', 'carFingerprint': 'HONDA_CIVIC_2022', 'openpilotLongitudinalControl': True,
'pcmCruise': False, 'passive': False, 'dashcamOnly': False, 'notCar': False, **overrides})
with TemporaryDirectory() as temporary:
params = Files(Path(temporary))
(params.root / 'SpeedLimitController').write_bytes(b'1')
(params.root / 'SLCPriority1').write_bytes(b'Dashboard')
(params.root / 'SLCPriority2').write_bytes(b'Map Data')
assert slc_transport_capable(honda(), {})
assert enabled(params, honda(), 'slc', {})
assert slc_runtime_settings(params, honda(), {}).enabled
assert not enabled(params, honda(), 'vision', {})
assert not vision_control_enabled(params, honda())
stock = honda(openpilotLongitudinalControl=False, pcmCruise=True)
assert enabled(params, stock, 'slc', {})
assert not slc_runtime_settings(params, stock, {}).enabled
assert not slc_transport_capable(honda(dashcamOnly=True), {})
assert not enabled(params, honda(dashcamOnly=True), 'slc', {})