mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-11-03 07:42:47 +08:00
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ba0f1859eb | |||
| 571a2fcb29 | |||
| 093c73e785 | |||
| 1f20b4bc79 | |||
| 20fcf35696 | |||
| 08bf9b3511 | |||
| c9316cc3d2 | |||
| 424311491c | |||
| a8795674b8 | |||
| 823b447fff | |||
| c36db99c2d | |||
| 5426b6af86 | |||
| bf0cdd667b | |||
| 9af59caf9c | |||
| 1a75c53ea4 | |||
| 83999585ec | |||
| 138353adb4 | |||
| 40dc4e1591 | |||
| cce4810904 | |||
| 5b58f9c1f5 | |||
| 815ac7732b | |||
| 2321f9d8f5 | |||
| b9020e0003 | |||
| ceb466578a | |||
| e1cfea4924 | |||
| dd8a2bf83a | |||
| ba36a28f2a | |||
| cf2010389a | |||
| 43522c4922 | |||
| 1cb5f24439 | |||
| b6a3f21a52 | |||
| 2ecc26b623 | |||
| 145f75fe06 | |||
| bd0578cbf9 | |||
| 40f24cc0b6 | |||
| 754efac063 | |||
| 132cc156f4 | |||
| 95ad932efb | |||
| ae30f4119f | |||
| d251ae4976 | |||
| 33324e590b | |||
| fea10ffd22 | |||
| f1e11e3f06 | |||
| c562eca8a1 | |||
| d9a690dac3 | |||
| a0eed058d1 | |||
| abc9f47a6f | |||
| b064f6fcaf | |||
| 0c7d7df2ec | |||
| dc86f35957 | |||
| 9685b0aa9b | |||
| f23cc408e3 | |||
| cea00a6c14 | |||
| f2949e1dc2 | |||
| 5f1f34fa7f | |||
| 2c041f9025 | |||
| 74b2d519b9 |
+1
-1
Submodule opendbc_repo updated: 3022d3367c...15c326f465
@@ -239,6 +239,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"BackupManager_RestoreVersion", {PERSISTENT, STRING}},
|
||||
|
||||
// sunnypilot car specific params
|
||||
{"HyundaiCustomButtonAction", {PERSISTENT | BACKUP, INT, "0"}},
|
||||
{"HyundaiLongitudinalTuning", {PERSISTENT | BACKUP, INT, "0"}},
|
||||
{"SubaruStopAndGo", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"SubaruStopAndGoManualParkingBrake", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
"""
|
||||
Copyright (c) 2021-, sunnypilot, and a number of other contributors.
|
||||
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
from collections.abc import Callable
|
||||
from enum import IntEnum
|
||||
|
||||
from opendbc.car.structs import car
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
|
||||
ALT_BUTTON_2_BIT = int(car.CarState.ButtonEvent.Type.altButton2)
|
||||
|
||||
|
||||
class CustomButtonAction(IntEnum):
|
||||
NONE = 0
|
||||
BOOKMARK = 1
|
||||
CYCLE_UI = 2
|
||||
|
||||
|
||||
class CustomButton:
|
||||
"""Runs the selected action on each custom button release, read from selfdriveStateSP.buttonsReleaseToggle."""
|
||||
def __init__(self, callbacks: dict[int, Callable[[], None]]):
|
||||
self._callbacks = callbacks
|
||||
self._prev_toggle: int | None = None
|
||||
|
||||
def update(self) -> None:
|
||||
if not (ui_state.started and ui_state.has_custom_button):
|
||||
self._prev_toggle = None
|
||||
return
|
||||
|
||||
toggle = ui_state.sm["selfdriveStateSP"].buttonsReleaseToggle
|
||||
released = self._prev_toggle is not None and (self._prev_toggle ^ toggle) >> ALT_BUTTON_2_BIT & 1
|
||||
self._prev_toggle = toggle
|
||||
|
||||
if released and (callback := self._callbacks.get(ui_state.params.get("HyundaiCustomButtonAction", return_default=True))):
|
||||
callback()
|
||||
@@ -0,0 +1,29 @@
|
||||
"""
|
||||
Copyright (c) 2021-, sunnypilot, and a number of other contributors.
|
||||
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
from openpilot.selfdrive.ui.layouts.main import MainLayout, MainState
|
||||
from openpilot.selfdrive.ui.sunnypilot.custom_button import CustomButton, CustomButtonAction
|
||||
|
||||
|
||||
class MainLayoutSP(MainLayout):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._custom_button = CustomButton({
|
||||
CustomButtonAction.BOOKMARK: self._on_bookmark_clicked,
|
||||
CustomButtonAction.CYCLE_UI: self._cycle_ui,
|
||||
})
|
||||
|
||||
def _render(self, rect):
|
||||
self._custom_button.update()
|
||||
super()._render(rect)
|
||||
|
||||
def _cycle_ui(self):
|
||||
if self._current_mode == MainState.ONROAD and not self._sidebar.is_visible:
|
||||
self._sidebar.set_visible(True)
|
||||
elif self._current_mode == MainState.SETTINGS:
|
||||
self._set_mode_for_state()
|
||||
else:
|
||||
self._on_settings_clicked()
|
||||
@@ -20,7 +20,13 @@ class HyundaiSettings(BrandSettings):
|
||||
self.longitudinal_tuning_item = multiple_button_item_sp(tr("Custom Longitudinal Tuning"), "", tuning_texts,
|
||||
button_width=300, callback=self._on_tuning_selected,
|
||||
param="HyundaiLongitudinalTuning", inline=False)
|
||||
self.items = [self.longitudinal_tuning_item]
|
||||
|
||||
custom_button_texts = [tr("None"), tr("Bookmark"), tr("Cycle UI")]
|
||||
self.custom_button_item = multiple_button_item_sp(tr("Steering Custom Button"),
|
||||
tr("Choose the sunnypilot action for the steering wheel custom/star button."),
|
||||
custom_button_texts, button_width=300,
|
||||
param="HyundaiCustomButtonAction", inline=False)
|
||||
self.items = [self.custom_button_item, self.longitudinal_tuning_item]
|
||||
|
||||
@staticmethod
|
||||
def _on_tuning_selected(index):
|
||||
@@ -57,3 +63,7 @@ class HyundaiSettings(BrandSettings):
|
||||
self.longitudinal_tuning_item.show_description(True)
|
||||
self.longitudinal_tuning_item.action_item.set_selected_button(tuning_param)
|
||||
self.longitudinal_tuning_item.set_visible(self.alpha_long_available)
|
||||
|
||||
self.custom_button_item.action_item.set_selected_button(ui_state.params.get("HyundaiCustomButtonAction", return_default=True))
|
||||
self.custom_button_item.show_description(True)
|
||||
self.custom_button_item.set_visible(ui_state.has_custom_button)
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
"""
|
||||
Copyright (c) 2021-, sunnypilot, and a number of other contributors.
|
||||
|
||||
This file is part of sunnypilot and is licensed under the MIT License.
|
||||
See the LICENSE.md file in the root directory for more details.
|
||||
"""
|
||||
from openpilot.selfdrive.ui.mici.layouts.main import MiciMainLayout
|
||||
from openpilot.selfdrive.ui.sunnypilot.custom_button import CustomButton, CustomButtonAction
|
||||
from openpilot.system.ui.lib.application import gui_app
|
||||
from openpilot.system.ui.widgets import Widget
|
||||
|
||||
|
||||
class MiciMainLayoutSP(MiciMainLayout):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._custom_button = CustomButton({
|
||||
CustomButtonAction.BOOKMARK: self._on_bookmark_clicked,
|
||||
CustomButtonAction.CYCLE_UI: self._cycle_ui,
|
||||
})
|
||||
|
||||
def _render(self, rect):
|
||||
self._custom_button.update()
|
||||
super()._render(rect)
|
||||
|
||||
def _show_layout(self, layout: Widget):
|
||||
if gui_app.widget_in_stack(self._onboarding_window):
|
||||
return
|
||||
gui_app.pop_widgets_to(self, lambda: self._scroll_to(layout))
|
||||
|
||||
def _layout_visible(self, layout: Widget) -> bool:
|
||||
return abs(layout.rect.x - self._rect.x) < self._rect.width / 2
|
||||
|
||||
def _cycle_ui(self):
|
||||
if gui_app.widget_in_stack(self._settings_layout):
|
||||
self._show_layout(self._onroad_layout)
|
||||
elif gui_app.get_active_widget() is self and self._layout_visible(self._home_layout):
|
||||
gui_app.push_widget(self._settings_layout)
|
||||
else:
|
||||
self._show_layout(self._home_layout)
|
||||
@@ -9,6 +9,7 @@ from enum import Enum
|
||||
from openpilot.cereal import messaging, log, custom
|
||||
from opendbc.car.structs import car
|
||||
from opendbc.sunnypilot.car.interfaces import has_bsm
|
||||
from opendbc.sunnypilot.car.hyundai.values import HyundaiFlagsSP
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.selfdrive.ui.sunnypilot.layouts.settings.display import OnroadBrightness
|
||||
from openpilot.sunnypilot.models.helpers import ACTIVE_BUNDLE_KEYS, get_active_source
|
||||
@@ -33,6 +34,7 @@ class UIStateSP:
|
||||
self.params = Params()
|
||||
self.CP_SP: custom.CarParamsSP | None = None
|
||||
self.has_icbm: bool = False
|
||||
self.has_custom_button: bool = False
|
||||
self.is_sp_release: bool = self.params.get_bool("IsReleaseSpBranch")
|
||||
self.sm_services_ext = [
|
||||
"modelManagerSP", "selfdriveStateSP", "longitudinalPlanSP", "backupManagerSP",
|
||||
@@ -160,6 +162,8 @@ class UIStateSP:
|
||||
if CP_SP_bytes is not None:
|
||||
self.CP_SP = messaging.log_from_bytes(CP_SP_bytes, custom.CarParamsSP)
|
||||
self.has_icbm = self.CP_SP.intelligentCruiseButtonManagementAvailable and self.params.get_bool("IntelligentCruiseButtonManagement")
|
||||
# flagsSP bits are per brand
|
||||
self.has_custom_button = self.CP is not None and self.CP.brand == "hyundai" and bool(self.CP_SP.flags & HyundaiFlagsSP.HAS_CUSTOM_BUTTON)
|
||||
|
||||
self._enforce_constraints()
|
||||
source = get_active_source(chestnut=self.chestnut_present, chestnut_active=self.chestnut_active,
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import Mock
|
||||
|
||||
from openpilot.common.test import OpenpilotTestCase
|
||||
import openpilot.selfdrive.ui.sunnypilot.custom_button as custom_button
|
||||
from openpilot.selfdrive.ui.sunnypilot.custom_button import ALT_BUTTON_2_BIT, CustomButton, CustomButtonAction
|
||||
|
||||
|
||||
def make_ui_state(monkeypatch, action, has_custom_button=True):
|
||||
state = SimpleNamespace(started=True, has_custom_button=has_custom_button, params=Mock(),
|
||||
sm={"selfdriveStateSP": SimpleNamespace(buttonsReleaseToggle=0)})
|
||||
state.params.get.return_value = action
|
||||
monkeypatch.setattr(custom_button, "ui_state", state)
|
||||
return state
|
||||
|
||||
|
||||
def run(button, state, toggles):
|
||||
for toggle in toggles:
|
||||
state.sm["selfdriveStateSP"].buttonsReleaseToggle = toggle
|
||||
button.update()
|
||||
|
||||
|
||||
class TestCustomButton(OpenpilotTestCase):
|
||||
def test_actions_on_release(self, monkeypatch):
|
||||
for action in (CustomButtonAction.BOOKMARK, CustomButtonAction.CYCLE_UI):
|
||||
state = make_ui_state(monkeypatch, action)
|
||||
callbacks = {a: Mock() for a in (CustomButtonAction.BOOKMARK, CustomButtonAction.CYCLE_UI)}
|
||||
# first read seeds, then two releases of altButton2 and one of another button
|
||||
run(CustomButton(callbacks), state, [0, 1 << ALT_BUTTON_2_BIT, 1 << ALT_BUTTON_2_BIT, 0, 0b1])
|
||||
assert callbacks[action].call_count == 2
|
||||
assert sum(cb.call_count for cb in callbacks.values()) == 2
|
||||
|
||||
|
||||
def test_no_action_when_unavailable(self, monkeypatch):
|
||||
callback = Mock()
|
||||
state = make_ui_state(monkeypatch, CustomButtonAction.BOOKMARK, has_custom_button=False)
|
||||
run(CustomButton({CustomButtonAction.BOOKMARK: callback}), state, [0, 1 << ALT_BUTTON_2_BIT])
|
||||
|
||||
state = make_ui_state(monkeypatch, CustomButtonAction.BOOKMARK)
|
||||
run(CustomButton({CustomButtonAction.BOOKMARK: callback}), state, [1 << ALT_BUTTON_2_BIT]) # stale toggle on first read
|
||||
assert callback.call_count == 0
|
||||
@@ -10,6 +10,10 @@ from openpilot.selfdrive.ui.layouts.main import MainLayout
|
||||
from openpilot.selfdrive.ui.mici.layouts.main import MiciMainLayout
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
|
||||
if gui_app.sunnypilot_ui():
|
||||
from openpilot.selfdrive.ui.sunnypilot.layouts.main import MainLayoutSP as MainLayout
|
||||
from openpilot.selfdrive.ui.sunnypilot.mici.layouts.main import MiciMainLayoutSP as MiciMainLayout
|
||||
|
||||
BIG_UI = gui_app.big_ui()
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from opendbc.car.structs import car
|
||||
from opendbc.car.hyundai.values import CAR as HYUNDAI_CAR, UNSUPPORTED_LONGITUDINAL_CAR
|
||||
from opendbc.car.subaru.values import CAR as SUBARU_CAR, SubaruFlags
|
||||
from opendbc.car.toyota.values import CAR as TOYOTA_CAR, ToyotaFlags
|
||||
from opendbc.sunnypilot.car.hyundai.values import HyundaiFlagsSP
|
||||
from opendbc.sunnypilot.car.interfaces import has_bsm
|
||||
from opendbc.sunnypilot.car.tesla.values import TeslaFlagsSP
|
||||
from openpilot.common.params import Params
|
||||
@@ -44,6 +45,7 @@ CAPABILITY_FIELDS = (
|
||||
"device_type",
|
||||
"subaru_has_sng",
|
||||
"hyundai_alpha_long_available",
|
||||
"hyundai_has_custom_button",
|
||||
"toyota_tss2",
|
||||
"custom_model_active",
|
||||
)
|
||||
@@ -68,6 +70,7 @@ CAPABILITY_LABELS: dict[str, str] = {
|
||||
"device_type": "Device type",
|
||||
"subaru_has_sng": "Subaru Stop-and-Go available",
|
||||
"hyundai_alpha_long_available": "Hyundai Alpha Longitudinal available",
|
||||
"hyundai_has_custom_button": "Hyundai steering wheel custom button",
|
||||
"toyota_tss2": "Toyota TSS2 platform",
|
||||
"custom_model_active": "Non-Default model selected",
|
||||
}
|
||||
@@ -192,6 +195,7 @@ def generate_capabilities(params: Params | None = None) -> dict:
|
||||
caps["icbm_available"] = bool(CP_SP.intelligentCruiseButtonManagementAvailable)
|
||||
caps["has_icbm"] = bool(CP_SP.intelligentCruiseButtonManagementAvailable) and params.get_bool("IntelligentCruiseButtonManagement")
|
||||
caps["tesla_has_vehicle_bus"] = bool(CP_SP.flags & TeslaFlagsSP.HAS_VEHICLE_BUS)
|
||||
caps["hyundai_has_custom_button"] = caps["brand"] == "hyundai" and bool(CP_SP.flags & HyundaiFlagsSP.HAS_CUSTOM_BUTTON)
|
||||
except Exception:
|
||||
cloudlog.exception("capabilities: failed to deserialize CarParamsSPPersistent")
|
||||
|
||||
|
||||
@@ -2174,6 +2174,33 @@
|
||||
"title": "Hyundai / Kia / Genesis Settings",
|
||||
"description": "",
|
||||
"items": [
|
||||
{
|
||||
"key": "HyundaiCustomButtonAction",
|
||||
"widget": "multiple_button",
|
||||
"title": "Steering Custom Button",
|
||||
"description": "Choose the sunnypilot action for the steering wheel custom/star button.",
|
||||
"options": [
|
||||
{
|
||||
"value": 0,
|
||||
"label": "None"
|
||||
},
|
||||
{
|
||||
"value": 1,
|
||||
"label": "Bookmark"
|
||||
},
|
||||
{
|
||||
"value": 2,
|
||||
"label": "Cycle UI"
|
||||
}
|
||||
],
|
||||
"visibility": [
|
||||
{
|
||||
"type": "capability",
|
||||
"field": "hyundai_has_custom_button",
|
||||
"equals": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "HyundaiLongitudinalTuning",
|
||||
"widget": "multiple_button",
|
||||
|
||||
@@ -10,6 +10,21 @@ sections:
|
||||
title: Hyundai / Kia / Genesis Settings
|
||||
description: ''
|
||||
items:
|
||||
- key: HyundaiCustomButtonAction
|
||||
widget: multiple_button
|
||||
title: Steering Custom Button
|
||||
description: Choose the sunnypilot action for the steering wheel custom/star button.
|
||||
options:
|
||||
- value: 0
|
||||
label: None
|
||||
- value: 1
|
||||
label: Bookmark
|
||||
- value: 2
|
||||
label: Cycle UI
|
||||
visibility:
|
||||
- type: capability
|
||||
field: hyundai_has_custom_button
|
||||
equals: true
|
||||
- key: HyundaiLongitudinalTuning
|
||||
widget: multiple_button
|
||||
title: Custom Longitudinal Tuning
|
||||
|
||||
Reference in New Issue
Block a user