mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-11-06 14:23:44 +08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5958b2d25b | |||
| 932ff06d93 | |||
| 73c8b30fa9 | |||
| 8bdb2f54d9 | |||
| 9c1bdde65b | |||
| 914aaefac1 | |||
| d05649c0a4 | |||
| 3521140920 | |||
| 56628fc770 | |||
| 60a9cc8657 |
@@ -4,6 +4,7 @@
|
||||
[submodule "opendbc"]
|
||||
path = opendbc_repo
|
||||
url = https://github.com/sunnypilot/opendbc.git
|
||||
branch = toyotabsmhack
|
||||
[submodule "msgq"]
|
||||
path = msgq_repo
|
||||
url = https://github.com/sunnypilot/msgq.git
|
||||
|
||||
+1
-1
Submodule opendbc_repo updated: aa9bff6f54...a0f52f61af
@@ -245,6 +245,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"SubaruStopAndGoManualParkingBrake", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"TeslaCoopSteering", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"TeslaMadsScreenButton", {PERSISTENT | BACKUP, INT, "0"}},
|
||||
{"ToyotaEnhancedBsm", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"ToyotaEnforceStockLongitudinal", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"ToyotaStopAndGoHack", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
{"ToyotaTSS2Smooth", {PERSISTENT | BACKUP, BOOL, "0"}},
|
||||
|
||||
@@ -22,7 +22,6 @@ from openpilot.common.transformations.orientation import rot_from_euler
|
||||
from enum import IntEnum
|
||||
|
||||
if gui_app.sunnypilot_ui():
|
||||
from openpilot.selfdrive.ui.sunnypilot.mici.onroad.augmented_road_view import AugmentedRoadViewSP
|
||||
from openpilot.selfdrive.ui.sunnypilot.mici.onroad.hud_renderer import HudRendererSP as HudRenderer
|
||||
from openpilot.selfdrive.ui.sunnypilot.ui_state import OnroadTimerStatus
|
||||
|
||||
@@ -157,10 +156,9 @@ class BookmarkIcon(Widget):
|
||||
rl.draw_texture_ex(icon, rl.Vector2(icon_x, icon_y), 0.0, 1.0, rl.Color(255, 255, 255, round(255 * alpha)))
|
||||
|
||||
|
||||
class AugmentedRoadView(CameraView, AugmentedRoadViewSP):
|
||||
class AugmentedRoadView(CameraView):
|
||||
def __init__(self, bookmark_callback=None, stream_type: VisionStreamType = VisionStreamType.VISION_STREAM_NARROW_ROAD):
|
||||
super().__init__("camerad", stream_type)
|
||||
AugmentedRoadViewSP.__init__(self)
|
||||
self._bookmark_callback = bookmark_callback
|
||||
self._set_placeholder_color(rl.BLACK)
|
||||
|
||||
@@ -277,7 +275,7 @@ class AugmentedRoadView(CameraView, AugmentedRoadViewSP):
|
||||
if show_navigation:
|
||||
self._navigation.render(rl.Rectangle(self._content_rect.x + self._content_rect.width, self.rect.y, PANEL_WIDTH, self.rect.height))
|
||||
else:
|
||||
AugmentedRoadViewSP.render_side_panel(self, self.rect)
|
||||
self._confidence_ball.render(self.rect)
|
||||
|
||||
self._bookmark_icon.render(self.rect)
|
||||
|
||||
|
||||
@@ -12,10 +12,16 @@ from openpilot.system.ui.widgets import DialogResult
|
||||
from openpilot.system.ui.widgets.confirm_dialog import ConfirmDialog
|
||||
from openpilot.system.ui.sunnypilot.widgets.list_view import toggle_item_sp
|
||||
from opendbc.car.toyota.values import ToyotaFlags
|
||||
from opendbc.sunnypilot.car.toyota.values import ToyotaFlagsSP
|
||||
|
||||
|
||||
ONROAD_ONLY_DESCRIPTION = tr_noop("Start the vehicle to check vehicle compatibility.")
|
||||
SNG_HACK_UNAVAILABLE = tr_noop("sunnypilot Longitudinal Control must be available and enabled for your vehicle to use this feature.")
|
||||
BSM_UNAVAILABLE = tr_noop("Enhanced Blind Spot Monitoring requires a TSS2 Toyota/Lexus without SecOC, " +
|
||||
"or a smartDSU with sunnypilot longitudinal control.")
|
||||
BSM_STOCK_LONG_UNAVAILABLE = tr_noop("Enhanced Blind Spot Monitoring is not available while Enforce Factory Longitudinal Control is enabled.")
|
||||
BSM_REQUIRED = tr_noop("This vehicle does not report blind spot status over the standard CAN signals. " +
|
||||
"Enhanced Blind Spot Monitoring is required for blind spot detection.")
|
||||
PLATFORM_UNAVAILABLE = tr_noop("This feature is currently not available on this platform.")
|
||||
|
||||
DESCRIPTIONS = {
|
||||
@@ -26,6 +32,10 @@ DESCRIPTIONS = {
|
||||
'sunnypilot will allow some Toyota/Lexus cars to auto resume during stop and go traffic. ' +
|
||||
'This feature is only applicable to certain models that are able to use longitudinal control. This is an alpha feature. Use at your own risk.'
|
||||
),
|
||||
'enhanced_bsm': tr_noop(
|
||||
'sunnypilot will poll the blind spot monitor diagnostics directly from the radar. Use this on vehicles whose blind spot monitors ' +
|
||||
'do not report blind spot status over the standard CAN signals. This is an alpha feature. Use at your own risk.'
|
||||
),
|
||||
'tss2_smooth': tr_noop(
|
||||
'Enable smoother longitudinal control for TSS2 vehicles. ' +
|
||||
'Uses a custom speed-dependent integral gain curve for smoother traffic driving.'
|
||||
@@ -53,6 +63,14 @@ class ToyotaSettings(BrandSettings):
|
||||
enabled=lambda: not ui_state.engaged,
|
||||
)
|
||||
|
||||
self.enhanced_bsm = toggle_item_sp(
|
||||
lambda: tr("Enhanced Blind Spot Monitoring (Alpha)"),
|
||||
description=lambda: tr(DESCRIPTIONS["enhanced_bsm"]),
|
||||
initial_state=ui_state.params.get_bool("ToyotaEnhancedBsm"),
|
||||
callback=self._on_enable_enhanced_bsm,
|
||||
enabled=lambda: not ui_state.engaged,
|
||||
)
|
||||
|
||||
self.tss2_smooth = toggle_item_sp(
|
||||
lambda: tr("TSS2 Smooth Longitudinal (Alpha)"),
|
||||
description=lambda: tr(DESCRIPTIONS["tss2_smooth"]),
|
||||
@@ -64,6 +82,7 @@ class ToyotaSettings(BrandSettings):
|
||||
self.items = [
|
||||
self.enforce_stock_longitudinal,
|
||||
self.stop_and_go_hack,
|
||||
self.enhanced_bsm,
|
||||
self.tss2_smooth,
|
||||
]
|
||||
|
||||
@@ -130,6 +149,25 @@ class ToyotaSettings(BrandSettings):
|
||||
ui_state.params.put_bool("ToyotaStopAndGoHack", False)
|
||||
ui_state.params.put_bool("OnroadCycleRequested", True)
|
||||
|
||||
def _on_enable_enhanced_bsm(self, state: bool):
|
||||
if state:
|
||||
def confirm_callback(result: int):
|
||||
if result == DialogResult.CONFIRM:
|
||||
ui_state.params.put_bool("ToyotaEnhancedBsm", True)
|
||||
ui_state.params.put_bool("OnroadCycleRequested", True)
|
||||
else:
|
||||
self.enhanced_bsm.action_item.set_state(False)
|
||||
|
||||
content = (f"<h1>{self.enhanced_bsm.title}</h1><br>" +
|
||||
f"<p>{self.enhanced_bsm.description}</p>")
|
||||
|
||||
dlg = ConfirmDialog(content, tr("Enable"), rich=True, callback=confirm_callback)
|
||||
gui_app.push_widget(dlg)
|
||||
|
||||
else:
|
||||
ui_state.params.put_bool("ToyotaEnhancedBsm", False)
|
||||
ui_state.params.put_bool("OnroadCycleRequested", True)
|
||||
|
||||
def update_settings(self):
|
||||
if ui_state.CP is not None:
|
||||
longitudinal = ui_state.CP.openpilotLongitudinalControl
|
||||
@@ -150,6 +188,31 @@ class ToyotaSettings(BrandSettings):
|
||||
if show_desc:
|
||||
self.stop_and_go_hack.show_description(True)
|
||||
|
||||
# Enhanced BSM needs the radar diagnostic address, which is only in the TX allowlist for
|
||||
# TSS2 cars without SecOC, or for TSS-P cars whose smartDSU lets sunnypilot control
|
||||
# longitudinal. Enforcing factory longitudinal control rules both of those out.
|
||||
sdsu_bsm_supported = (longitudinal and ui_state.CP_SP is not None and
|
||||
bool(ui_state.CP_SP.flags & ToyotaFlagsSP.SMART_DSU))
|
||||
bsm_supported = (not bool(ui_state.CP.flags & ToyotaFlags.SECOC) and
|
||||
(bool(ui_state.CP.flags & ToyotaFlags.TSS2) or sdsu_bsm_supported))
|
||||
bsm_available = bsm_supported and not enforce_stock
|
||||
self.enhanced_bsm.action_item.set_enabled(bsm_available and not ui_state.engaged)
|
||||
|
||||
bsm_desc = tr(DESCRIPTIONS["enhanced_bsm"])
|
||||
if not bsm_supported:
|
||||
self.enhanced_bsm.action_item.set_state(False)
|
||||
bsm_desc = "<b>" + tr(BSM_UNAVAILABLE) + "</b>\n\n" + bsm_desc
|
||||
elif enforce_stock:
|
||||
self.enhanced_bsm.action_item.set_state(False)
|
||||
bsm_desc = "<b>" + tr(BSM_STOCK_LONG_UNAVAILABLE) + "</b>\n\n" + bsm_desc
|
||||
elif ui_state.CP_SP is not None and ui_state.CP_SP.flags & ToyotaFlagsSP.SP_NEED_DEBUG_BSM:
|
||||
bsm_desc = "<b>" + tr(BSM_REQUIRED) + "</b>\n\n" + bsm_desc
|
||||
|
||||
if self.enhanced_bsm.description != bsm_desc:
|
||||
self.enhanced_bsm.set_description(bsm_desc)
|
||||
if not bsm_available:
|
||||
self.enhanced_bsm.show_description(True)
|
||||
|
||||
tss2 = bool(ui_state.CP.flags & ToyotaFlags.TSS2)
|
||||
if longitudinal and not enforce_stock and tss2:
|
||||
self.tss2_smooth.action_item.set_enabled(not ui_state.engaged)
|
||||
@@ -173,6 +236,12 @@ class ToyotaSettings(BrandSettings):
|
||||
self.stop_and_go_hack.set_description(new_desc)
|
||||
self.stop_and_go_hack.show_description(True)
|
||||
|
||||
self.enhanced_bsm.action_item.set_enabled(False)
|
||||
bsm_desc = "<b>" + tr(ONROAD_ONLY_DESCRIPTION) + "</b>\n\n" + tr(DESCRIPTIONS["enhanced_bsm"])
|
||||
if self.enhanced_bsm.description != bsm_desc:
|
||||
self.enhanced_bsm.set_description(bsm_desc)
|
||||
self.enhanced_bsm.show_description(True)
|
||||
|
||||
self.tss2_smooth.action_item.set_enabled(False)
|
||||
new_desc = "<b>" + tr(ONROAD_ONLY_DESCRIPTION) + "</b>\n\n" + tr(DESCRIPTIONS["tss2_smooth"])
|
||||
if self.tss2_smooth.description != new_desc:
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, 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.
|
||||
"""
|
||||
import math
|
||||
import pyray as rl
|
||||
|
||||
from openpilot.cereal import log
|
||||
from openpilot.common.filter_simple import FirstOrderFilter
|
||||
from openpilot.selfdrive.ui.mici.onroad import SIDE_PANEL_WIDTH
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.accel_boost import get_boost_max
|
||||
from openpilot.system.ui.lib.application import gui_app
|
||||
from openpilot.system.ui.widgets import Widget
|
||||
|
||||
BAR_WIDTH = 26
|
||||
TRACK_TOP_RATIO = 0.08
|
||||
TRACK_BOTTOM_RATIO = 0.92
|
||||
CAP_BLEND_START = 0.45
|
||||
MAX_BOOST_BLEND = 0.55
|
||||
FADE_THRESHOLD = 0.01
|
||||
|
||||
COLOR_TRACK = rl.Color(255, 255, 255, 28)
|
||||
COLOR_FILL = rl.Color(0, 230, 120, 255)
|
||||
|
||||
|
||||
def get_boost_fraction(boost: float, max_boost: float) -> float:
|
||||
if max_boost <= 0.0:
|
||||
return 0.0
|
||||
return min(max(boost / max_boost, 0.0), 1.0)
|
||||
|
||||
|
||||
def lighten(color: rl.Color, amount: float) -> rl.Color:
|
||||
amount = min(max(amount, 0.0), 1.0)
|
||||
return rl.Color(int(color.r + (255 - color.r) * amount),
|
||||
int(color.g + (255 - color.g) * amount),
|
||||
int(color.b + (255 - color.b) * amount), color.a)
|
||||
|
||||
|
||||
def get_boost_color(fraction: float) -> rl.Color:
|
||||
blend = max(0.0, (fraction - CAP_BLEND_START) / (1.0 - CAP_BLEND_START))
|
||||
return lighten(COLOR_FILL, MAX_BOOST_BLEND * blend)
|
||||
|
||||
|
||||
class AccelBoostIndicator(Widget):
|
||||
def __init__(self, panel_width: float = SIDE_PANEL_WIDTH, bar_width: float = BAR_WIDTH):
|
||||
super().__init__()
|
||||
self._panel_width = panel_width
|
||||
self._bar_width = bar_width
|
||||
fps = max(gui_app.target_fps, 1)
|
||||
self._boost_filter = FirstOrderFilter(0.0, 0.15, 1 / fps)
|
||||
self._alpha_filter = FirstOrderFilter(0.0, 0.1, 1 / fps)
|
||||
self._max_boost_filter = FirstOrderFilter(get_boost_max(), 0.25, 1 / fps)
|
||||
|
||||
@property
|
||||
def holding_panel(self) -> bool:
|
||||
return self._alpha_filter.x > FADE_THRESHOLD
|
||||
|
||||
def _update_state(self):
|
||||
sm = ui_state.sm
|
||||
visible = (ui_state.accel_boost and ui_state.has_longitudinal_control and sm.alive['selfdriveState'] and
|
||||
sm.alive['longitudinalPlan'] and sm['selfdriveState'].enabled)
|
||||
plan = sm['longitudinalPlan']
|
||||
applied = visible and plan.longitudinalPlanSource == log.LongitudinalPlan.LongitudinalPlanSource.e2e
|
||||
self._boost_filter.update(float(plan.accelBoost) if applied else 0.0)
|
||||
self._alpha_filter.update(1.0 if visible else 0.0)
|
||||
|
||||
if sm.alive['selfdriveState']:
|
||||
self._max_boost_filter.update(get_boost_max(sm['selfdriveState'].personality))
|
||||
|
||||
def _render(self, _):
|
||||
alpha = self._alpha_filter.x
|
||||
if alpha < FADE_THRESHOLD:
|
||||
return
|
||||
|
||||
panel_x = max(self.rect.x, self.rect.x + self.rect.width - self._panel_width)
|
||||
bar_x = panel_x + (self._panel_width - self._bar_width) / 2
|
||||
track_top = self.rect.y + self.rect.height * TRACK_TOP_RATIO
|
||||
track = rl.Rectangle(bar_x, track_top, self._bar_width,
|
||||
max(1.0, self.rect.height * (TRACK_BOTTOM_RATIO - TRACK_TOP_RATIO)))
|
||||
rl.draw_rectangle_rounded(track, 0.5, 12,
|
||||
rl.Color(COLOR_TRACK.r, COLOR_TRACK.g, COLOR_TRACK.b, int(COLOR_TRACK.a * alpha)))
|
||||
|
||||
fraction = get_boost_fraction(self._boost_filter.x, self._max_boost_filter.x)
|
||||
fill_h = fraction * track.height
|
||||
if fill_h < 1.0:
|
||||
return
|
||||
|
||||
fill_color = get_boost_color(fraction)
|
||||
tip = track.y + track.height - fill_h
|
||||
rl.begin_scissor_mode(int(track.x), int(tip), int(math.ceil(track.width)) + 1, int(math.ceil(fill_h)))
|
||||
rl.draw_rectangle_rounded(track, 0.5, 12, rl.Color(fill_color.r, fill_color.g, fill_color.b, int(235 * alpha)))
|
||||
rl.end_scissor_mode()
|
||||
@@ -1,19 +0,0 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, 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.
|
||||
"""
|
||||
import pyray as rl
|
||||
|
||||
from openpilot.selfdrive.ui.sunnypilot.mici.onroad.accel_boost_indicator import AccelBoostIndicator
|
||||
|
||||
|
||||
class AugmentedRoadViewSP:
|
||||
def __init__(self):
|
||||
self._accel_boost_indicator = AccelBoostIndicator()
|
||||
|
||||
def render_side_panel(self, rect: rl.Rectangle) -> None:
|
||||
self._accel_boost_indicator.render(rect)
|
||||
if not self._accel_boost_indicator.holding_panel:
|
||||
self._confidence_ball.render(rect)
|
||||
@@ -1,36 +0,0 @@
|
||||
"""
|
||||
Copyright (c) 2021-, Haibin Wen, 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.cereal import log
|
||||
from openpilot.common.test import OpenpilotTestCase
|
||||
from openpilot.selfdrive.ui.sunnypilot.mici.onroad.accel_boost_indicator import (
|
||||
CAP_BLEND_START, COLOR_FILL, get_boost_color, get_boost_fraction,
|
||||
)
|
||||
from openpilot.sunnypilot.selfdrive.controls.lib.accel_boost import ACCEL_BOOST_MAX, get_boost_max
|
||||
|
||||
|
||||
class TestAccelBoostIndicator(OpenpilotTestCase):
|
||||
def test_bar_fills_at_the_active_profile_cap(self):
|
||||
for personality in (log.LongitudinalPersonality.aggressive, log.LongitudinalPersonality.standard,
|
||||
log.LongitudinalPersonality.relaxed):
|
||||
cap = get_boost_max(personality)
|
||||
assert get_boost_fraction(0.0, cap) == 0.0
|
||||
assert get_boost_fraction(cap * 0.5, cap) == 0.5
|
||||
assert get_boost_fraction(cap, cap) == 1.0
|
||||
|
||||
assert get_boost_fraction(max(ACCEL_BOOST_MAX), min(ACCEL_BOOST_MAX)) == 1.0
|
||||
assert get_boost_fraction(0.0, 0.0) == 0.0
|
||||
assert get_boost_fraction(-1.0, get_boost_max()) == 0.0
|
||||
|
||||
def test_fill_lightens_as_boost_builds(self):
|
||||
base = get_boost_color(0.0)
|
||||
assert (base.r, base.g, base.b) == (COLOR_FILL.r, COLOR_FILL.g, COLOR_FILL.b)
|
||||
assert (get_boost_color(CAP_BLEND_START).r, get_boost_color(CAP_BLEND_START).b) == (COLOR_FILL.r, COLOR_FILL.b)
|
||||
|
||||
full = get_boost_color(1.0)
|
||||
assert full.r > base.r
|
||||
assert full.b > base.b
|
||||
assert full.g > full.r and full.g > full.b
|
||||
@@ -44,7 +44,6 @@ class UIStateSP:
|
||||
self.screensaver = ScreenSaverSP(params=self.params)
|
||||
self.screensaver_enabled: bool = False
|
||||
|
||||
self.accel_boost: bool = False
|
||||
self.active_bundle = None
|
||||
self.model_runner_tinygrad: bool = False
|
||||
self.active_runner_tinygrad: bool = False
|
||||
@@ -172,7 +171,6 @@ class UIStateSP:
|
||||
# stock only counts the default big model's compiled pkl. a downloaded big bundle runs on the
|
||||
# chestnut just the same, so ChestnutState has to see it as available too.
|
||||
self.chestnut_compiled = self.chestnut_compiled or self.model_runner_tinygrad
|
||||
self.accel_boost = self.params.get_bool("AccelBoostSP")
|
||||
self.blindspot = self.params.get_bool("BlindSpot")
|
||||
self.chevron_metrics = self.params.get("ChevronInfo")
|
||||
self.custom_interactive_timeout = self.params.get("InteractivityTimeout", return_default=True)
|
||||
|
||||
@@ -242,7 +242,7 @@ class ModelState(ModelStateBase):
|
||||
desired_curvature = get_curvature_from_output(model_output, curvature_plan, v_ego, lat_action_t, self.mlsim)
|
||||
else:
|
||||
desired_accel = model_output['action'][0, 1]
|
||||
desired_curvature = model_output['action'][0, 0] / (max(1.0, v_ego))**2
|
||||
desired_curvature = model_output['action'][0, 0] / (max(2.5, v_ego))**2
|
||||
if blendful is not None:
|
||||
desired_curvature += blendful(desired_curvature)
|
||||
|
||||
|
||||
@@ -126,6 +126,7 @@ def initialize_params(params) -> list[dict[str, Any]]:
|
||||
keys.extend([
|
||||
"ToyotaEnforceStockLongitudinal",
|
||||
"ToyotaStopAndGoHack",
|
||||
"ToyotaEnhancedBsm",
|
||||
"ToyotaTSS2Smooth",
|
||||
])
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ 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.interfaces import has_bsm
|
||||
from opendbc.sunnypilot.car.tesla.values import TeslaFlagsSP
|
||||
from opendbc.sunnypilot.car.toyota.values import ToyotaFlagsSP
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.common.swaglog import cloudlog
|
||||
from openpilot.common.hardware import HARDWARE
|
||||
@@ -44,6 +45,7 @@ CAPABILITY_FIELDS = (
|
||||
"device_type",
|
||||
"subaru_has_sng",
|
||||
"hyundai_alpha_long_available",
|
||||
"toyota_enhanced_bsm_available",
|
||||
"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",
|
||||
"toyota_enhanced_bsm_available": "Toyota Enhanced BSM available",
|
||||
"toyota_tss2": "Toyota TSS2 platform",
|
||||
"custom_model_active": "Non-Default model selected",
|
||||
}
|
||||
@@ -89,6 +92,7 @@ CAR_CAPABILITY_FIELDS = (
|
||||
"subaru_has_sng",
|
||||
"hyundai_alpha_long_available",
|
||||
"toyota_tss2",
|
||||
"toyota_enhanced_bsm_available",
|
||||
)
|
||||
|
||||
# Explicit defaults for non-boolean capability fields
|
||||
@@ -104,7 +108,7 @@ def _bundle_field(bundle: dict | None, key: str) -> str:
|
||||
return bundle.get(key, "") if isinstance(bundle, dict) else ""
|
||||
|
||||
|
||||
def _resolve_brand_capabilities(caps: dict, bundle_platform: str, CP) -> None:
|
||||
def _resolve_brand_capabilities(caps: dict, bundle_platform: str, CP, CP_SP=None) -> None:
|
||||
"""Set brand-specific capabilities from bundle platform or CarParams fallback.
|
||||
|
||||
Bundle (manual car selection) is a pre-fingerprint approximation.
|
||||
@@ -138,11 +142,18 @@ def _resolve_brand_capabilities(caps: dict, bundle_platform: str, CP) -> None:
|
||||
elif brand == "toyota":
|
||||
if bundle_platform:
|
||||
try:
|
||||
caps["toyota_tss2"] = bool(TOYOTA_CAR[bundle_platform].config.flags & ToyotaFlags.TSS2)
|
||||
flags = TOYOTA_CAR[bundle_platform].config.flags
|
||||
caps["toyota_tss2"] = bool(flags & ToyotaFlags.TSS2)
|
||||
caps["toyota_enhanced_bsm_available"] = bool(flags & ToyotaFlags.TSS2) and not bool(flags & ToyotaFlags.SECOC)
|
||||
except KeyError:
|
||||
cloudlog.exception(f"capabilities: unknown toyota platform {bundle_platform!r}")
|
||||
elif CP is not None:
|
||||
caps["toyota_tss2"] = bool(CP.flags & ToyotaFlags.TSS2)
|
||||
# same gate as _initialize_toyota: TSS2 without SecOC, or TSS-P with a smartDSU and openpilot
|
||||
# longitudinal control (the bundle path can't see 0x2FF, so it stays TSS2-only)
|
||||
sdsu_bsm = CP_SP is not None and bool(CP_SP.flags & ToyotaFlagsSP.SMART_DSU) and bool(CP.openpilotLongitudinalControl)
|
||||
caps["toyota_enhanced_bsm_available"] = (not bool(CP.flags & ToyotaFlags.SECOC) and
|
||||
(bool(CP.flags & ToyotaFlags.TSS2) or sdsu_bsm))
|
||||
|
||||
|
||||
def generate_capabilities(params: Params | None = None) -> dict:
|
||||
@@ -217,7 +228,7 @@ def generate_capabilities(params: Params | None = None) -> dict:
|
||||
if CP is not None:
|
||||
caps["has_bsm"] = has_bsm(CP, CP_SP)
|
||||
|
||||
_resolve_brand_capabilities(caps, bundle_platform, CP)
|
||||
_resolve_brand_capabilities(caps, bundle_platform, CP, CP_SP)
|
||||
|
||||
return caps
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ The tables below describe the **compiled** `settings_ui.json` schema — what th
|
||||
|
||||
**Enablement rules**: Grayed out (disabled) when rules fail. Frontend shows a contextual badge explaining why.
|
||||
|
||||
**Capability fields** (referenced in rules): `has_longitudinal_control`, `has_icbm`, `icbm_available`, `torque_allowed`, `brand`, `pcm_cruise`, `alpha_long_available`, `steer_control_type`, `has_bsm`, `is_release`, `is_sp_release`, `is_development`, `tesla_has_vehicle_bus`, `has_stop_and_go`, `stock_longitudinal`
|
||||
**Capability fields** (referenced in rules): `has_longitudinal_control`, `has_icbm`, `icbm_available`, `torque_allowed`, `brand`, `pcm_cruise`, `alpha_long_available`, `steer_control_type`, `has_bsm`, `is_release`, `is_sp_release`, `is_development`, `tesla_has_vehicle_bus`, `has_stop_and_go`, `stock_longitudinal`, `toyota_enhanced_bsm_available`
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -2361,6 +2361,28 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "ToyotaEnhancedBsm",
|
||||
"widget": "toggle",
|
||||
"needs_onroad_cycle": true,
|
||||
"title": "Enhanced Blind Spot Monitoring (Alpha)",
|
||||
"description": "sunnypilot will poll the blind spot monitor diagnostics directly from the radar. Use this on vehicles whose blind spot monitors do not report blind spot status over the standard CAN signals. This is an alpha feature. Use at your own risk.",
|
||||
"enablement": [
|
||||
{
|
||||
"type": "not_engaged"
|
||||
},
|
||||
{
|
||||
"type": "capability",
|
||||
"field": "toyota_enhanced_bsm_available",
|
||||
"equals": true
|
||||
},
|
||||
{
|
||||
"type": "capability",
|
||||
"field": "stock_longitudinal",
|
||||
"equals": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "ToyotaTSS2Smooth",
|
||||
"widget": "toggle",
|
||||
|
||||
@@ -101,6 +101,21 @@ sections:
|
||||
- type: param
|
||||
key: ToyotaEnforceStockLongitudinal
|
||||
equals: false
|
||||
- key: ToyotaEnhancedBsm
|
||||
widget: toggle
|
||||
needs_onroad_cycle: true
|
||||
title: Enhanced Blind Spot Monitoring (Alpha)
|
||||
description: sunnypilot will poll the blind spot monitor diagnostics directly from the radar. Use this on vehicles whose
|
||||
blind spot monitors do not report blind spot status over the standard CAN signals. This is an alpha feature. Use at
|
||||
your own risk.
|
||||
enablement:
|
||||
- $ref: '#/macros/not_engaged'
|
||||
- type: capability
|
||||
field: toyota_enhanced_bsm_available
|
||||
equals: true
|
||||
- type: capability
|
||||
field: stock_longitudinal
|
||||
equals: false
|
||||
- key: ToyotaTSS2Smooth
|
||||
widget: toggle
|
||||
needs_onroad_cycle: true
|
||||
|
||||
@@ -70,12 +70,18 @@ class TestOpaquePerBrandFlags(OpenpilotTestCase):
|
||||
def test_hyundai_alpha_long_available_field_present(self):
|
||||
assert "hyundai_alpha_long_available" in CAPABILITY_FIELDS
|
||||
|
||||
def test_toyota_enhanced_bsm_available_field_present(self):
|
||||
assert "toyota_enhanced_bsm_available" in CAPABILITY_FIELDS
|
||||
|
||||
def test_subaru_has_sng_default_false(self, caps):
|
||||
assert caps["subaru_has_sng"] is False
|
||||
|
||||
def test_hyundai_alpha_long_available_default_false(self, caps):
|
||||
assert caps["hyundai_alpha_long_available"] is False
|
||||
|
||||
def test_toyota_enhanced_bsm_available_default_false(self, caps):
|
||||
assert caps["toyota_enhanced_bsm_available"] is False
|
||||
|
||||
def test_toyota_tss2_field_present(self):
|
||||
assert "toyota_tss2" in CAPABILITY_FIELDS
|
||||
|
||||
|
||||
@@ -207,6 +207,7 @@ class TestNotEngagedReplacement(OpenpilotTestCase):
|
||||
"AlphaLongitudinalEnabled",
|
||||
"ToyotaEnforceStockLongitudinal",
|
||||
"ToyotaStopAndGoHack",
|
||||
"ToyotaEnhancedBsm",
|
||||
"ToyotaTSS2Smooth",
|
||||
], names=["key"])
|
||||
def test_offroad_only_replaced_with_not_engaged(self, schema, key):
|
||||
|
||||
@@ -286,6 +286,7 @@ class TestKnownVehicleSettings(OpenpilotTestCase):
|
||||
keys = {i["key"] for i in _brand_items(schema["vehicle_settings"].get("toyota"))}
|
||||
assert "ToyotaEnforceStockLongitudinal" in keys
|
||||
assert "ToyotaStopAndGoHack" in keys
|
||||
assert "ToyotaEnhancedBsm" in keys
|
||||
assert "ToyotaTSS2Smooth" in keys
|
||||
|
||||
def test_tesla_has_coop_steering(self, schema):
|
||||
|
||||
Reference in New Issue
Block a user