Restore Tesla AOL for standard and screen harnesses with matching firmware

This commit is contained in:
firestar5683
2026-11-10 17:49:38 -06:00
55 changed files with 376 additions and 46 deletions
@@ -3,24 +3,30 @@ from opendbc.car.tesla.values import CAR, TeslaFlags
SCREEN_WORDS = frozenset((512, 513, 1536, 1537, 768, 769, 1792, 1793))
BASE_WORDS = frozenset((0, 1, 256, 257))
ORDINARY_WORDS = frozenset((2048, 2049, 2304, 2305, 3072, 3073, 3328, 3329))
AOL_WORDS = SCREEN_WORDS | ORDINARY_WORDS
def screen_tap_supported(cp):
def modern_aol_supported(cp):
try:
if (cp.brand != 'tesla' or cp.carFingerprint not in (CAR.TESLA_MODEL_3, CAR.TESLA_MODEL_Y) or
cp.passive or cp.dashcamOnly or cp.notCar or cp.alternativeExperience not in (0, 32) or len(cp.safetyConfigs) != 1 or
int(cp.safetyConfigs[0].safetyModel.raw) != 10 or
not cp.flags & TeslaFlags.HAS_VEHICLE_BUS or
cp.flags & ~int(TeslaFlags.MISSING_DAS_SETTINGS | TeslaFlags.HAS_VEHICLE_BUS | TeslaFlags.AOL_SCREEN_BUTTON)):
return False
word = int(cp.safetyConfigs[0].safetyParam)
return (word in BASE_WORDS | SCREEN_WORDS and (not word & 256 or cp.carFingerprint == CAR.TESLA_MODEL_3) and
return (word in BASE_WORDS | AOL_WORDS and (not word & 256 or cp.carFingerprint == CAR.TESLA_MODEL_3) and
bool(word & 1) == bool(cp.openpilotLongitudinalControl) and
bool(word & 512) == bool(cp.flags & TeslaFlags.AOL_SCREEN_BUTTON))
bool(word & 512) == bool(cp.flags & TeslaFlags.AOL_SCREEN_BUTTON) and
(not word & 512 or bool(cp.flags & TeslaFlags.HAS_VEHICLE_BUS)))
except (AttributeError, ValueError, TypeError, IndexError):
return False
def screen_tap_supported(cp):
return bool(modern_aol_supported(cp) and cp.flags & TeslaFlags.HAS_VEHICLE_BUS)
modern_screen_supported = screen_tap_supported
@@ -29,6 +35,24 @@ def screen_qualified(cp, *, marked_only=False):
cp.alternativeExperience in ((32,) if marked_only else (0, 32)))
def modern_aol_qualified(cp, *, marked_only=False):
return bool(modern_aol_supported(cp) and int(cp.safetyConfigs[0].safetyParam) in AOL_WORDS and
cp.alternativeExperience in ((32,) if marked_only else (0, 32)))
def apply_modern_aol(cp, requested, screen, brake_disengage):
if not modern_aol_supported(cp):
return
use_screen = requested and screen and screen_tap_supported(cp)
base = int(cp.safetyConfigs[0].safetyParam) & 257
cp.flags &= ~int(TeslaFlags.AOL_SCREEN_BUTTON)
cp.safetyConfigs[0].safetyParam = base
if requested:
cp.safetyConfigs[0].safetyParam = base | (512 if use_screen else 2048) | (1024 if brake_disengage else 0)
if use_screen:
cp.flags |= TeslaFlags.AOL_SCREEN_BUTTON.value
def apply_screen_button(cp, requested, brake_disengage):
if not screen_tap_supported(cp):
return
@@ -1,6 +1,7 @@
#pragma once
static bool tesla_screen_enabled = false;
static bool tesla_screen_tap_enabled = false;
static bool tesla_screen_brake_disengage = false;
static bool tesla_screen_longitudinal = false;
static bool tesla_screen_initialized = false;
@@ -75,7 +76,7 @@ static uint8_t tesla_screen_permission(void) {
}
static void tesla_screen_optional_rx(const CANPacket_t *msg) {
if (tesla_screen_enabled && msg_matches(msg, 0x3DFU, 1U, 8U)) {
if (tesla_screen_tap_enabled && msg_matches(msg, 0x3DFU, 1U, 8U)) {
const bool pressed = msg->data[3] == 3U;
if (tesla_screen_initialized && pressed && !tesla_screen_pressed && aol_rx_healthy() &&
tesla_screen_physical_ready() && !(tesla_screen_brake_disengage && brake_pressed)) {
@@ -132,9 +133,11 @@ static void tesla_screen_rx(const CANPacket_t *msg, bool autopark) {
static bool tesla_screen_param_valid(uint16_t param) {
const uint16_t screen_param = (uint16_t)(param & ~256U);
bool valid = (screen_param == 512U) || (screen_param == 1536U);
bool valid = (screen_param == 512U) || (screen_param == 1536U) ||
(screen_param == 2048U) || (screen_param == 3072U);
#ifdef ALLOW_DEBUG
valid = valid || (screen_param == 513U) || (screen_param == 1537U);
valid = valid || (screen_param == 513U) || (screen_param == 1537U) ||
(screen_param == 2049U) || (screen_param == 3073U);
#endif
return valid;
}
@@ -144,8 +147,9 @@ static void tesla_screen_configure(uint16_t param) {
tesla_screen_reset();
tesla_screen_enabled = tesla_screen_param_valid(screen_param);
tesla_screen_enabled = tesla_screen_enabled && ((unsigned int)alternative_experience == 32U);
tesla_screen_brake_disengage = (screen_param == 1536U) || (screen_param == 1537U);
tesla_screen_longitudinal = (screen_param == 513U) || (screen_param == 1537U);
tesla_screen_tap_enabled = tesla_screen_enabled && GET_FLAG(screen_param, 512U);
tesla_screen_brake_disengage = tesla_screen_enabled && GET_FLAG(screen_param, 1024U);
tesla_screen_longitudinal = tesla_screen_enabled && GET_FLAG(screen_param, 1U);
if (tesla_screen_enabled) {
static const AolSafetyPolicy policy = {
.reset = tesla_screen_reset,
@@ -0,0 +1,89 @@
import os
import unittest
from opendbc.safety.tests.common import CANPackerSafety
from opendbc.safety.tests.libsafety import libsafety_py
from opendbc.safety.tests import test_tesla_screen_button as screen
class TestTeslaOrdinaryAol(unittest.TestCase):
start = screen.TestTeslaScreenButton.start
feed = screen.TestTeslaScreenButton.feed
permission = screen.TestTeslaScreenButton.permission
touch = screen.TestTeslaScreenButton.touch
tearDown = screen.TestTeslaScreenButton.tearDown
def setUp(self):
self.lib = libsafety_py.libsafety
self.packer = CANPackerSafety('tesla_model3_party')
self.start(2048)
def test_standard_harness_brake_choice_and_real_cruise_rearm(self):
for word in (2048, 2304, 3072, 3328):
with self.subTest(word=word):
self.start(word)
self.touch(0)
self.touch(3)
self.assertEqual(self.permission(), 0, 'optional bus1 gestures cannot arm ordinary AOL')
self.feed(state=1)
self.assertEqual(self.permission(3), 1)
self.touch(0)
self.touch(3)
self.assertEqual(self.permission(), 1, 'optional bus1 gestures cannot cancel ordinary AOL')
self.feed(state=1, brake=True)
self.assertEqual(self.permission(), 0 if word & 1024 else 1)
self.feed(state=1)
self.assertEqual(self.permission(), 0 if word & 1024 else 1)
self.feed(state=2)
self.assertEqual(self.permission(), 1)
self.feed(state=0)
self.assertEqual(self.permission(), 0)
self.feed(state=1)
self.assertEqual(self.permission(), 0, 'availability cannot undo a cancellation')
def test_physical_faults_heartbeat_and_request_expiry_still_withdraw(self):
for fault in ({'hands': 3}, {'gear': 0}, {'door': True}, {'eps': 3}, {'autopark': 3}, {'state': 5}):
with self.subTest(fault=fault):
self.start(2048)
self.feed(state=1)
self.assertEqual(self.permission(), 1)
self.feed(**({'state': 1} | fault))
self.assertEqual(self.permission(), 0)
self.feed(state=1)
self.assertEqual(self.permission(), 0)
self.start(2048)
self.feed(state=1)
self.assertEqual(self.permission(), 1)
self.lib.set_aol_test_heartbeat(False)
self.assertEqual(self.permission(), 0)
self.lib.set_aol_test_heartbeat(True)
self.assertEqual(self.permission(), 0)
self.feed(state=2)
self.assertEqual(self.permission(), 1)
self.time += 1_100_000
self.lib.set_timer(self.time)
self.assertEqual(self.lib.aol_get_permission_mask(), 0)
def test_longitudinal_stays_independent_and_release_debug_limits_remain(self):
positive = self.packer.make_can_msg_safety('DAS_control', 0, {'DAS_accelMin': 1, 'DAS_accelMax': 1})
for word in (2048, 3072, 2049, 3073):
if word & 1 and os.environ.get('TESLA_SCREEN_NATIVE_RELEASE') == '1':
self.assertEqual(self.lib.set_safety_hooks(10, word), -1)
continue
self.start(word)
self.feed(state=1)
self.assertEqual(self.permission(3), 1)
self.assertFalse(self.lib.safety_tx_hook(positive))
self.feed(state=2)
self.assertEqual(self.permission(3), 3 if word & 1 else 1)
if word & 1:
self.assertTrue(self.lib.safety_tx_hook(positive))
self.feed(state=2, brake=True)
self.assertFalse(self.lib.safety_tx_hook(positive))
def test_profile_must_be_exact_and_saved_aol_opt_in_is_required(self):
for word in (2048 | 512, 2048 | 16, 2048 | 2, 2048 | 4096, 3072 | 512):
self.assertEqual(self.lib.set_safety_hooks(10, word), -1)
self.lib.set_alternative_experience(0)
self.assertEqual(self.lib.set_safety_hooks(10, 2048), 0)
self.feed(state=1)
self.assertEqual(self.permission(), 0)
Binary file not shown.
@@ -260,7 +260,8 @@ int main() {
ford.safety_param = static_cast<uint16_t>(word);
assert(aol_capable(ford, 6U, VEHICLE_REGISTRY) == expected);
}
constexpr uint16_t tesla_screen_words[] = {512U, 513U, 768U, 769U, 1536U, 1537U, 1792U, 1793U};
constexpr uint16_t tesla_screen_words[] = {512U, 513U, 768U, 769U, 1536U, 1537U, 1792U, 1793U,
2048U, 2049U, 2304U, 2305U, 3072U, 3073U, 3328U, 3329U};
for (uint32_t word = 0U; word <= 65535U; ++word) {
bool expected = false;
for (const auto exact : tesla_screen_words) expected |= word == exact;
+11 -11
View File
@@ -2,18 +2,18 @@ from opendbc.car import structs
from opendbc.car.tesla.preap.aol import qualified, temporary_restriction as preap_temporary_restriction
from openpilot.starpilot.aol.policy import AolVehiclePolicy
from openpilot.starpilot.car.tesla.stock_intent import TeslaPreapCardIntent
from opendbc.car.tesla.screen_button import screen_tap_supported, screen_qualified, SCREEN_WORDS
from opendbc.car.tesla.screen_button import modern_aol_supported, modern_aol_qualified, AOL_WORDS
from openpilot.starpilot.car.tesla.screen_intent import TeslaScreenCardIntent
def policy_for(cp):
if screen_tap_supported(cp):
admitted = screen_qualified(cp)
if modern_aol_supported(cp):
admitted = modern_aol_qualified(cp)
return AolVehiclePolicy(intent_supported=admitted, settings_supported=True,
runtime_supported=admitted, normal_runtime_supported=admitted,
ordinary_axis_ack_required=screen_qualified(cp, marked_only=True),
ordinary_axis_ack_required=modern_aol_qualified(cp, marked_only=True),
full_axis_runtime_required=admitted,
cruise_main_required=not screen_qualified(cp, marked_only=True),
cruise_main_required=not modern_aol_qualified(cp, marked_only=True),
explicit_latch=admitted, alternative_experience_addition=32 if admitted else 0)
admitted = qualified(cp)
return AolVehiclePolicy(intent_supported=admitted, settings_supported=admitted,
@@ -25,31 +25,31 @@ def policy_for(cp):
def native_profile_supported(model, param):
return (model == 39 and param in (0, 1, 2, 3, 6, 7)) or (model == 10 and param in SCREEN_WORDS)
return (model == 39 and param in (0, 1, 2, 3, 6, 7)) or (model == 10 and param in AOL_WORDS)
def native_accepts_cp(cp, model, param):
return bool((qualified(cp, marked_only=True) or screen_qualified(cp, marked_only=True)) and
return bool((qualified(cp, marked_only=True) or modern_aol_qualified(cp, marked_only=True)) and
native_profile_supported(model, param) and len(cp.safetyConfigs) == 1 and
int(cp.safetyConfigs[0].safetyModel.raw) == model and int(cp.safetyConfigs[0].safetyParam) == param)
def native_latch_rejected(cp, native):
return (qualified(cp, marked_only=True) or screen_qualified(cp, marked_only=True)) and native.requestedLateral and not native.lateralAllowed
return (qualified(cp, marked_only=True) or modern_aol_qualified(cp, marked_only=True)) and native.requestedLateral and not native.lateralAllowed
def ordinary_axis_request_allowed(cp, state):
return bool((qualified(cp, marked_only=True) or screen_qualified(cp, marked_only=True)) and
return bool((qualified(cp, marked_only=True) or modern_aol_qualified(cp, marked_only=True)) and
state.canValid and not state.canTimeout and not state.steerFaultPermanent)
def retain_on_native_denial(cp, native, state):
return preap_temporary_restriction(cp, state) or bool(
screen_qualified(cp, marked_only=True) and state is not None and state.canValid and not state.canTimeout and
modern_aol_qualified(cp, marked_only=True) and state is not None and state.canValid and not state.canTimeout and
not state.steerFaultPermanent and not state.steeringDisengage and not state.doorOpen and not state.accFaulted and
(state.gearShifter in (structs.CarState.GearShifter.reverse, structs.CarState.GearShifter.neutral) or
state.gearShifter == structs.CarState.GearShifter.drive and state.steerFaultTemporary))
def create_intent(cp, settings):
return TeslaScreenCardIntent(cp, settings) if screen_qualified(cp) else TeslaPreapCardIntent(cp, settings)
return TeslaScreenCardIntent(cp, settings) if modern_aol_qualified(cp) else TeslaPreapCardIntent(cp, settings)
+2 -1
View File
@@ -10,7 +10,8 @@ inline constexpr AolSafetyProfile TESLA_PREAP_AOL_PROFILE{39U, tesla_preap_aol_p
inline bool tesla_screen_aol_param(uint16_t param) {
param &= ~256U;
return param == 512U || param == 513U || param == 1536U || param == 1537U;
return param == 512U || param == 513U || param == 1536U || param == 1537U ||
param == 2048U || param == 2049U || param == 3072U || param == 3073U;
}
inline constexpr AolSafetyProfile TESLA_SCREEN_AOL_PROFILE{10U, tesla_screen_aol_param, true};
@@ -9,7 +9,8 @@ def supported(cp):
cp.flags & ~int(TeslaFlags.MISSING_DAS_SETTINGS | TeslaFlags.HAS_VEHICLE_BUS | TeslaFlags.AOL_SCREEN_BUTTON)):
return False
word = int(cp.safetyConfigs[0].safetyParam)
return word in (0, 1, 256, 257, 512, 513, 768, 769, 1536, 1537, 1792, 1793) and bool(word & 1) == bool(cp.openpilotLongitudinalControl)
return (word in (0, 1, 256, 257, 512, 513, 768, 769, 1536, 1537, 1792, 1793, 2048, 2049, 2304, 2305, 3072, 3073, 3328, 3329) and
bool(word & 1) == bool(cp.openpilotLongitudinalControl))
except (AttributeError, TypeError, ValueError, IndexError):
return False
@@ -7,6 +7,7 @@ from openpilot.starpilot.aol.intent import AolCardIntent, ButtonType
class TeslaScreenCardIntent(AolCardIntent):
def __init__(self, cp, settings):
super().__init__(settings, explicit_latch=True)
self.screen_enabled = bool(cp.safetyConfigs[0].safetyParam & 512)
self.screen_override = None
self.brake_disengage = bool(cp.safetyConfigs[0].safetyParam & 1024)
self.previous_enabled = False
@@ -23,7 +24,7 @@ class TeslaScreenCardIntent(AolCardIntent):
available = bool(CS.cruiseState.available)
# Stock cruise availability does not revoke an explicit screen selection.
if (engaged and not self.previous_enabled) or (self.previous_available and not available and not CS.brakePressed and
self.screen_override is not True):
(not self.screen_enabled or self.screen_override is not True)):
self.screen_override = None if engaged and not self.previous_enabled else False
self.brake_blocked = False
self.pause_lateral = False
@@ -40,7 +41,7 @@ class TeslaScreenCardIntent(AolCardIntent):
if fault or cancel or not self.settings.enabled:
self.screen_override = False
for event in CS.buttonEvents:
if event.type != ButtonType.lkas:
if event.type != ButtonType.lkas or not self.screen_enabled:
continue
fresh_press = bool(event.pressed and not self.screen_held)
self.screen_held = bool(event.pressed)
@@ -0,0 +1,103 @@
"""Standard and screen harnesses select independent, exact AOL profiles."""
from dataclasses import replace
import pytest
from opendbc.car import structs
from opendbc.car.tesla.values import CAR
from opendbc.car.tesla.screen_button import apply_modern_aol, modern_aol_supported, modern_aol_qualified, screen_tap_supported
from opendbc.car.tesla.tests.test_screen_button import screen_params
from openpilot.common.params import Params
from openpilot.starpilot.aol.intent import AolSettings, ButtonType
from openpilot.starpilot.car.tesla.aol import policy_for, native_accepts_cp
from openpilot.starpilot.car.tesla.screen_intent import TeslaScreenCardIntent
from openpilot.starpilot.car.tesla.tests.test_screen_intent import state
from openpilot.starpilot.vehicle_preferences import VehicleStartupPreferences
from openpilot.starpilot.galaxy.tests.test_tesla_screen_settings import vehicle
from openpilot.starpilot.galaxy.settings import AuthorityContext, SettingsGateway
@pytest.mark.parametrize('candidate', (CAR.TESLA_MODEL_3, CAR.TESLA_MODEL_Y))
@pytest.mark.parametrize('harness', (False, True))
@pytest.mark.parametrize('screen', (False, True))
@pytest.mark.parametrize('long', (False, True))
@pytest.mark.parametrize('brake', (False, True))
def test_profiles_settings_and_exact_native_identity(candidate, harness, screen, long, brake):
cp = screen_params(candidate, harness=harness, long=long)
assert modern_aol_supported(cp) and policy_for(cp).settings_supported
assert screen_tap_supported(cp) is harness
apply_modern_aol(cp, True, screen, brake)
expected = (512 if harness and screen else 2048) + int(long) + 1024 * brake
assert cp.safetyConfigs[0].safetyParam == expected
assert modern_aol_qualified(cp) and policy_for(cp).runtime_supported
cp.alternativeExperience = 32
assert native_accepts_cp(cp, 10, expected)
assert not native_accepts_cp(cp, 10, expected ^ 1024)
apply_modern_aol(cp, False, screen, brake)
assert cp.safetyConfigs[0].safetyParam == int(long)
assert not modern_aol_qualified(cp)
@pytest.mark.parametrize('brake', (False, True))
@pytest.mark.parametrize('cooperative', (False, True))
def test_actual_startup_selection_is_frozen_and_master_off_clears(tmp_path, brake, cooperative):
params = Params(str(tmp_path))
for key, value in (('AlwaysOnLateral', True), ('TeslaAOLDisengageOnBrake', brake), ('TeslaCoopSteering', cooperative)):
params.put_bool(key, value, block=True)
saved = VehicleStartupPreferences.read(params, enabled=True)
cp = screen_params(harness=False)
saved.prepare(cp)
word = 2048 + 1024 * brake + 256 * cooperative
assert cp.safetyConfigs[0].safetyParam == word
params.put_bool('TeslaAOLDisengageOnBrake', not brake, block=True)
saved.finalize(cp)
assert cp.safetyConfigs[0].safetyParam == word
params.put_bool('AlwaysOnLateral', False, block=True)
VehicleStartupPreferences.read(params, enabled=True).prepare(cp)
assert cp.safetyConfigs[0].safetyParam == 256 * cooperative
assert not policy_for(cp).runtime_supported
@pytest.mark.parametrize('brake', (False, True))
def test_ordinary_intent_brake_rearm_and_screen_input_refusal(brake):
cp = screen_params(harness=False)
apply_modern_aol(cp, True, False, brake)
owner = TeslaScreenCardIntent(cp, AolSettings(True, 0, 9, 0, (0, 0, 0), (0, 0, 0)))
owner.update(state().as_reader(), now_ns=1)
assert owner.allowed_latch
owner.update(state(press=True).as_reader(), now_ns=2)
assert owner.allowed_latch, 'screen input must have no authority on the standard harness'
owner.update(state(brake=True).as_reader(), now_ns=3)
assert owner.allowed_latch is not brake
owner.update(state().as_reader(), now_ns=4)
assert owner.allowed_latch is not brake
owner.update(state(enabled=True).as_reader(), now_ns=5)
assert owner.allowed_latch
cs = state(enabled=True)
cs.buttonEvents = [structs.CarState.ButtonEvent(type=ButtonType.cancel, pressed=True)]
owner.update(cs.as_reader(), now_ns=6)
assert not owner.allowed_latch
owner.settings = replace(owner.settings, enabled=False)
owner.update(state(enabled=True).as_reader(), now_ns=7)
assert not owner.allowed_latch
@pytest.mark.parametrize('harness', (False, True))
def test_actual_ui_master_and_brake_toggle_with_either_harness(tmp_path, harness):
params = Params(str(tmp_path))
cp = vehicle(harness=harness)
class Owner:
context = AuthorityContext(True, cp, cp.to_bytes())
def sample(self):
return self.context
owner = Owner()
gateway = SettingsGateway(params, owner, clock=lambda: 100.0)
page = gateway.page('vehicle', 'session', b'generation')
labels = {row['label'] for row in page['rows']}
assert 'Disengage AOL on Brake' in labels
assert ('Three-Finger AOL Tap' in labels) is harness
aol = gateway.page('aol', 'session', b'generation')
assert next(row for row in aol['rows'] if row['label'] == 'Enable Always On Lateral')['available']
index = next(i for i, row in enumerate(page['rows']) if row['label'] == 'Disengage AOL on Brake')
intent = gateway.preview(page['view'], index, 0, 'session', b'generation', value='On')
assert gateway.confirm(intent['intent'], 'session', b'generation')
assert params.get_bool('TeslaAOLDisengageOnBrake')
assert cp.safetyConfigs[0].safetyParam == 0
@@ -0,0 +1,99 @@
"""Ordinary harness AOL through real parser, intent, native and axis callers."""
from types import SimpleNamespace
from typing import cast
import pytest
from opendbc.can import CANPacker
from opendbc.car.tesla.interface import CarInterface
from opendbc.car.tesla.screen_button import apply_modern_aol
from opendbc.car.tesla.tests.test_screen_button import screen_params
from opendbc.safety.tests.libsafety import libsafety_py
from openpilot.cereal import log
from openpilot.selfdrive.selfdrived.events import Events
from openpilot.selfdrive.selfdrived.selfdrived import SelfdriveD
from openpilot.starpilot.aol.intent import AolSettings
from openpilot.starpilot.aol.runtime import AxisDecision
from openpilot.starpilot.aol.wire import IntentState, PandaSlot, SafetyState
from openpilot.starpilot.car.tesla.screen_intent import TeslaScreenCardIntent
class HealthyPeers(dict):
def all_checks(self, services):
return all(service in self for service in services)
@pytest.mark.parametrize('cooperative', [False, True])
@pytest.mark.parametrize('brake_disengage', [False, True])
def test_ordinary_axis_actual_parser_native_and_selfdrived(cooperative, brake_disengage):
cp = screen_params(harness=False)
apply_modern_aol(cp, True, False, brake_disengage)
cp.safetyConfigs[0].safetyParam |= 256 * cooperative
cp.alternativeExperience = 32
ci = CarInterface(cp)
owner = TeslaScreenCardIntent(cp, AolSettings(True, 0., 0, 0, (0, 0, 0), (0, 0, 0)))
packer = CANPacker('tesla_model3_party')
peers = HealthyPeers(modelV2=SimpleNamespace(),
extrinsicsCalibration=SimpleNamespace(calStatus=log.ExtrinsicsCalibration.Status.calibrated),
driverMonitoringState=SimpleNamespace(lockout=False, alwaysOnLockout=False, alertLevel=0))
sd = SimpleNamespace(CP=cp, active=False, enabled=False, initialized=True, sm=peers, aol_settings=owner.settings,
aol_axis_decision=AxisDecision(), aol_car_state_log_ns=0, aol_session_id='screen-test',
aol_dm_lateral_inhibit=False, nostalgia_paddle_cancel=False, aol_cruise_main_required=False,
events=Events())
native = libsafety_py.libsafety
native.init_tests()
native.set_alternative_experience(32)
native.set_safety_hooks(10, cp.safetyConfigs[0].safetyParam)
native.set_aol_test_heartbeat(True)
try:
for tick in range(250):
now = 1_000_000_000 + tick * 10_000_000
native.set_timer(now // 1000)
stock_state = 0 if tick < 20 else 1 if 80 <= tick < 140 else 2
messages: tuple[tuple[str, int, dict[str, float]], ...] = (
('DAS_control', 2, {}), ('DAS_steeringControl', 2, {}),
('SCCM_steeringAngleSensor', 2, {}), ('DAS_status', 2, {}), ('DAS_settings', 2, {}),
('DI_speed', 0, {'DI_vehicleSpeed': 0}),
('ESP_B', 0, {'ESP_vehicleSpeed': 0, 'ESP_wheelSpeedsQF': 1, 'ESP_vehicleStandstillSts': 1}),
('EPAS3S_sysStatus', 0, {'EPAS3S_internalSAS': 0, 'EPAS3S_eacStatus': 1,
'EPAS3S_handsOnLevel': 3 if tick >= 240 else 0, 'EPAS3S_torsionBarTorque': 0}),
('DI_systemStatus', 0, {'DI_gear': 4, 'DI_accelPedalPos': 20 if tick % 30 < 15 else 0}),
('ESP_status', 0, {'ESP_driverBrakeApply': 2 if 100 <= tick < 120 else 1}),
('UI_warning', 0, {'buckleStatus': 1}),
('DI_state', 0, {'DI_cruiseState': stock_state}),
)
frames = [packer.make_can_msg(name, bus, values) for name, bus, values in messages]
for address, data, bus in frames:
assert native.safety_rx_hook(libsafety_py.make_CANPacket(address, bus, data))
native.safety_tick()
cs = ci.update([(now, frames)]).as_reader()
if tick > 1:
assert cs.canValid and not cs.canTimeout
owner.update(cs, now_ns=now)
allowed, pause, long_pause = owner.output(cs)
intention = IntentState('screen-card', tick + 1, now, now, now + 30_000_000, allowed, pause, long_pause, True, allowed)
permission = native.aol_get_permission_mask()
request = native.aol_get_request_mask()
safety = SafetyState(1, True, now, now + 200_000_000, 10, cp.safetyConfigs[0].safetyParam,
bool(permission & 1), bool(permission & 2), bool(request & 1), bool(request & 2),
'test-panda', 'screen-test', now,
(PandaSlot(0, 'test-panda', 10, cp.safetyConfigs[0].safetyParam, 32, bool(native.get_controls_allowed())),))
sd.aol_car_state_log_ns = now
sd.events = Events()
sd.events.add(log.OnroadEvent.EventName.pcmDisable)
if not cs.cruiseState.available:
sd.events.add(log.OnroadEvent.EventName.wrongCarMode)
decision = SelfdriveD._decide_aol_axes(cast(SelfdriveD, sd), cs, intention, safety, now_ns=now)
sd.aol_axis_decision = decision
native.aol_set_host_request(int(decision.desired_lateral))
assert not decision.longitudinal_active
if brake_disengage and tick == 140:
assert decision.desired_lateral and not decision.lateral_active
elif 22 <= tick < 240:
assert decision.lateral_active is not (brake_disengage and 100 <= tick < 140)
elif tick >= 240:
assert not decision.lateral_active
finally:
native.init_tests()
native.set_alternative_experience(0)
native.set_safety_hooks(0, 0)
@@ -80,8 +80,8 @@ def test_actual_startup_preferences_preserve_off_and_freeze_brake(tmp_path):
cp = screen_params()
saved = VehicleStartupPreferences.read(params, enabled=True)
saved.prepare(cp)
assert cp.safetyConfigs[0].safetyParam == 0
assert policy_for(cp).settings_supported and not policy_for(cp).runtime_supported
assert cp.safetyConfigs[0].safetyParam == 2048
assert policy_for(cp).settings_supported and policy_for(cp).runtime_supported
params.put_bool('TeslaAOLScreenTap', True, block=True)
params.put_bool('TeslaAOLDisengageOnBrake', True, block=True)
saved = VehicleStartupPreferences.read(params, enabled=True)
@@ -101,7 +101,7 @@ DESCRIPTIONS = {
'TruckTuning': 'Softens small acceleration requests, reduces grade correction and smooths light braking on supported GM trucks.',
'EVTuning': 'Selects EV acceleration curves for inherited acceleration presets.',
'TeslaAOLScreenTap': 'Lets a three-finger tap on a supported Tesla screen toggle Always On Lateral.',
'TeslaAOLDisengageOnBrake': 'Disarms screen-tap Always On Lateral when you press the brake.',
'TeslaAOLDisengageOnBrake': 'Disarms Tesla Always On Lateral when you press the brake, with either harness.',
'RemoteStartBootsComma': 'Wakes comma during GM remote start.',
'HKGRemoteStartBootsComma': 'Wakes comma during Hyundai, Kia or Genesis remote climate operation.',
'IgnoreIgnitionLine': 'Uses GM CAN ignition instead of the harness ignition signal.',
@@ -194,7 +194,7 @@ INITIALIZATION = {
'permission. An already admitted mode can be disabled live.'),
'VoltSNG': 'Applies when the vehicle controller next starts: its fresh resume-plan input is created for the selected stop-and-go mode.',
'TeslaAOLScreenTap': 'Requires the next vehicle startup to configure the screen-button CAN source and matching safety permission.',
'TeslaAOLDisengageOnBrake': 'Requires the next vehicle startup to configure the screen-button brake/disarm safety permission.',
'TeslaAOLDisengageOnBrake': 'Requires the next vehicle startup to configure the Tesla brake/disarm safety permission.',
'RemoteStartBootsComma': 'Requires a device restart to load the matching Panda ignition firmware.',
'HKGRemoteStartBootsComma': 'Requires a device restart to load the matching Panda ignition firmware.',
'IgnoreIgnitionLine': 'Requires a device restart to load the matching Panda ignition firmware.',
@@ -66,7 +66,9 @@ class TestTeslaScreenSettings(unittest.TestCase):
with self.subTest(options=options):
cp = vehicle(**options)
self.context = AuthorityContext(True, cp, cp.to_bytes())
self.assertFalse(any('AOL' in row['label'] for row in self.page()['rows']))
labels = {row['label'] for row in self.page()['rows']}
self.assertNotIn('Three-Finger AOL Tap', labels)
self.assertEqual('Disengage AOL on Brake' in labels, options != {'marker': False})
def test_stale_vehicle_or_onroad_change_rejects_saved_intent(self):
intent = self.intent()
@@ -10,7 +10,7 @@ ROWS = (
'Touch the Tesla screen with three fingers to toggle Always On Lateral. Requires Always On Lateral and the detected Vehicle CAN add-on cable. ' +
'Does not engage or cancel cruise control. Applies after the next startup.'),
('TeslaAOLDisengageOnBrake', 'Disengage AOL on Brake',
'With screen-tap steering enabled, pressing the brake disarms Always On Lateral. ' +
'Pressing the brake disarms Always On Lateral. ' +
'Turn off to keep steering armed during braking. Applies after the next startup.'),
)
@@ -23,9 +23,9 @@ class TeslaScreenFeature:
self.vehicle_fingerprint = owner.vehicle_fingerprint
def capability(self):
from opendbc.car.tesla.screen_button import screen_tap_supported
from opendbc.car.tesla.screen_button import modern_aol_supported
cp = self.vehicle_params()
if not screen_tap_supported(cp):
if not modern_aol_supported(cp):
return None
return (str(cp.carFingerprint), str(cp.brand), int(cp.flags), bool(cp.openpilotLongitudinalControl),
bool(cp.pcmCruise), int(cp.alternativeExperience),
@@ -36,7 +36,10 @@ class TeslaScreenFeature:
if capability is None:
return ()
rows = []
from opendbc.car.tesla.screen_button import screen_tap_supported
for key, label, reason in ROWS:
if key == 'TeslaAOLScreenTap' and not screen_tap_supported(self.vehicle_params()):
continue
raw, readable = read_saved(self.params, key, 8)
valid = readable and raw in (None, b'0', b'1')
rows.append(FeatureRow(key, label, ('On' if raw == b'1' else 'Off') if valid else 'Invalid saved choice',
@@ -54,7 +57,8 @@ class TeslaScreenFeature:
def authorized():
return (self.authority('parked_preferences') and bool(request.vehicle_fingerprint) and
self.vehicle_fingerprint() == request.vehicle_fingerprint and request.capability is not None and
self.capability() == request.capability)
self.capability() == request.capability and
(request.key != 'TeslaAOLScreenTap' or any(row.key == request.key for row in self.rows(True))))
result = commit_exact(self.params, key=request.key, max_bytes=8, expected=request.expected,
raw=b'1' if request.value == 'On' else b'0', authorized=authorized, temp_prefix='.tesla-screen-')
+1 -1
View File
@@ -47,5 +47,5 @@ def confirmation_question(request):
if request.key == "TeslaAOLScreenTap":
return f"{verb} three-finger screen taps for Always On Lateral after the next startup? Cruise control stays independent."
if request.key == "TeslaAOLDisengageOnBrake":
return f"{verb} disarming Always On Lateral with the brake after the next startup? This applies to screen-tap steering."
return f"{verb} disarming Always On Lateral with the brake after the next startup? This applies with either Tesla harness."
raise ValueError("Unsupported vehicle preference")
+9 -8
View File
@@ -38,6 +38,7 @@ class VehicleStartupPreferences:
gm_auto_hold: bool = False
volt_one_pedal: bool = False
tesla_cooperative: bool = field(default=False, kw_only=True)
tesla_aol: bool = field(default=False, kw_only=True)
tesla_screen: bool = False
tesla_screen_brake: bool = False
gm_camera_pedal: bool = True
@@ -99,9 +100,9 @@ class VehicleStartupPreferences:
assist = assist_readable and assist_raw in (None, b"1")
except (OSError, TypeError, ValueError):
assist = False
screen = bool(enabled and readable and safe in (None, b"0") and
read_saved(params, 'AlwaysOnLateral', 8) == (b'1', True) and
read_saved(params, 'TeslaAOLScreenTap', 8) == (b'1', True))
tesla_aol = bool(enabled and readable and safe in (None, b"0") and
read_saved(params, 'AlwaysOnLateral', 8) == (b'1', True))
screen = tesla_aol and read_saved(params, 'TeslaAOLScreenTap', 8) == (b'1', True)
cooperative = bool(enabled and readable and safe in (None, b"0") and
read_saved(params, "TeslaCoopSteering", 8) == (b"1", True))
screen_brake = read_saved(params, 'TeslaAOLDisengageOnBrake', 8) == (b'1', True)
@@ -114,7 +115,7 @@ class VehicleStartupPreferences:
subaru_sng=bool(enabled and readable and safe in (None, b"0") and read_saved(params, "SubaruSNG", 8) == (b"1", True)),
subaru_software_cruise=bool(enabled and readable and safe in (None, b"0") and
read_saved(params, "SubaruRedneckCruise", 8) == (b"1", True)),
ford_bluepilot=tuple(ford_bluepilot(params, enabled=enabled).items()), tesla_screen=screen,
ford_bluepilot=tuple(ford_bluepilot(params, enabled=enabled).items()), tesla_aol=tesla_aol, tesla_screen=screen,
tesla_screen_brake=screen_brake, tesla_cooperative=cooperative, toyota_auto_hold=toyota,
toyota_sng=bool(enabled and readable and safe in (None, b"0") and
read_saved(params, "SNGHack", 8) == (b"1", True)), jeep_brake_hold=jeep_hold,
@@ -192,8 +193,8 @@ class VehicleStartupPreferences:
from opendbc.car.gm.values import apply_gm_auto_hold, apply_volt_one_pedal
from openpilot.starpilot.car.tesla.preap_preferences import prepare_stock
prepare_stock(cp, self.tesla_preap_stock, self.tesla_preap_radar, self.tesla_preap_pedal)
from opendbc.car.tesla.screen_button import apply_screen_button
apply_screen_button(cp, self.tesla_screen, self.tesla_screen_brake)
from opendbc.car.tesla.screen_button import apply_modern_aol
apply_modern_aol(cp, self.tesla_aol, self.tesla_screen, self.tesla_screen_brake)
from openpilot.starpilot.car.tesla.coop_preferences import prepare
prepare(cp, self.tesla_cooperative)
self._prepare_honda_radar(cp)
@@ -237,8 +238,8 @@ class VehicleStartupPreferences:
admitted_hold = is_gm_auto_hold(cp)
from openpilot.starpilot.car.tesla.preap_preferences import prepare_stock
prepare_stock(cp, self.tesla_preap_stock, self.tesla_preap_radar, self.tesla_preap_pedal)
from opendbc.car.tesla.screen_button import apply_screen_button
apply_screen_button(cp, self.tesla_screen, self.tesla_screen_brake)
from opendbc.car.tesla.screen_button import apply_modern_aol
apply_modern_aol(cp, self.tesla_aol, self.tesla_screen, self.tesla_screen_brake)
from openpilot.starpilot.car.tesla.coop_preferences import prepare
prepare(cp, self.tesla_cooperative)
self._prepare_honda_radar(cp)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1,4 +1,4 @@
#pragma once
extern const uint8_t gitversion[29];
const uint8_t gitversion[29] = "DEV-b6d2afbc-Pf38f504f-DEBUG";
const uint8_t gitversion[29] = "DEV-dd532d60-Pf38f504f-DEBUG";
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
DEV-b6d2afbc-Pf38f504f-DEBUG
DEV-dd532d60-Pf38f504f-DEBUG
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
{"protected_inventory_sha256": "5708a3cd319cd5c96ad0fa1679a47712342bb2b70ff983b410bc308aad184d47", "schema_version": 1}
{"protected_inventory_sha256": "689c16ce9b83e3e452ebc990e5feb7451c0c68de933c5e0e053439ac40f83292", "schema_version": 1}