fix(toyota): drop virtual cruise speed for now

This commit is contained in:
rav4kumar
2026-08-17 16:17:49 -07:00
parent 3b2247fd49
commit 0fd8368de4
10 changed files with 1 additions and 306 deletions
-1
View File
@@ -236,7 +236,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"TeslaMadsScreenButton", {PERSISTENT | BACKUP, INT, "0"}},
{"ToyotaEnforceStockLongitudinal", {PERSISTENT | BACKUP, BOOL, "0"}},
{"ToyotaStopAndGoHack", {PERSISTENT | BACKUP, BOOL, "0"}},
{"ToyotaVirtualCruiseSpeed", {PERSISTENT | BACKUP, BOOL, "0"}},
{"DynamicExperimentalControl", {PERSISTENT | BACKUP, BOOL, "0"}},
{"BlindSpot", {PERSISTENT | BACKUP, BOOL, "0"}},
@@ -11,12 +11,10 @@ from openpilot.system.ui.lib.multilang import tr, tr_noop
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.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.")
VIRTUAL_CRUISE_UNAVAILABLE = tr_noop("Virtual Cruise Speed is available only on supported Toyota TSS2 configurations with sunnypilot Longitudinal Control.")
DESCRIPTIONS = {
'enforce_stock_longitudinal': tr_noop(
@@ -26,13 +24,6 @@ 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.'
),
'virtual_cruise_speed': tr_noop(
'Use a sunnypilot-owned cruise target with the Toyota RES/SET buttons while sunnypilot longitudinal control is active. ' +
'This unlocks Custom ACC Speed Increments; set the short interval to 5 for next-5-unit tap behavior. ' +
'The Toyota cluster will continue to show the factory target and may differ from sunnypilot. ' +
'The direct button signals are route-validated on Corolla Cross and Prius TSS2, but held-button timing differs by platform. ' +
'This is an alpha feature; validate acceleration above the factory target in a controlled setting.'
),
}
@@ -56,17 +47,8 @@ class ToyotaSettings(BrandSettings):
enabled=lambda: not ui_state.engaged,
)
self.virtual_cruise_speed = toggle_item_sp(
lambda: tr("Virtual Cruise Speed (Alpha)"),
description=lambda: tr(DESCRIPTIONS["virtual_cruise_speed"]),
initial_state=ui_state.params.get_bool("ToyotaVirtualCruiseSpeed"),
callback=self._on_enable_virtual_cruise_speed,
enabled=lambda: not ui_state.engaged,
)
self.items = [
self.enforce_stock_longitudinal,
self.virtual_cruise_speed,
self.stop_and_go_hack,
]
@@ -78,9 +60,7 @@ class ToyotaSettings(BrandSettings):
if ui_state.params.get_bool("AlphaLongitudinalEnabled"):
ui_state.params.put_bool("AlphaLongitudinalEnabled", False)
ui_state.params.put_bool("ToyotaStopAndGoHack", False)
ui_state.params.put_bool("ToyotaVirtualCruiseSpeed", False)
self.stop_and_go_hack.action_item.set_state(False)
self.virtual_cruise_speed.action_item.set_state(False)
ui_state.params.put_bool("OnroadCycleRequested", True)
else:
self.enforce_stock_longitudinal.action_item.set_state(False)
@@ -114,46 +94,10 @@ class ToyotaSettings(BrandSettings):
ui_state.params.put_bool("ToyotaStopAndGoHack", False)
ui_state.params.put_bool("OnroadCycleRequested", True)
def _on_enable_virtual_cruise_speed(self, state: bool):
if state:
def confirm_callback(result: int):
enabled = result == DialogResult.CONFIRM
ui_state.params.put_bool("ToyotaVirtualCruiseSpeed", enabled)
self.virtual_cruise_speed.action_item.set_state(enabled)
if enabled:
ui_state.params.put_bool("OnroadCycleRequested", True)
content = (f"<h1>{self.virtual_cruise_speed.title}</h1><br>" +
f"<p>{self.virtual_cruise_speed.description}</p>")
dlg = ConfirmDialog(content, tr("Enable"), rich=True, callback=confirm_callback)
gui_app.push_widget(dlg)
else:
ui_state.params.put_bool("ToyotaVirtualCruiseSpeed", False)
ui_state.params.put_bool("OnroadCycleRequested", True)
def update_settings(self):
if ui_state.CP is not None:
longitudinal = ui_state.CP.openpilotLongitudinalControl
enforce_stock = self.enforce_stock_longitudinal.action_item.get_state()
virtual_cruise_available = bool(ui_state.CP_SP is not None and
ui_state.CP_SP.flags & ToyotaFlagsSP.VIRTUAL_CRUISE_SPEED_AVAILABLE)
if longitudinal and virtual_cruise_available:
self.virtual_cruise_speed.action_item.set_enabled(not ui_state.engaged)
virtual_cruise_desc = tr(DESCRIPTIONS["virtual_cruise_speed"])
show_virtual_cruise_desc = False
else:
self.virtual_cruise_speed.action_item.set_enabled(False)
if self.virtual_cruise_speed.action_item.get_state():
self.virtual_cruise_speed.action_item.set_state(False)
ui_state.params.put_bool("ToyotaVirtualCruiseSpeed", False)
virtual_cruise_desc = "<b>" + tr(VIRTUAL_CRUISE_UNAVAILABLE) + "</b>\n\n" + tr(DESCRIPTIONS["virtual_cruise_speed"])
show_virtual_cruise_desc = True
if self.virtual_cruise_speed.description != virtual_cruise_desc:
self.virtual_cruise_speed.set_description(virtual_cruise_desc)
if show_virtual_cruise_desc:
self.virtual_cruise_speed.show_description(True)
if longitudinal and not enforce_stock:
self.stop_and_go_hack.action_item.set_enabled(not ui_state.engaged)
@@ -170,12 +114,6 @@ class ToyotaSettings(BrandSettings):
if show_desc:
self.stop_and_go_hack.show_description(True)
else:
self.virtual_cruise_speed.action_item.set_enabled(False)
virtual_cruise_desc = "<b>" + tr(ONROAD_ONLY_DESCRIPTION) + "</b>\n\n" + tr(DESCRIPTIONS["virtual_cruise_speed"])
if self.virtual_cruise_speed.description != virtual_cruise_desc:
self.virtual_cruise_speed.set_description(virtual_cruise_desc)
self.virtual_cruise_speed.show_description(True)
self.stop_and_go_hack.action_item.set_enabled(False)
new_desc = "<b>" + tr(ONROAD_ONLY_DESCRIPTION) + "</b>\n\n" + tr(DESCRIPTIONS["stop_and_go_hack"])
if self.stop_and_go_hack.description != new_desc:
@@ -139,7 +139,6 @@ def initialize_params(params) -> list[dict[str, Any]]:
"ToyotaTSS2Long",
"ToyotaEnhancedBsm",
"ToyotaAutoHold",
"ToyotaVirtualCruiseSpeed",
])
return [{k: params.get(k, return_default=True)} for k in keys]
@@ -11,7 +11,6 @@ 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.sunnypilot.car.tesla.values import TeslaFlagsSP
from opendbc.sunnypilot.car.toyota.values import ToyotaFlagsSP, VIRTUAL_CRUISE_SPEED_CAR
from openpilot.common.params import Params
from openpilot.common.swaglog import cloudlog
from openpilot.common.hardware import HARDWARE
@@ -20,7 +19,6 @@ from openpilot.common.hardware import HARDWARE
# Wire-protocol version for the capabilities payload. Bump on breaking changes
# only; additive fields are backward-compatible and do not require a bump.
PROTOCOL_VERSION = 1
TOYOTA_VIRTUAL_CRUISE_SPEED_PLATFORMS = {str(platform) for platform in VIRTUAL_CRUISE_SPEED_CAR}
# All capability fields that rules may reference.
# Non-boolean fields must have defaults in CAPABILITY_DEFAULTS.
@@ -44,7 +42,6 @@ CAPABILITY_FIELDS = (
"device_type",
"subaru_has_sng",
"hyundai_alpha_long_available",
"toyota_virtual_cruise_speed_available",
)
CAPABILITY_LABELS: dict[str, str] = {
@@ -67,7 +64,6 @@ 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_virtual_cruise_speed_available": "Toyota Virtual Cruise Speed available",
}
# Explicit defaults for non-boolean capability fields
@@ -114,12 +110,6 @@ def _resolve_brand_capabilities(caps: dict, bundle_platform: str, CP) -> None:
caps["subaru_has_sng"] = not bool(CP.flags & (SubaruFlags.GLOBAL_GEN2 | SubaruFlags.HYBRID))
caps["has_stop_and_go"] = caps["subaru_has_sng"]
elif brand == "toyota":
if bundle_platform:
caps["toyota_virtual_cruise_speed_available"] = bundle_platform in TOYOTA_VIRTUAL_CRUISE_SPEED_PLATFORMS
elif CP is not None:
caps["toyota_virtual_cruise_speed_available"] = str(CP.carFingerprint) in TOYOTA_VIRTUAL_CRUISE_SPEED_PLATFORMS
def generate_capabilities(params: Params | None = None) -> dict:
"""Generate a SettingsCapabilities dict from CarParams + boolean params.
@@ -184,8 +174,6 @@ 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)
if caps["brand"] == "toyota":
caps["toyota_virtual_cruise_speed_available"] = bool(CP_SP.flags & ToyotaFlagsSP.VIRTUAL_CRUISE_SPEED_AVAILABLE)
except Exception:
cloudlog.exception("capabilities: failed to deserialize CarParamsSPPersistent")
@@ -759,21 +759,6 @@
"type": "capability",
"field": "has_icbm",
"equals": true
},
{
"type": "all",
"conditions": [
{
"type": "capability",
"field": "toyota_virtual_cruise_speed_available",
"equals": true
},
{
"type": "param",
"key": "ToyotaVirtualCruiseSpeed",
"equals": true
}
]
}
]
}
@@ -812,21 +797,6 @@
"type": "capability",
"field": "has_icbm",
"equals": true
},
{
"type": "all",
"conditions": [
{
"type": "capability",
"field": "toyota_virtual_cruise_speed_available",
"equals": true
},
{
"type": "param",
"key": "ToyotaVirtualCruiseSpeed",
"equals": true
}
]
}
]
}
@@ -2432,40 +2402,6 @@
"enablement": [
{
"type": "not_engaged"
},
{
"type": "param",
"key": "ToyotaVirtualCruiseSpeed",
"equals": false
}
]
},
{
"key": "ToyotaVirtualCruiseSpeed",
"widget": "toggle",
"needs_onroad_cycle": true,
"title": "Toyota: Virtual Cruise Speed (Alpha)",
"description": "Uses a sunnypilot-owned cruise target with the Toyota RES/SET buttons and unlocks Custom ACC Speed Intervals. Set the short interval to 5 for next-5-unit tap behavior. The Toyota cluster continues to show the factory target and may differ from sunnypilot. The direct button signals are route-validated on Corolla Cross and Prius TSS2, but held-button timing differs by platform. Validate acceleration above the factory target in a controlled setting.",
"visibility": [
{
"type": "capability",
"field": "toyota_virtual_cruise_speed_available",
"equals": true
}
],
"enablement": [
{
"type": "not_engaged"
},
{
"type": "capability",
"field": "has_longitudinal_control",
"equals": true
},
{
"type": "param",
"key": "ToyotaEnforceStockLongitudinal",
"equals": false
}
]
},
@@ -100,14 +100,6 @@ sections:
- type: capability
field: has_icbm
equals: true
- type: all
conditions:
- type: capability
field: toyota_virtual_cruise_speed_available
equals: true
- type: param
key: ToyotaVirtualCruiseSpeed
equals: true
items:
- key: CustomAccIncrementsEnabled
widget: toggle
@@ -129,14 +121,6 @@ sections:
- type: capability
field: has_icbm
equals: true
- type: all
conditions:
- type: capability
field: toyota_virtual_cruise_speed_available
equals: true
- type: param
key: ToyotaVirtualCruiseSpeed
equals: true
sub_panels:
- id: custom_acc_intervals
label: Custom ACC Speed Intervals Settings
@@ -113,28 +113,6 @@ sections:
description: sunnypilot will not take over control of gas and brakes. Factory Toyota longitudinal control will be used.
enablement:
- $ref: '#/macros/not_engaged'
- type: param
key: ToyotaVirtualCruiseSpeed
equals: false
- key: ToyotaVirtualCruiseSpeed
widget: toggle
needs_onroad_cycle: true
title: 'Toyota: Virtual Cruise Speed (Alpha)'
description: Uses a sunnypilot-owned cruise target with the Toyota RES/SET buttons and unlocks Custom ACC Speed
Intervals. Set the short interval to 5 for next-5-unit tap behavior. The Toyota cluster continues to show the
factory target and may differ from sunnypilot. The direct button signals are route-validated on Corolla Cross
and Prius TSS2, but held-button timing differs by platform. Validate acceleration above the factory target in a
controlled setting.
visibility:
- type: capability
field: toyota_virtual_cruise_speed_available
equals: true
enablement:
- $ref: '#/macros/not_engaged'
- $ref: '#/macros/longitudinal'
- type: param
key: ToyotaEnforceStockLongitudinal
equals: false
- key: ToyotaStopAndGoHack
widget: toggle
needs_onroad_cycle: true
@@ -13,15 +13,7 @@ the same commit so the bump shows up in code review.
from __future__ import annotations
from typing import cast
from openpilot.cereal import custom
from openpilot.common.params import Params
from openpilot.common.parameterized import parameterized
from openpilot.common.test import OpenpilotTestCase
from opendbc.car.structs import car
from opendbc.car.toyota.values import CAR as TOYOTA_CAR
from opendbc.sunnypilot.car.toyota.values import ToyotaFlagsSP
from openpilot.sunnypilot.sunnylink.capabilities import (
CAPABILITY_DEFAULTS,
CAPABILITY_FIELDS,
@@ -46,24 +38,6 @@ class FakeParams:
return bool(self.values.get(key, False))
def build_persistent_toyota_params(platform, *, sp_flags=0) -> Params:
CP = car.CarParams.new_message()
CP.brand = "toyota"
CP.carFingerprint = str(platform)
CP.pcmCruise = True
CP.openpilotLongitudinalControl = True
CP_SP = custom.CarParamsSP.new_message()
CP_SP.flags = int(sp_flags)
return cast(Params, FakeParams(
{
"CarParamsPersistent": CP.to_bytes(),
"CarParamsSPPersistent": CP_SP.to_bytes(),
}
))
def caps():
return generate_capabilities()
@@ -111,66 +85,6 @@ class TestOpaquePerBrandFlags(OpenpilotTestCase):
assert caps["hyundai_alpha_long_available"] is False
class TestToyotaVirtualCruiseSpeedCapability(OpenpilotTestCase):
def test_field_present_and_labeled(self):
assert "toyota_virtual_cruise_speed_available" in CAPABILITY_FIELDS
assert "toyota_virtual_cruise_speed_available" in CAPABILITY_LABELS
def test_default_false(self):
caps = generate_capabilities(cast(Params, FakeParams()))
assert caps["toyota_virtual_cruise_speed_available"] is False
@parameterized.expand(
(
(TOYOTA_CAR.TOYOTA_COROLLA_TSS2, True),
(TOYOTA_CAR.TOYOTA_PRIUS_TSS2, True),
(TOYOTA_CAR.TOYOTA_RAV4_TSS2, False),
)
)
def test_bundle_platform_gating(self, platform, expected):
params = FakeParams(
{
"CarPlatformBundle": {
"brand": "toyota",
"platform": str(platform),
},
}
)
caps = generate_capabilities(cast(Params, params))
assert caps["toyota_virtual_cruise_speed_available"] is expected
@parameterized.expand(
(
(TOYOTA_CAR.TOYOTA_COROLLA_TSS2, ToyotaFlagsSP.VIRTUAL_CRUISE_SPEED_AVAILABLE, True),
(TOYOTA_CAR.TOYOTA_COROLLA_TSS2, 0, True),
(TOYOTA_CAR.TOYOTA_PRIUS_TSS2, ToyotaFlagsSP.VIRTUAL_CRUISE_SPEED_AVAILABLE, True),
(TOYOTA_CAR.TOYOTA_PRIUS_TSS2, 0, True),
(TOYOTA_CAR.TOYOTA_RAV4_TSS2, ToyotaFlagsSP.VIRTUAL_CRUISE_SPEED_AVAILABLE, False),
)
)
def test_persistent_car_params_platform_gating(self, platform, sp_flags, expected):
caps = generate_capabilities(build_persistent_toyota_params(platform, sp_flags=sp_flags))
assert caps["toyota_virtual_cruise_speed_available"] is expected
@parameterized.expand(
(
(TOYOTA_CAR.TOYOTA_COROLLA_TSS2, TOYOTA_CAR.TOYOTA_RAV4_TSS2, True),
(TOYOTA_CAR.TOYOTA_PRIUS_TSS2, TOYOTA_CAR.TOYOTA_RAV4_TSS2, True),
(TOYOTA_CAR.TOYOTA_RAV4_TSS2, TOYOTA_CAR.TOYOTA_COROLLA_TSS2, False),
(TOYOTA_CAR.TOYOTA_RAV4_TSS2, TOYOTA_CAR.TOYOTA_PRIUS_TSS2, False),
)
)
def test_bundle_platform_takes_precedence_over_stale_persistent_params(self, bundle_platform, persistent_platform, expected):
params = build_persistent_toyota_params(persistent_platform, sp_flags=ToyotaFlagsSP.VIRTUAL_CRUISE_SPEED_AVAILABLE)
params.values["CarPlatformBundle"] = {
"brand": "toyota",
"platform": str(bundle_platform),
}
caps = generate_capabilities(params)
assert caps["toyota_virtual_cruise_speed_available"] is expected
class TestCapabilitiesShape(OpenpilotTestCase):
def test_all_fields_present(self, caps):
for field in CAPABILITY_FIELDS:
@@ -106,26 +106,6 @@ def _references_capability_field(rules: list[dict[str, Any]] | None, field: str)
return found
def _has_toyota_virtual_cruise_gate(rules: list[dict[str, Any]] | None) -> bool:
def _walk(rule: dict[str, Any]) -> bool:
if rule.get("type") == "all":
conditions = rule.get("conditions", [])
has_capability = any(
c.get("type") == "capability" and c.get("field") == "toyota_virtual_cruise_speed_available" and c.get("equals") is True for c in conditions
)
has_param = any(c.get("type") == "param" and c.get("key") == "ToyotaVirtualCruiseSpeed" and c.get("equals") is True for c in conditions)
if has_capability and has_param:
return True
if rule.get("type") == "not" and "condition" in rule:
return _walk(rule["condition"])
if rule.get("type") in ("any", "all"):
return any(_walk(c) for c in rule.get("conditions", []))
return False
return any(_walk(rule) for rule in rules or [])
def schema():
return generate_schema()
@@ -237,23 +217,3 @@ class TestNotEngagedReplacement(OpenpilotTestCase):
assert "not_engaged" in rule_types, f"{key} missing not_engaged"
class TestToyotaVirtualCruiseSpeed(OpenpilotTestCase):
def test_vehicle_toggle_contract(self, schema):
toyota = schema["vehicle_settings"]["toyota"]
item = next((item for item in toyota["items"] if item.get("key") == "ToyotaVirtualCruiseSpeed"), None)
assert item is not None
assert item["widget"] == "toggle"
assert item.get("needs_onroad_cycle") is True
assert _references_capability_field(item.get("visibility"), "toyota_virtual_cruise_speed_available")
assert _references_capability_field(item.get("enablement"), "has_longitudinal_control")
assert "not_engaged" in _flatten_rule_types(item.get("enablement"))
def test_custom_acc_section_links_virtual_cruise_opt_in(self, schema):
section = _find_section(schema, "cruise", "custom_acc_increments")
assert section is not None
assert _has_toyota_virtual_cruise_gate(section.get("enablement"))
item = _find_item(schema, "CustomAccIncrementsEnabled")
assert item is not None
assert _has_toyota_virtual_cruise_gate(item.get("enablement"))
@@ -305,11 +305,10 @@ class TestKnownVehicleSettings(OpenpilotTestCase):
keys = {i["key"] for i in _brand_items(schema["vehicle_settings"].get("hyundai"))}
assert "HyundaiLongitudinalTuning" in keys
def test_toyota_has_enforce_stock_stop_go_and_virtual_cruise(self, schema):
def test_toyota_has_enforce_stock_stop_go(self, schema):
keys = {i["key"] for i in _brand_items(schema["vehicle_settings"].get("toyota"))}
assert "ToyotaEnforceStockLongitudinal" in keys
assert "ToyotaStopAndGoHack" in keys
assert "ToyotaVirtualCruiseSpeed" in keys
def test_tesla_has_coop_steering(self, schema):
keys = {i["key"] for i in _brand_items(schema["vehicle_settings"].get("tesla"))}