Keep Ford standby display through the final steering packet

This commit is contained in:
firestar5683
2026-10-29 14:34:35 -05:00
parent 42057a3f8f
commit 06a74465c0
3 changed files with 74 additions and 2 deletions
+7 -1
View File
@@ -30,7 +30,7 @@ static uint8_t ford_aol_owned = 0U;
static uint32_t ford_aol_accepted_ts = 0U;
// An accepted inactive actuator plus a truthful OFF/standby display can own
// cluster continuity without owning steering. Keep the original 200ms bound.
// cluster continuity without owning steering. Keep the existing command lease.
#define FORD_AOL_NEUTRAL_STEERING_SEEN 0x80U
static bool ford_aol_neutral_request_seen = false;
static uint32_t ford_aol_neutral_steering_ts = 0U;
@@ -123,6 +123,12 @@ static void ford_aol_host_request(uint8_t mask) {
ford_aol_neutral_request_seen = true;
ford_aol_request_seen |= mask != 0U;
if (ford_aol_retained_display_profile() && ((mask & 1U) == 0U)) {
// Bridge Off UI before the next inactive actuator without renewing its accepted-command deadline.
if ((mask == 0U) && ford_aol_neutral_sources_current() && ((ford_aol_owned & FORD_AOL_STEERING_OWNED) != 0U) &&
(safety_get_ts_elapsed(microsecond_timer_get(), ford_aol_accepted_ts) <= AOL_HOST_REQUEST_TIMEOUT_US)) {
ford_aol_neutral_steering_ts = ford_aol_accepted_ts;
ford_aol_neutral_display_mask |= FORD_AOL_NEUTRAL_STEERING_SEEN;
}
ford_aol_owned &= FORD_AOL_STEERING_OWNED;
}
}
@@ -150,3 +150,69 @@ def test_neutral_continuity_across_real_microsecond_timer_wrap(owner):
assert owner.safety.safety_fwd_hook(2, 0x18A) == -1
assert owner.safety.safety_fwd_hook(2, 0x3D8) == -1
assert owner.safety.aol_get_permission_mask() == 0
def active_then_off(owner, full=False):
owner.arm()
bus = CanBus(fingerprint=gen_empty_fingerprint())
address, data, src = mache_can.create_lka_msg(owner.packer, bus)
assert owner.safety.safety_tx_hook(libsafety_py.make_CANPacket(address, src, data))
address, data, src = mache_can.create_lat_ctl2_msg(owner.packer, bus, 1, 0, 1, 0., 0., 0)
assert owner.safety.safety_tx_hook(libsafety_py.make_CANPacket(address, src, data))
assert owner.safety.aol_get_permission_mask() == 1
if full:
owner.pump(10, main=5, mask=3, heartbeat=True)
assert owner.safety.aol_get_permission_mask() == 3
owner.safety.aol_set_host_request(0)
owner.safety.set_aol_test_heartbeat(False)
assert owner.safety.aol_get_permission_mask() == 0
@pytest.mark.parametrize('full', [False, True])
def test_off_display_precedes_next_inactive_actuator_without_stock_warning_gap(owner, full):
active_then_off(owner, full=full)
assert owner.safety.safety_fwd_hook(2, 0x18A) == 0
assert ui(owner, 0x18A)
assert owner.safety.safety_fwd_hook(2, 0x18A) == -1
assert owner.safety.safety_fwd_hook(2, 0x3D8) == 0
assert ui(owner, 0x3D8)
assert owner.safety.safety_fwd_hook(2, 0x3D8) == -1
assert owner.safety.safety_fwd_hook(2, 0x3D6) == 0
assert owner.safety.aol_get_permission_mask() == 0
owner.pump(4, main=3, mask=0, heartbeat=False)
inactive(owner)
assert owner.safety.safety_fwd_hook(2, 0x18A) == -1
def test_off_handover_ui_and_host_repeats_do_not_renew_the_original_command_lease(owner):
active_then_off(owner)
assert ui(owner, 0x18A)
for _ in range(10):
owner.pump(3, main=3, mask=0, heartbeat=False)
assert ui(owner, 0x18A)
owner.pump(1, main=3, mask=0, heartbeat=False)
assert not ui(owner, 0x18A)
assert owner.safety.safety_fwd_hook(2, 0x18A) == 0
assert owner.safety.aol_get_permission_mask() == 0
@pytest.mark.parametrize('loss', ['eps', 'gear', 'lka', 'acc-fault', 'rx'])
def test_off_handover_returns_stock_on_real_faults(owner, loss):
active_then_off(owner)
assert ui(owner, 0x18A)
if loss == 'eps':
owner.rx('EPAS_INFO', {'EPAS_Failure': 1})
elif loss == 'gear':
owner.pump(10, main=3, mask=0, gear=1, heartbeat=False)
elif loss == 'lka':
owner.rx('Lane_Assist_Data3_FD1', {'LatCtlSte_D_Stat': 0})
elif loss == 'acc-fault':
owner.rx('EngBrakeData', {'CcStat_D_Actl': 1, 'BpedDrvAppl_D_Actl': 1})
else:
address, data, bus = owner.packer.make_can_msg('BrakeSysFeatures', 0, {'Veh_V_ActlBrk': 36., 'VehVActlBrk_D_Qf': 3})
bad = bytearray(data)
bad[0] ^= 1
assert not owner.safety.safety_rx_hook(libsafety_py.make_CANPacket(address, bus, bad))
assert not ui(owner, 0x18A)
assert owner.safety.safety_fwd_hook(2, 0x18A) == 0
assert owner.safety.aol_get_permission_mask() == 0
+1 -1
View File
@@ -1 +1 @@
{"protected_inventory_sha256": "845201e8021f9955dae8eb23a1c053d4a13e609c70b9d29fac4156450fe8f365", "schema_version": 1}
{"protected_inventory_sha256": "6accf43a213ae9a890b1ff76172826831210df455860137ba905e4a7f348f734", "schema_version": 1}