Files
StarPilot/openpilot/starpilot/aol/tests/test_angle_cancel.py
T

105 lines
5.4 KiB
Python

from contextlib import ExitStack
from dataclasses import replace
import pytest
from opendbc.car import structs
from opendbc.car.hyundai.canfd_angle_aol import MODELS
from opendbc.car.hyundai.tests.test_stock_angle_aol import source_profile
from opendbc.car.hyundai.values import CAR
from openpilot.common.prefix import OpenpilotPrefix
from openpilot.common.params import Params
from openpilot.starpilot.aol.intent import AolSettings, read_settings
from openpilot.starpilot.aol.tests import test_ioniq_availability as fixture
from openpilot.starpilot.car.hyundai.aol import create_intent, physical_cancel_lateral_allowed
from openpilot.starpilot.aol.runtime import AxisDecision
from openpilot.starpilot.aol.wire import IntentState, PandaSlot, SafetyState
@pytest.mark.parametrize('identity', sorted(MODELS))
@pytest.mark.parametrize('tick', [2, 6])
def test_unassigned_cancel_retains_current_angle_lateral_and_card_latch(identity, tick):
case = fixture.IoniqAvailabilityTests(methodName='runTest')
with ExitStack() as cleanup:
cleanup.callback(case.doCleanups)
with OpenpilotPrefix():
saved = Params()
saved.put('LKASButtonControl', 9, block=True)
saved.put('MainCruiseButtonControl', 0, block=True)
for key in ('CancelButtonControl', 'LongCancelButtonControl', 'VeryLongCancelButtonControl'):
saved.put(key, 0, block=True)
sd, _, step, card, receive = case._ioniq_availability_callers(full_op=False, stock_angle=identity)
sd.aol_settings = read_settings(saved)
assert sd.aol_settings == card.aol_card_intent.settings
state = fixture.car_state()
state.vEgoRaw = state.vEgo
state.buttonEvents = [structs.CarState.ButtonEvent(type='cancel', pressed=True)]
axis, _, command = step(tick, observed_state=state)
assert axis.lateralActive and command.latActive
assert not axis.longitudinalActive and not command.longActive and not sd.enabled
assert receive(10_000_000_000 + tick * 10_000_000, state=state, axis=sd.pm.messages['aolAxisState'],
event=sd.pm.messages['onroadEvents'])
assert card.aol_card_intent.allowed_latch
@pytest.mark.parametrize('identity', sorted(MODELS))
@pytest.mark.parametrize('action', [0, 3, 4, 9])
def test_angle_cancel_mapping_preserves_saved_action_semantics(identity, action):
cp = source_profile(CAR(identity))
cp.alternativeExperience = 32
settings = AolSettings(True, 0., 9, 0, (0, 0, 0), (action, 0, 0))
owner = create_intent(cp, settings)
state = structs.CarState(canValid=True, gearShifter='drive')
state.cruiseState.available = True
owner.update(state, now_ns=1)
state.buttonEvents = [structs.CarState.ButtonEvent(type='lkas', pressed=True)]
owner.update(state, now_ns=2)
assert owner.allowed_latch
state.buttonEvents = [structs.CarState.ButtonEvent(type='lkas', pressed=False)]
owner.update(state, now_ns=3)
state.buttonEvents = [structs.CarState.ButtonEvent(type='cancel', pressed=True)]
owner.update(state, now_ns=4)
assert owner.allowed_latch == (action == 0)
assert owner.settings == settings
@pytest.mark.parametrize('identity', sorted(MODELS))
@pytest.mark.parametrize('restriction', ['none', 'unclaimed', 'mapped_cancel', 'paused', 'old_source', 'old_native',
'wrong_session', 'foreign_inventory', 'rx_invalid', 'lat_denied', 'no_cancel'])
def test_angle_cancel_preservation_requires_current_claim_and_native_inventory(identity, restriction):
cp = source_profile(CAR(identity))
cp.alternativeExperience = 32
now, source = 10_000_000_000, 9_990_000_000
settings = AolSettings(True, 0., 9, 0, (0, 0, 0), (0, 0, 0))
state = structs.CarState(canValid=True, gearShifter='drive', vEgo=10.)
state.buttonEvents = [structs.CarState.ButtonEvent(type='cancel', pressed=True)]
intent = IntentState('angle-card', 1, source, source, source + 200_000_000, True, False, False, True, True)
config = cp.safetyConfigs[0]
slot = PandaSlot(0, 'angle-panda', int(config.safetyModel.raw), config.safetyParam, 32)
native = SafetyState(1, True, now, now + 200_000_000, int(config.safetyModel.raw), config.safetyParam,
True, False, True, False, 'angle-panda', 'angle-session', now, (slot,))
previous = AxisDecision(lateral_active=True, native_acknowledged=True)
if restriction == 'unclaimed':
previous = replace(previous, lateral_active=False)
elif restriction == 'mapped_cancel':
settings = replace(settings, cancel_actions=(3, 0, 0))
elif restriction == 'paused':
intent = replace(intent, pauseLateral=True)
elif restriction == 'old_source':
source = now - 30_000_001
intent = replace(intent, carStateLogMonoTime=source, observedMonoTime=source)
elif restriction == 'old_native':
native = replace(native, validUntilMonoTime=now - 1)
elif restriction == 'wrong_session':
native = replace(native, axisSessionId='foreign-session')
elif restriction == 'foreign_inventory':
native = replace(native, pandaInventory=(replace(slot, safetyParam=config.safetyParam ^ 1),))
elif restriction == 'rx_invalid':
native = replace(native, pandaInventory=(replace(slot, safetyRxChecksInvalid=True),))
elif restriction == 'lat_denied':
native = replace(native, lateralAllowed=False)
elif restriction == 'no_cancel':
state.buttonEvents = []
assert physical_cancel_lateral_allowed(cp, state, intent, native, settings=settings, previous=previous,
source_ns=source, now_ns=now, axis_session_id='angle-session') == (restriction == 'none')