Files
StarPilot/starpilot/common/tests/test_screen_device_runtime.py
T

220 lines
9.4 KiB
Python

"""Run the real Device class without opening a display or native IPC sockets."""
import ast
from collections.abc import Callable
from enum import Enum
from pathlib import Path
from types import SimpleNamespace
import numpy as np
import pytest
from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.starpilot.common import screen_settings as screen
class Params:
def __init__(self, values):
self.values = values
def get(self, key):
return self.values.get(key)
def get_int(self, key, **kwargs):
return int(self.values.get(key, 101 if 'Brightness' in key else 30))
def get_bool(self, key):
return bool(self.values.get(key, False))
class Messages(dict):
def __init__(self):
super().__init__(selfdriveState=SimpleNamespace(enabled=False, alertSize='none', alertStatus='normal'),
starpilotSelfdriveState=SimpleNamespace(alertSize='none', alertStatus='normal'),
carState=SimpleNamespace(leftBlinker=False, rightBlinker=False, brakePressed=False, gasPressed=False,
gearShifter='drive', buttonEvents=[]))
self.updated = dict.fromkeys(self, True)
self.recv_frame = dict.fromkeys(self, 1)
self.recv_time = dict.fromkeys(self, 100)
self.logMonoTime = dict.fromkeys(self, 1)
self.valid = dict.fromkeys(self, True)
self.alive = dict.fromkeys(self, True)
def make_device(*, device_type="tici", **settings):
status = Enum('UIStatus', 'DISENGAGED ENGAGED OVERRIDE')
state = SimpleNamespace(started=True, ignition=True, status=status.DISENGAGED, light_sensor=-1, started_time=0, started_frame=0, starpilot_toggles={},
params_memory=Params({}), ui_params=Params({'ScreenManagement': True, 'ScreenBrightness': 101,
'ScreenBrightnessOnroad': 101, 'StandbyMode': True, **settings}), sm=Messages())
app = SimpleNamespace(target_fps=20, big_ui=lambda: False, mouse_events=[], set_should_render=lambda value: None)
env = {**vars(screen), 'ui_state': state, 'gui_app': app, 'UIStatus': status, 'BACKLIGHT_OFFROAD': 65,
'np': np, 'time': SimpleNamespace(monotonic=lambda: 100), 'FirstOrderFilter': FirstOrderFilter,
'Callable': Callable, 'HARDWARE': SimpleNamespace(set_display_power=lambda value: None, get_device_type=lambda: device_type),
'cloudlog': SimpleNamespace(debug=lambda value: None), 'PC': False, 'TICI': True}
source = Path(__file__).resolve().parents[3] / 'selfdrive/ui/ui_state.py'
node = next(n for n in ast.parse(source.read_text()).body if isinstance(n, ast.ClassDef) and n.name == 'Device')
exec(compile(ast.Module(body=[node], type_ignores=[]), str(source), 'exec'), env)
device = env['Device']()
device._brightness_filter = SimpleNamespace(update=lambda value: value)
device._ignition = True
device._interaction_time = 90
return device, state, app
def test_driving_and_parked_offsets_apply_independently():
device, state, _ = make_device(StandbyMode=False, ScreenBrightnessOffset=-20, ScreenBrightnessOnroadOffset=15)
assert device._calculate_brightness() == 75
state.started = False
assert device._calculate_brightness() == 52
def test_offset_is_ignored_in_manual_and_when_screen_settings_disabled():
device, _, _ = make_device(StandbyMode=False, ScreenBrightnessOnroad=22, ScreenBrightnessOnroadOffset=50)
assert device._calculate_brightness() == 22
device._params.values['ScreenManagement'] = False
device._refresh_screen_settings(force=True)
assert device._calculate_brightness() == 65
def test_parked_zero_can_be_woken_by_touch_then_times_out_without_standby():
device, state, app = make_device(StandbyMode=False, ScreenBrightness=0)
state.started = state.ignition = device._ignition = False
assert device._calculate_brightness() == 0
app.mouse_events = [SimpleNamespace(left_down=True)]
device._update_wakefulness()
assert device._calculate_brightness() == 5
app.mouse_events = []
device._interaction_time = 90
device._update_wakefulness()
assert not device.awake
assert device._calculate_brightness() == 0
@pytest.mark.parametrize('key,field,value', [
('StandbyWakeInfoAlert', 'alertSize', 'small'),
('StandbyWakeWarningAlert', 'alertStatus', 'userPrompt'),
('StandbyWakeCriticalAlert', 'alertStatus', 'critical'),
])
def test_only_selected_alert_categories_wake(key, field, value):
settings = dict.fromkeys(screen.SCREEN_WAKE_KEYS, False)
device, state, _ = make_device(**settings)
state.sm['selfdriveState'].alertSize = 'small'
setattr(state.sm['selfdriveState'], field, value)
device._update_wakefulness()
assert device._calculate_brightness() == 0
device._params.values[key] = True
device._refresh_screen_settings(force=True)
device._interaction_time = 90
device._update_wakefulness()
assert device._calculate_brightness() == 65
@pytest.mark.parametrize('key,field', [
('StandbyWakeTurnSignal', 'leftBlinker'),
])
def test_selected_driver_input_wakes_once_and_can_sleep_while_held(key, field):
device, state, _ = make_device(**dict.fromkeys(screen.SCREEN_WAKE_KEYS, False))
device._params.values[key] = True
device._refresh_screen_settings(force=True)
device._update_wakefulness()
setattr(state.sm['carState'], field, True)
device._update_wakefulness()
assert device._calculate_brightness() == 65
device._interaction_time = 90
device._update_wakefulness()
assert device._calculate_brightness() == 0
def test_runtime_limits_legacy_offsets_to_thirty_percent():
device, state, _ = make_device(StandbyMode=False, ScreenBrightnessOffset=-100, ScreenBrightnessOnroadOffset=-100)
assert device._calculate_brightness() == 46
state.started = False
assert device._calculate_brightness() == 46
@pytest.mark.parametrize('key', sorted(screen.SCREEN_WAKE_KEYS))
@pytest.mark.parametrize('selected', [False, True])
def test_every_wake_choice_controls_its_own_event(key, selected):
settings = dict.fromkeys(screen.SCREEN_WAKE_KEYS, False)
settings[key] = selected
device, state, app = make_device(**settings)
device._update_wakefulness() # Seed signals; startup is not a driver event.
if key == 'StandbyWakeEngage':
state.sm['selfdriveState'].enabled = True
state.status = type(state.status).ENGAGED
elif key == 'StandbyWakeDisengage':
state.sm['selfdriveState'].enabled = True
state.status = type(state.status).ENGAGED
device._update_wakefulness()
state.sm['selfdriveState'].enabled = False
state.status = type(state.status).DISENGAGED
elif key.endswith('Alert'):
alert = state.sm['selfdriveState']
alert.alertSize = 'small'
alert.alertStatus = {'StandbyWakeInfoAlert': 'normal', 'StandbyWakeWarningAlert': 'userPrompt', 'StandbyWakeCriticalAlert': 'critical'}[key]
elif key == 'StandbyWakeButton':
state.params_memory.values['StandbyButtonPressTime'] = 99_500_000_000
elif key == 'StandbyWakeTurnSignal':
state.sm['carState'].leftBlinker = True
else:
pytest.fail('No stimulus for wake option ' + key)
device._interaction_time = 90
device._update_wakefulness()
assert (device._calculate_brightness() > 0) is selected
def test_external_button_press_is_fresh_and_consumed_once():
settings = dict.fromkeys(screen.SCREEN_WAKE_KEYS, False)
settings['StandbyWakeButton'] = True
device, state, _ = make_device(**settings)
device._update_wakefulness()
state.params_memory.values['StandbyButtonPressTime'] = 99_500_000_000
device._update_wakefulness()
assert (device._calculate_brightness() > 0) is True
device._interaction_time = 90
device._update_wakefulness()
assert device._calculate_brightness() == 0
state.params_memory.values['StandbyButtonPressTime'] = 95_000_000_000
device._update_wakefulness()
assert device._calculate_brightness() == 0
def test_consumed_button_press_is_not_replayed_between_ui_frames():
device, state, _ = make_device(StandbyWakeButton=True)
device._update_wakefulness()
state.params_memory.values['StandbyButtonPressTime'] = 99_500_000_000
device._update_wakefulness()
assert device._calculate_brightness() > 0
device._interaction_time = 90
device._update_wakefulness()
assert device._calculate_brightness() == 0
def test_hidden_secondary_alert_does_not_bypass_primary_category_selection():
settings = dict.fromkeys(screen.SCREEN_WAKE_KEYS, False)
settings['StandbyWakeInfoAlert'] = True
device, state, _ = make_device(**settings)
state.sm['selfdriveState'].alertStatus = 'critical'
state.sm['selfdriveState'].alertSize = 'full'
state.sm['starpilotSelfdriveState'].alertSize = 'small'
device._update_wakefulness()
assert device._active_standby_alerts() == {'StandbyWakeCriticalAlert'}
assert device._calculate_brightness() == 0
@pytest.mark.parametrize('device_type', ['tici', 'mici'])
def test_dom_alert_predicate_does_not_depend_on_renderer_hide_setting(device_type):
device, state, _ = make_device(device_type=device_type)
state.starpilot_toggles['hide_alerts'] = True
state.sm['selfdriveState'].alertSize = 'small'
device._update_wakefulness()
assert (device._calculate_brightness() > 0) is True
def test_bluetooth_wake_during_ignition_only_standby():
settings = dict.fromkeys(screen.SCREEN_WAKE_KEYS, False)
settings["StandbyWakeButton"] = True
device, state, _ = make_device(**settings)
state.started = False
state.ignition = device._ignition = True
device._update_wakefulness()
state.params_memory.values['StandbyButtonPressTime'] = 99_500_000_000
device._update_wakefulness()
assert (device._calculate_brightness() > 0) is True