mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-05 03:54:04 +08:00
Keep Mazda source handoffs within the original control lease
This commit is contained in:
@@ -829,8 +829,10 @@ class SelfdriveD:
|
||||
def source_deadline_deferral_supported(self):
|
||||
from openpilot.starpilot.car.hyundai.aol import source_deadline_supported
|
||||
from openpilot.starpilot.car.toyota.aol import qualified as qualified_toyota
|
||||
from opendbc.car.mazda.stock_aol import qualified as qualified_mazda
|
||||
return (qualified_ioniq6(self.CP) or qualified_gm(self.CP) or source_deadline_supported(self.CP) or
|
||||
qualified_toyota(self.CP, marked_only=True) or self.ford_source_deadline_supported())
|
||||
qualified_toyota(self.CP, marked_only=True) or qualified_mazda(self.CP, marked_only=True) or
|
||||
self.ford_source_deadline_supported())
|
||||
|
||||
def held_axis_override_wait(self, CS, proof, now_ns, *, fresh_successor=False):
|
||||
"""Recognize an already applied override; never admit a new physical edge."""
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
"""Recorded Mazda source cutoff; real SD/Controls, synthetic clocks and transport."""
|
||||
from contextlib import ExitStack
|
||||
from dataclasses import replace
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from opendbc.car import gen_empty_fingerprint
|
||||
from opendbc.car.mazda.interface import CarInterface
|
||||
from opendbc.car.mazda.values import CAR
|
||||
from openpilot.cereal import log
|
||||
from openpilot.common.prefix import OpenpilotPrefix
|
||||
from openpilot.starpilot.aol.tests import test_ioniq_availability as fixture
|
||||
from openpilot.starpilot.aol.tests.test_input_deadline_continuity import BASE, intent
|
||||
from openpilot.starpilot.aol.wire import decode_intent, encode_intent
|
||||
|
||||
|
||||
@pytest.mark.parametrize('identity', (CAR.MAZDA_CX5_2022, CAR.MAZDA_CX9_2021))
|
||||
@pytest.mark.parametrize('condition', ('healthy', 'deadline', 'native_denied', 'cancel', 'brake', 'main_off',
|
||||
'eps_fault', 'invalid_can', 'producer', 'pause', 'repeated'))
|
||||
def test_mazda_source_cutoff_preserves_only_original_command_lease(identity, condition):
|
||||
with OpenpilotPrefix(), ExitStack() as cleanup:
|
||||
case = fixture.IoniqAvailabilityTests(methodName='runTest')
|
||||
cleanup.callback(case.doCleanups)
|
||||
cp = CarInterface.get_params(identity, gen_empty_fingerprint(), [], False, False, False)
|
||||
sd, controls, drive = case._authority_callers(True, cp=cp, genuine_events=True)
|
||||
state = fixture.car_state()
|
||||
state.cruiseState.available = state.cruiseState.enabled = True
|
||||
drive(0, observed_state=state, native_request_long=False, long_allowed=False, panda_controls_allowed=True)
|
||||
old, _, command = drive(2, state_stamp=BASE, offset_ns=4_237_448,
|
||||
intent_message=intent(BASE, 3), observed_state=state, native_request_long=False, long_allowed=False, panda_controls_allowed=True)
|
||||
assert old.lateralActive and command.latActive and not command.longActive
|
||||
original = sd.pm.messages['aolAxisState'].as_builder().to_bytes()
|
||||
now = BASE + 30_453_437
|
||||
sd.aol_step_input_proof = sd.aol_published_input_proof
|
||||
sd.aol_step_deferral_checked = False
|
||||
sd.aol_step_intent_drain_count = 0
|
||||
sd.aol_step_intent_drain_ok = True
|
||||
if condition == 'deadline':
|
||||
now = old.validUntilMonoTime
|
||||
elif condition == 'native_denied':
|
||||
sd.sm.valid['aolSafetyWire'] = False
|
||||
elif condition == 'cancel':
|
||||
sd.events.add(log.OnroadEvent.EventName.buttonCancel)
|
||||
elif condition == 'brake':
|
||||
state.brakePressed = True
|
||||
elif condition == 'main_off':
|
||||
state.cruiseState.available = False
|
||||
state.cruiseState.enabled = False
|
||||
sd.events.add(log.OnroadEvent.EventName.wrongCarMode)
|
||||
elif condition == 'eps_fault':
|
||||
state.steerFaultPermanent = True
|
||||
elif condition == 'invalid_can':
|
||||
state.canValid = False
|
||||
elif condition in ('producer', 'pause'):
|
||||
message = intent(BASE + 29_000_000, 4)
|
||||
value = decode_intent(message.aolIntentWire)
|
||||
message.aolIntentWire = encode_intent(replace(value, **(
|
||||
{'producerSessionId': 'different-card'} if condition == 'producer' else {'pauseLateral': True})))
|
||||
sd.aol_intent_companion._observe(message.logMonoTime, message.valid, message.aolIntentWire)
|
||||
elif condition == 'repeated':
|
||||
sd.aol_step_deferral_checked = True
|
||||
initial = (sd.state_machine.state, sd.state_machine.soft_disable_timer, sd.enabled, sd.active)
|
||||
sd.car_state_samples = ((state.as_reader(), True),)
|
||||
with mock.patch('openpilot.selfdrive.selfdrived.selfdrived.time.monotonic_ns', return_value=now):
|
||||
deferred = sd.defer_expired_axis_publication(state, initial, now_ns=now)
|
||||
assert deferred == (condition == 'healthy')
|
||||
assert sd.pm.messages['aolAxisState'].as_builder().to_bytes() == original
|
||||
assert old.sourceCarStateMonoTime == BASE
|
||||
assert old.validUntilMonoTime == BASE + 34_237_448
|
||||
# Every consumer still withdraws at the original absolute deadline.
|
||||
with mock.patch('openpilot.selfdrive.controls.controlsd.time.monotonic_ns', return_value=old.validUntilMonoTime + 1):
|
||||
expired, _ = controls.state_control()
|
||||
assert not expired.latActive and not expired.longActive
|
||||
if condition == 'healthy':
|
||||
fresh = BASE + 27_821_823
|
||||
axis, _, command = drive(6, state_stamp=fresh, offset_ns=-7_000_000,
|
||||
intent_message=intent(fresh, 4), observed_state=state, native_request_long=False, long_allowed=False, panda_controls_allowed=True)
|
||||
assert axis.sourceCarStateMonoTime == fresh and axis.lateralActive and command.latActive
|
||||
assert not command.longActive
|
||||
assert log.OnroadEvent.EventName.commIssue not in sd.events.names
|
||||
assert log.OnroadEvent.EventName.controlsMismatch not in sd.events.names
|
||||
|
||||
|
||||
@pytest.mark.parametrize('identity', (CAR.MAZDA_CX5_2022, CAR.MAZDA_CX9_2021))
|
||||
def test_mazda_actual_step_defers_warning_then_consumes_fresh_successor(identity):
|
||||
with OpenpilotPrefix(), ExitStack() as cleanup:
|
||||
case = fixture.IoniqAvailabilityTests(methodName='runTest')
|
||||
cleanup.callback(case.doCleanups)
|
||||
cp = CarInterface.get_params(identity, gen_empty_fingerprint(), [], False, False, False)
|
||||
sd, controls, drive = case._authority_callers(True, cp=cp, genuine_events=True)
|
||||
state = fixture.car_state()
|
||||
state.cruiseState.available = state.cruiseState.enabled = True
|
||||
options = {'observed_state': state, 'native_request_long': False,
|
||||
'long_allowed': False, 'panda_controls_allowed': True}
|
||||
drive(0, **options)
|
||||
old, _, command = drive(2, state_stamp=BASE, offset_ns=4_237_448,
|
||||
intent_message=intent(BASE, 3), **options)
|
||||
assert old.lateralActive and command.latActive
|
||||
original = sd.pm.messages['aolAxisState'].as_builder().to_bytes()
|
||||
now = [BASE + 29_900_000]
|
||||
actual_events = sd.update_events
|
||||
|
||||
def events(cs):
|
||||
result = actual_events(cs)
|
||||
now[0] = BASE + 30_453_437
|
||||
return result
|
||||
|
||||
with mock.patch('openpilot.selfdrive.selfdrived.selfdrived.time.monotonic_ns', side_effect=lambda: now[0]), \
|
||||
mock.patch.object(sd, 'update_events', side_effect=events):
|
||||
axis, _, command = drive(5, timeout=True, offset_ns=-100_000,
|
||||
intent_message=intent(BASE, 3), **options)
|
||||
assert sd.aol_axis_publication_deferred
|
||||
assert sd.pm.messages['aolAxisState'].as_builder().to_bytes() == original
|
||||
assert command.latActive and not command.longActive
|
||||
assert log.OnroadEvent.EventName.commIssue not in sd.events.names
|
||||
assert log.OnroadEvent.EventName.controlsMismatch not in sd.events.names
|
||||
with mock.patch('openpilot.selfdrive.controls.controlsd.time.monotonic_ns', return_value=old.validUntilMonoTime + 1):
|
||||
expired, _ = controls.state_control()
|
||||
assert not expired.latActive and not expired.longActive
|
||||
fresh = BASE + 27_821_823
|
||||
axis, _, command = drive(6, state_stamp=fresh, offset_ns=-7_000_000,
|
||||
intent_message=intent(fresh, 4), **options)
|
||||
assert axis.sourceCarStateMonoTime == fresh and axis.lateralActive and command.latActive
|
||||
assert not command.longActive
|
||||
assert log.OnroadEvent.EventName.commIssue not in sd.events.names
|
||||
assert log.OnroadEvent.EventName.controlsMismatch not in sd.events.names
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"protected_inventory_sha256": "b1d97b7008d6b691c0ab1be89789b81b3a68217e1dfaa48c1bccdaef6532ae30", "schema_version": 1}
|
||||
{"protected_inventory_sha256": "3c88c96a3d4067ed5c4cb263e809b67c05ac819dd274f40c42af5c974c0998d2", "schema_version": 1}
|
||||
|
||||
@@ -39,6 +39,7 @@ FORD_BLUEPILOT_NATIVE_TARGETS = tuple(str(path.relative_to(ROOT)) for path in so
|
||||
# Representative production callers plus their source/native refusal cases.
|
||||
# The emitted selected_test_ids record exact parametrized configurations.
|
||||
AOL_LIFECYCLE_TARGETS = (
|
||||
'openpilot/starpilot/aol/tests/test_mazda_source_deadline.py',
|
||||
"openpilot/starpilot/aol/tests/test_gv60_hda1_alpha_aol.py",
|
||||
"opendbc_repo/opendbc/car/hyundai/tests/test_torque_ev_deferred_takeover.py",
|
||||
'openpilot/starpilot/aol/tests/test_hkg_early_long_withdrawal.py',
|
||||
|
||||
Reference in New Issue
Block a user