mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-08 05:23:41 +08:00
136 lines
5.7 KiB
Python
136 lines
5.7 KiB
Python
from types import SimpleNamespace as NS
|
|
|
|
import pytest
|
|
|
|
from opendbc.car.structs import car
|
|
from openpilot.cereal import messaging
|
|
from openpilot.common.params import Params
|
|
from openpilot.selfdrive.car.card import Car
|
|
from openpilot.selfdrive.car.tests.publication_fixture import initialize_publication_sources
|
|
from openpilot.selfdrive.car.cruise import CRUISE_LONG_PRESS, VCruiseHelper
|
|
from openpilot.selfdrive.car.tests.test_hyundai_aol import candidate
|
|
from openpilot.starpilot.controllers.wheel_actions import ACTIONS, KEYS, WheelConsumer, WheelPublisher, capture
|
|
|
|
|
|
TYPE = car.CarState.ButtonEvent.Type
|
|
DRIVE = 1_000_000_000
|
|
NOW = DRIVE + 2_000_000_000
|
|
|
|
|
|
def state(*pressed, button=TYPE.gapAdjustCruise):
|
|
return car.CarState(canValid=True, buttonEvents=[car.CarState.ButtonEvent(type=button, pressed=value) for value in pressed])
|
|
|
|
|
|
class Publisher:
|
|
def __init__(self):
|
|
self.events = []
|
|
|
|
def send(self, service, event):
|
|
self.events.append((service, event.to_bytes()))
|
|
|
|
|
|
def services(cp, now=NOW):
|
|
names = ('deviceState', 'carState', 'carControl')
|
|
data = {'deviceState': NS(started=True, startedMonoTime=DRIVE), 'carState': state(),
|
|
'carControl': car.CarControl(enabled=True, longActive=True)}
|
|
class Services(dict):
|
|
pass
|
|
sm = Services(data)
|
|
sm.logMonoTime = dict.fromkeys(names, now)
|
|
sm.recv_time = dict.fromkeys(names, now / 1e9)
|
|
sm.seen = sm.alive = sm.valid = dict.fromkeys(names, True)
|
|
sm.frame = 1
|
|
sm.all_checks = lambda _: True
|
|
return sm
|
|
|
|
|
|
@pytest.fixture
|
|
def context(tmp_path):
|
|
params = Params(str(tmp_path))
|
|
_, cp = candidate(False)
|
|
return params, cp
|
|
|
|
|
|
def test_exact_catalog_and_missing_vs_saved_off(context):
|
|
params, _ = context
|
|
assert sorted(ACTIONS.values()) == list(range(15))
|
|
assert len(KEYS) == 15
|
|
assert capture(params)['DistanceButtonControl'] == 1
|
|
assert capture(params)['LongDistanceButtonControl'] == 5
|
|
assert capture(params)['VeryLongDistanceButtonControl'] == 6
|
|
params.put('DistanceButtonControl', 0, block=True)
|
|
assert capture(params)['DistanceButtonControl'] == 0
|
|
|
|
|
|
@pytest.mark.parametrize('key,code', [('DistanceButtonControl', code) for code in (1, 2, 5, 6, 7, 8, 11, 12, 13, 14)])
|
|
def test_real_distance_short_delivers_once_and_claims_serialized_release(context, key, code):
|
|
params, cp = context
|
|
params.put(key, code, block=True)
|
|
owner = WheelPublisher()
|
|
owner.observe(params, cp, state(), now_ns=NOW, drive_id=DRIVE)
|
|
assert not any(action for _, action in owner.observe(params, cp, state(True), now_ns=NOW + 10_000_000, drive_id=DRIVE))
|
|
commands = owner.observe(params, cp, state(False), now_ns=NOW + 20_000_000, drive_id=DRIVE)
|
|
assert commands == ((key, code),)
|
|
assert owner.suppress_distance_release
|
|
assert not any(action for _, action in owner.observe(params, cp, state(), now_ns=NOW + 30_000_000, drive_id=DRIVE))
|
|
|
|
|
|
def test_held_long_then_very_long_exactly_once_no_short_release(context):
|
|
params, cp = context
|
|
owner = WheelPublisher()
|
|
owner.observe(params, cp, state(), now_ns=NOW, drive_id=DRIVE)
|
|
observed = []
|
|
for frame in range(1, CRUISE_LONG_PRESS * 5 + 3):
|
|
commands = owner.observe(params, cp, state(True) if frame == 1 else state(),
|
|
now_ns=NOW + frame * 10_000_000, drive_id=DRIVE)
|
|
observed.extend((frame, key, action) for key, action in commands if action)
|
|
assert observed == [(CRUISE_LONG_PRESS, 'LongDistanceButtonControl', 5),
|
|
(CRUISE_LONG_PRESS * 5, 'VeryLongDistanceButtonControl', 6)]
|
|
assert not any(action for _, action in owner.observe(params, cp, state(False),
|
|
now_ns=NOW + (CRUISE_LONG_PRESS * 5 + 4) * 10_000_000, drive_id=DRIVE))
|
|
|
|
|
|
def test_published_receipt_exact_cp_session_replay_and_delayed_source(context):
|
|
params, cp = context
|
|
params.put('DistanceButtonControl', 8, block=True)
|
|
publisher = Publisher()
|
|
owner = WheelPublisher()
|
|
owner.publish((('DistanceButtonControl', 8),), cp, publisher, now_ns=NOW, drive_id=DRIVE,
|
|
source_car_ns=NOW, source_control_ns=NOW)
|
|
event = messaging.log_from_bytes(publisher.events[0][1])
|
|
sm = services(cp)
|
|
consumer = WheelConsumer()
|
|
assert consumer.accept(event, params, cp, sm, now_ns=NOW).action == 8
|
|
assert consumer.accept(event, params, cp, sm, now_ns=NOW) is None
|
|
changed = cp.as_reader().as_builder()
|
|
changed.pcmCruise = not cp.pcmCruise
|
|
assert WheelConsumer().accept(event, params, changed.as_reader(), sm, now_ns=NOW) is None
|
|
sm.recv_time['carState'] = (NOW - 300_000_000) / 1e9
|
|
assert WheelConsumer().accept(event, params, cp, sm, now_ns=NOW) is None
|
|
|
|
|
|
def test_actual_card_published_distance_off_cannot_trigger_unconditional_personality(context):
|
|
params, cp = context
|
|
params.put('DistanceButtonControl', 0, block=True)
|
|
owner = WheelPublisher()
|
|
sm = services(cp)
|
|
owner.observe(params, cp, state(), now_ns=NOW, drive_id=DRIVE)
|
|
owner.observe(params, cp, state(True), now_ns=NOW + 10_000_000, drive_id=DRIVE)
|
|
physical = state(False)
|
|
commands = owner.observe(params, cp, physical, now_ns=NOW + 20_000_000, drive_id=DRIVE)
|
|
instance = Car.__new__(Car)
|
|
instance.CP, instance.params, instance.sm = cp, params, sm
|
|
vars(instance)['pm'] = Publisher()
|
|
instance.wheel_publisher, instance.wheel_commands = owner, commands
|
|
instance.slc_replay = instance.curve_replay = instance.conditional_replay = instance.aol_replay = False
|
|
instance.last_actuators_output = car.CarControl.Actuators()
|
|
instance.can_rcv_cum_timeout_counter = 0
|
|
vars(instance)['rk'] = NS(remaining=0.0)
|
|
instance.v_cruise_helper = VCruiseHelper(cp)
|
|
instance.slc_receipts = []
|
|
initialize_publication_sources(instance)
|
|
instance.state_publish(physical, None)
|
|
serialized = next(messaging.log_from_bytes(raw).carState for name, raw in instance.pm.events if name == 'carState')
|
|
assert len(serialized.buttonEvents) == 0
|
|
assert len(physical.buttonEvents) == 1
|