mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-11-08 05:23:41 +08:00
a82935f326
Integrate onroad views, configurable widgets, local settings, steering-profile contracts, Bluetooth and Android Auto with their device and runtime services. Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com> Co-authored-by: Daniel Koepping <elkoled@gmail.com> Co-authored-by: Danny <dannyirwin31@yahoo.com> Co-authored-by: DimitriChrysafis <Dimitri.chrysafis@gmail.com> Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com> Co-authored-by: Harald Schäfer <harald.the.engineer@gmail.com> Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu> Co-authored-by: Shane Smiskol <shane@smiskol.com> Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com> Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com> Co-authored-by: stef <19478336+stefpi@users.noreply.github.com> Co-authored-by: whoisdomi <dcantu83@gmail.com> Co-authored-by: Intelli <contact@intelli.software> Co-authored-by: pharmacomaniac <blittle65@gmail.com> Co-authored-by: prabhaavp <prabhaav@msu.edu>
188 lines
9.5 KiB
Python
188 lines
9.5 KiB
Python
"""Real disposable Params tests for the six saved Ioniq media assignments."""
|
|
|
|
from pathlib import Path
|
|
import tempfile
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from opendbc.car.car_helpers import interfaces
|
|
from opendbc.car.hyundai.values import CAR, HyundaiFlags
|
|
from openpilot.common.params import Params
|
|
from openpilot.starpilot.conditional_mode.button_actions import (
|
|
CONFIG_KEY, MEDIA_KEYS, RUNTIME_KEYS, SAFE_KEY, capture_sources, commit_assignment,
|
|
display_action, media_capability, runtime_map_ready,
|
|
)
|
|
from openpilot.starpilot.conditional_mode.manual import read_button_map
|
|
from openpilot.starpilot.saved_source import read_saved
|
|
|
|
|
|
def qualified_cp():
|
|
cp = interfaces[CAR.HYUNDAI_IONIQ_6].get_non_essential_params(CAR.HYUNDAI_IONIQ_6)
|
|
cp.flags = int(cp.flags | HyundaiFlags.CANFD_LKA_STEER_MSG)
|
|
cp.openpilotLongitudinalControl = True
|
|
return cp
|
|
|
|
|
|
class ButtonActionsTests(unittest.TestCase):
|
|
def setUp(self):
|
|
temporary = tempfile.TemporaryDirectory()
|
|
self.addCleanup(temporary.cleanup)
|
|
self.params = Params(temporary.name)
|
|
self.parked = True
|
|
self.cp = qualified_cp()
|
|
|
|
def snapshot(self):
|
|
config, _ = read_saved(self.params, CONFIG_KEY, 4096)
|
|
safe, _ = read_saved(self.params, SAFE_KEY, 8)
|
|
return capture_sources(self.params, config, safe)
|
|
|
|
def write(self, key, choice, sources=None):
|
|
sources = sources or self.snapshot()
|
|
cp = media_capability(self.cp)
|
|
return commit_assignment(self.params, key=key, choice=choice, expected=sources.raw(key),
|
|
dependencies=sources.dependencies,
|
|
authorized=lambda: self.parked and cp is not None and media_capability(self.cp) == cp)
|
|
|
|
def test_exact_platform_and_all_six_real_saved_actions(self):
|
|
self.assertIsNotNone(media_capability(self.cp))
|
|
wrong = qualified_cp()
|
|
wrong.flags = int(wrong.flags & ~HyundaiFlags.CANFD_LKA_STEER_MSG)
|
|
self.assertIsNone(media_capability(wrong))
|
|
wrong = qualified_cp()
|
|
wrong.passive = True
|
|
self.assertIsNone(media_capability(wrong))
|
|
self.assertTrue(runtime_map_ready(self.snapshot()))
|
|
for key in MEDIA_KEYS:
|
|
with self.subTest(key=key):
|
|
self.assertTrue(self.write(key, "Cycle conditional mode").verified)
|
|
self.assertEqual(read_saved(self.params, key, 8), (b"5", True))
|
|
self.assertEqual(getattr(read_button_map(self.params, include_ioniq_media=True),
|
|
{"ModeButtonControl": "mode", "LongModeButtonControl": "mode_long",
|
|
"VeryLongModeButtonControl": "mode_very_long", "StarButtonControl": "custom",
|
|
"LongStarButtonControl": "custom_long",
|
|
"VeryLongStarButtonControl": "custom_very_long"}[key]), 5)
|
|
self.assertTrue(self.write(key, "Off").verified)
|
|
self.assertEqual(read_saved(self.params, key, 8), (b"0", True))
|
|
self.assertTrue(self.write(key, "Toggle traffic mode").verified)
|
|
self.assertEqual(read_saved(self.params, key, 8), (b"6", True))
|
|
self.assertEqual(display_action(b"6")[:2], ("Toggle traffic mode", ("Off", "Cycle conditional mode", "Toggle traffic mode", "Switchback Mode")))
|
|
self.assertTrue(self.write(key, "Off").verified)
|
|
|
|
def test_corrupt_or_unsupported_saved_value_requires_explicit_repair(self):
|
|
key = MEDIA_KEYS[0]
|
|
Path(self.params.get_param_path(key)).write_bytes(b"05")
|
|
self.assertEqual(display_action(self.snapshot().raw(key)), ("Unsupported saved action", (), "Off"))
|
|
self.assertFalse(self.write(key, "Cycle conditional mode").committed)
|
|
self.assertTrue(self.write(key, "Off").verified)
|
|
Path(self.params.get_param_path(key)).write_bytes(b"14")
|
|
self.assertEqual(display_action(self.snapshot().raw(key))[2], "Off")
|
|
self.assertFalse(self.write(key, "Cycle conditional mode").committed)
|
|
self.assertTrue(self.write(key, "Off").verified)
|
|
self.assertFalse(self.write(key, "Pause longitudinal").committed)
|
|
self.assertFalse(self.write("CancelButtonControl", "Off").committed)
|
|
|
|
def test_invalid_saved_config_or_safe_mode_cannot_bypass_page(self):
|
|
key = MEDIA_KEYS[0]
|
|
Path(self.params.get_param_path(CONFIG_KEY)).write_bytes(b'{"version":9}')
|
|
self.assertFalse(self.write(key, "Off").committed)
|
|
self.assertFalse(self.write(key, "Cycle conditional mode").committed)
|
|
Path(self.params.get_param_path(CONFIG_KEY)).unlink()
|
|
Path(self.params.get_param_path(SAFE_KEY)).write_bytes(b"yes")
|
|
self.assertFalse(self.write(key, "Off").committed)
|
|
|
|
def test_exact_sources_parked_cp_and_cancel_dependency(self):
|
|
key = MEDIA_KEYS[0]
|
|
captured = self.snapshot()
|
|
Path(self.params.get_param_path("LongStarButtonControl")).write_bytes(b"5")
|
|
self.assertFalse(self.write(key, "Cycle conditional mode", captured).committed)
|
|
self.assertIsNone(read_saved(self.params, key, 8)[0])
|
|
captured = self.snapshot()
|
|
Path(self.params.get_param_path("CancelButtonControl")).write_bytes(b"5")
|
|
self.assertFalse(runtime_map_ready(self.snapshot()))
|
|
self.assertIsNone(read_button_map(self.params, include_ioniq_media=True))
|
|
self.assertFalse(self.write(key, "Cycle conditional mode", captured).committed)
|
|
captured = self.snapshot()
|
|
self.params.put_bool(SAFE_KEY, True, block=True)
|
|
self.assertFalse(self.write(key, "Cycle conditional mode", captured).committed)
|
|
self.parked = False
|
|
self.assertFalse(self.write(key, "Cycle conditional mode").committed)
|
|
self.parked = True
|
|
self.cp.flags = int(self.cp.flags & ~HyundaiFlags.CANFD_LKA_STEER_MSG)
|
|
self.assertFalse(self.write(key, "Cycle conditional mode").committed)
|
|
|
|
def test_unreadable_source_and_commit_uncertainty(self):
|
|
key = MEDIA_KEYS[0]
|
|
path = Path(self.params.get_param_path(key))
|
|
path.write_bytes(b"5" * 9)
|
|
self.assertFalse(self.snapshot().readable)
|
|
self.assertFalse(self.write(key, "Off").committed)
|
|
self.assertEqual(path.read_bytes(), b"5" * 9)
|
|
path.write_bytes(b"0")
|
|
from openpilot.starpilot import saved_document
|
|
with patch.object(saved_document.os, "fsync", side_effect=[None, OSError("post-rename failure")]):
|
|
result = self.write(key, "Cycle conditional mode")
|
|
self.assertTrue(result.committed)
|
|
self.assertFalse(result.verified)
|
|
self.assertEqual(path.read_bytes(), b"5")
|
|
|
|
def test_all_dependencies_captured_once_and_nonregular_source(self):
|
|
sources = self.snapshot()
|
|
self.assertEqual(tuple(name for name, _ in sources.dependencies), (CONFIG_KEY, SAFE_KEY, *RUNTIME_KEYS))
|
|
key = MEDIA_KEYS[0]
|
|
Path(self.params.get_param_path(key)).mkdir()
|
|
self.assertFalse(self.snapshot().readable)
|
|
self.assertFalse(self.write(key, "Cycle conditional mode").committed)
|
|
|
|
def test_stage_to_lock_rechecks_parked_cp_and_config(self):
|
|
from openpilot.starpilot import saved_document
|
|
key = MEDIA_KEYS[0]
|
|
original_fsync = saved_document.os.fsync
|
|
for change in ("parked", "cp", "config"):
|
|
with self.subTest(change=change):
|
|
self.parked = True
|
|
self.cp = qualified_cp()
|
|
config_path = Path(self.params.get_param_path(CONFIG_KEY))
|
|
config_path.unlink(missing_ok=True)
|
|
def change_at_stage(fd, scenario=change, path=config_path):
|
|
result = original_fsync(fd)
|
|
if scenario == "parked":
|
|
self.parked = False
|
|
elif scenario == "cp":
|
|
self.cp.flags = int(self.cp.flags & ~HyundaiFlags.CANFD_LKA_STEER_MSG)
|
|
else:
|
|
path.write_bytes(b'{"version":9}')
|
|
return result
|
|
with patch.object(saved_document.os, "fsync", side_effect=change_at_stage):
|
|
self.assertFalse(self.write(key, "Cycle conditional mode").committed)
|
|
self.assertFalse(Path(self.params.get_param_path(key)).exists())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|
|
|
|
|
|
def test_gm_distance_configuration_is_exact_and_preserves_other_actions(tmp_path):
|
|
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
|
|
from openpilot.starpilot.conditional_mode.button_actions import distance_capability
|
|
from openpilot.starpilot.ui.feature_settings_owner import FeatureSettingsOwner
|
|
from openpilot.starpilot.ui.feature_settings_state import FeaturePage
|
|
params = Params(str(tmp_path))
|
|
for cp in [*(pedal_params(car, setting=True, pedal=True) for car in PEDAL_BOLT_CAR),
|
|
ascm_params(CAR.CHEVROLET_BOLT_EUV, alpha=True), ascm_params(CAR.CHEVROLET_VOLT, radar=True),
|
|
ascm_params(CAR.CHEVROLET_VOLT_ASCM, sascm=True, alpha=True)]:
|
|
assert distance_capability(cp) is not None
|
|
owner = FeatureSettingsOwner(params, lambda group: True, vehicle_fingerprint=lambda cp=cp: cp.carFingerprint, vehicle_params=lambda cp=cp: cp)
|
|
rows = owner.snapshot(FeaturePage.WHEEL, parked=True, system_long=True, lateral_context=False, metric=False).rows
|
|
rows = [row for row in rows if row.key.startswith('wheel:') and 'Distance' in row.key]
|
|
assert len(rows) == 3
|
|
assert all(row.available and 'Traffic mode' in row.choices and 'Quick Select 1' in row.choices for row in rows)
|
|
for car in (CAR.CHEVROLET_BOLT_EUV, CAR.CHEVROLET_VOLT_CAMERA, CAR.CHEVROLET_VOLT_2019):
|
|
assert distance_capability(ascm_params(car)) is None
|
|
params.put('DistanceButtonControl', 3, block=True)
|
|
rows = owner.snapshot(FeaturePage.WHEEL, parked=True, system_long=True, lateral_context=False, metric=False).rows
|
|
row = next(row for row in rows if row.key == 'wheel:DistanceButtonControl')
|
|
assert row.source == b'3' and row.value == 'Pause steering' and 'Traffic mode' in row.choices
|
|
assert params.get('DistanceButtonControl') == 3
|