Files
StarPilot/openpilot/starpilot/aol/transport_pause.py
T
Dom efe875ffd6 Retire completed GM cold-MAIN recovery before a new lateral request
Clear prior recovery wait state only after the existing healthy unlatched baseline is accepted. Preserve native acknowledgment, fault, identity and expiry gates; cover actual Card and native permission transitions.
2026-10-27 22:49:52 -05:00

1844 lines
120 KiB
Python

"""Reason-qualified intent retention; this module never grants an axis."""
from openpilot.cereal import log
from openpilot.starpilot.aol.panda_faults import blocking_fault_mask, blocking_fault_list
from openpilot.starpilot.aol.runtime import AXIS_MAX_AGE_NS, SAFETY_MAX_AGE_NS, current_native, native_inventory_matches_cp
from openpilot.starpilot.aol.wire import SafetyState, decode_intent
def cp_identity(cp):
return (str(cp.brand), str(cp.carFingerprint), int(cp.flags), int(cp.alternativeExperience),
bool(cp.passive), bool(cp.dashcamOnly), bool(cp.notCar),
bool(cp.openpilotLongitudinalControl), bool(cp.pcmCruise),
tuple((int(c.safetyModel.raw), int(c.safetyParam)) for c in cp.safetyConfigs))
def _configured_transport_native(sm, cp, session, now_ns, native=None, *, require_longitudinal=True, allow_restricted_lateral=False):
"""Validate the exact live native configuration and every Panda."""
try:
validated_here = native is None
native = native or current_native(sm, cp, now_ns=now_ns, axis_session_id=session)
if (not session or native is None or str(native.axisSessionId) != session or
native.requestedLateral and not native.lateralAllowed and not allow_restricted_lateral or
require_longitudinal and native.requestedLongitudinal and not native.longitudinalAllowed):
return None
coherent = bool(native.pandaInventory)
if coherent and (int(sm.logMonoTime['aolSafetyWire']) != native.observedMonoTime or
not 0 < native.observedMonoTime <= now_ns <= native.validUntilMonoTime or
now_ns - native.observedMonoTime > SAFETY_MAX_AGE_NS or
native.validUntilMonoTime - native.observedMonoTime > SAFETY_MAX_AGE_NS):
return None
# current_native checked this inventory; supplied native values still need structural validation.
if coherent and (not validated_here and not native_inventory_matches_cp(native, cp) or
any(p.safetyRxChecksInvalid or p.heartbeatLost or blocking_fault_mask(p.faults, cp) or
(require_longitudinal and native.requestedLongitudinal and str(config.safetyModel) not in ('silent', 'noOutput') and
not p.controlsAllowed)
for p, config in zip(native.pandaInventory, cp.safetyConfigs, strict=True))):
return None
# v2 carries exact producer-read health under its monotonic 200ms lease.
# The independently conflated BOOTTIME PandaStates is a latest veto only.
stamp = int(sm.logMonoTime['pandaStates'])
if not (sm.seen['pandaStates'] and sm.valid['pandaStates'] and sm.alive['pandaStates'] and
stamp > 0 and (coherent or stamp <= now_ns and now_ns - stamp <= SAFETY_MAX_AGE_NS)):
return None
pandas = sm['pandaStates']
if not cp.safetyConfigs or len(pandas) != len(cp.safetyConfigs):
return None
return native if all(int(p.safetyModel.raw) == int(c.safetyModel.raw) and p.safetyParam == c.safetyParam and
p.alternativeExperience == cp.alternativeExperience and not p.safetyRxChecksInvalid and
not p.heartbeatLost and not blocking_fault_list(p.faults, cp) and
(not require_longitudinal or not native.requestedLongitudinal or str(c.safetyModel) in ('silent', 'noOutput') or p.controlsAllowed)
for p, c in zip(pandas, cp.safetyConfigs, strict=True)) else None
except (AttributeError, KeyError, IndexError, TypeError, ValueError):
return None
def _healthy_transport_native(sm, cp, cs, session, now_ns, native=None, *, require_longitudinal=True):
"""Require both current vehicle health and the exact live native configuration."""
try:
if not cs.canValid or cs.canTimeout or cs.steerFaultTemporary or cs.steerFaultPermanent:
return None
return _configured_transport_native(sm, cp, session, now_ns, native,
require_longitudinal=require_longitudinal)
except (AttributeError, KeyError, IndexError, TypeError, ValueError):
return None
def _newer_combined_intent_native(sm, cp, cs, axis, now_ns):
# A prior LAT proof may await LONG ACK despite newer FULL inventory. Retain intent only;
# output still requires current native proof and original axis deadlines.
if (not axis.nativeAcknowledged or not axis.desiredLateral or not axis.lateralActive or
not axis.desiredLongitudinal or not cs.cruiseState.enabled or
cs.brakePressed or cs.gasPressed or cs.accFaulted):
return None
native = _healthy_transport_native(sm, cp, cs, str(axis.sessionId), now_ns, require_longitudinal=False)
if (native is None or not native.pandaInventory or not native.requestedLateral or not native.lateralAllowed or
not native.requestedLongitudinal or not native.longitudinalAllowed or
not 0 < int(sm.logMonoTime['pandaStates']) < native.sourcePandaStatesMonoTime or
any(not slot.controlsAllowed for slot, config in zip(native.pandaInventory, cp.safetyConfigs, strict=True)
if str(config.safetyModel) not in ('silent', 'noOutput'))):
return None
return native
def independent_lateral_health(sm, cp, cs, session, now_ns):
"""Structural health for retaining LAT intent; never grant either output axis."""
native = _healthy_transport_native(sm, cp, cs, session, now_ns, require_longitudinal=False)
return native if native is not None and native.requestedLateral and native.lateralAllowed else None
def healthy_transport(sm, cp, cs, session, now_ns, native=None):
"""Require the live, exact native configuration, including every Panda."""
return _healthy_transport_native(sm, cp, cs, session, now_ns, native) is not None
AVAILABILITY_EVENTS = (log.OnroadEvent.EventName.commIssue, log.OnroadEvent.EventName.commIssueAvgFreq)
def availability_only(events):
faults = [event for event in events if event.immediateDisable or event.softDisable]
return bool(faults and all(event.name in AVAILABILITY_EVENTS and event.softDisable and
not event.immediateDisable for event in faults))
HOST_SOURCE_AVAILABILITY_EVENTS = (*AVAILABILITY_EVENTS, log.OnroadEvent.EventName.selfdrivedLagging)
def host_source_availability_only(events):
"""Closed host SOFT set for qualified inactive source-zero intent only."""
faults = [event for event in events if event.immediateDisable or event.softDisable]
return bool(faults and not any(event.userDisable for event in events) and
all(event.name in HOST_SOURCE_AVAILABILITY_EVENTS and event.softDisable and
not event.immediateDisable for event in faults))
def stock_lateral_user_event(cp):
"""Current ordinary-owner USER event for an established stock LAT role."""
if not cp.pcmCruise:
return None
if cp.brand == 'honda':
from opendbc.car.honda.stock_aol import qualified
return log.OnroadEvent.EventName.cruiseDisabled if qualified(cp, marked_only=True) else None
return log.OnroadEvent.EventName.pcmDisable
def stock_lateral_off(cp, cs, native, *, allow_independent_cancel=False, allow_independent_brake=False,
allow_independent_gas=False):
from openpilot.starpilot.nostalgia import physical_cancel
from opendbc.car.hyundai.canfd_angle_aol import qualified as angle_qualified
from opendbc.car.hyundai.canfd_stock_aol import qualified as stock_canfd_qualified
from openpilot.starpilot.car.toyota.aol import qualified as toyota_qualified
independent_angle = angle_qualified(cp, marked_only=True)
independent_brake = independent_angle or (allow_independent_brake and (
toyota_qualified(cp, marked_only=True) and not cs.cruiseState.enabled or
cp.brand == 'hyundai' and len(cp.safetyConfigs) == 1 and stock_canfd_qualified(cp, marked_only=True)))
return bool(cp.pcmCruise and cs.cruiseState.available and
(not cs.cruiseState.enabled or independent_brake and allow_independent_brake and cs.brakePressed) and
cs.canValid and not cs.canTimeout and not cs.steerFaultPermanent and not cs.steerFaultTemporary and
not cs.accFaulted and not cs.doorOpen and not cs.seatbeltUnlatched and
(not cs.brakePressed or independent_brake and allow_independent_brake) and
not cs.regenBraking and (not cs.gasPressed or independent_angle or
allow_independent_gas and toyota_qualified(cp, marked_only=True)) and
(not physical_cancel(cs, cp) or independent_angle and allow_independent_cancel) and
native is not None and native.requestedLateral and native.lateralAllowed and not native.requestedLongitudinal)
class AvailabilityPause:
"""Retain an accepted armed producer; this proof never enables output."""
def __init__(self, cp, session):
self.cp, self.session = cp_identity(cp), session
self.producer = ''
self.epoch = None
self.inventory = None
self.native_ns = 0
self.baseline_ns = 0
self.active = False
def observe(self, *, cp, session, sm, cs, native, now_ns, companion, intent,
events, model_ready, source_current, prior_lateral_active, hard_fault, healthy_native, source_expired=False):
try:
healthy = healthy_native
eligible = bool(cp_identity(cp) == self.cp and
session == self.session and not hard_fault and model_ready and (source_current or source_expired) and companion is not None and
companion.last_drain_ok and intent is not None and intent.allowedLatch and intent.lateralArmed and
healthy is not None and healthy.requestedLateral and healthy.lateralAllowed and healthy.pandaInventory)
if not eligible:
self.active = False
self.baseline_ns = 0
return False
if source_expired:
latest = companion.latest
raw = latest[2] if latest is not None and latest[1] else None
verified = companion.verified_sm_projection
sm_intent = decode_intent(sm['aolIntentWire'])
projection = bool(verified is not None and int(sm.logMonoTime['aolIntentWire']) == verified[0] and
verified[2] == companion.integrity_epoch and verified[3] == companion.session and
sm_intent == verified[1] and 0 < verified[0] <= now_ns <= verified[0] + SAFETY_MAX_AGE_NS and
sm_intent.settingsQualified and sm_intent.allowedLatch and sm_intent.lateralArmed and
sm_intent.producerSessionId == intent.producerSessionId)
if (raw is None or not raw.settingsQualified or not raw.allowedLatch or not raw.lateralArmed or
raw.producerSessionId != intent.producerSessionId or
not 0 < intent.carStateLogMonoTime <= now_ns or
now_ns - intent.carStateLogMonoTime > SAFETY_MAX_AGE_NS or
not 0 < raw.carStateLogMonoTime <= now_ns or raw.observedMonoTime > now_ns or
now_ns - raw.carStateLogMonoTime > SAFETY_MAX_AGE_NS or
(int(sm.logMonoTime['aolIntentWire']) != raw.carStateLogMonoTime and not projection) or
not sm.seen['aolIntentWire'] or not sm.valid['aolIntentWire'] or not sm.alive['aolIntentWire']):
self.active = False
return False
inventory = (healthy.pandaSerial, tuple(p.hardwareSerial for p in healthy.pandaInventory))
faults = [event for event in events if event.immediateDisable or event.softDisable]
if not faults:
recovery_handoff = bool(self.active and source_current and not source_expired and self.baseline_ns > 0 and
self.producer == intent.producerSessionId and self.epoch == companion.integrity_epoch and
self.inventory == inventory and healthy.observedMonoTime >= self.native_ns)
self.active = False
if prior_lateral_active or recovery_handoff:
self.producer, self.epoch = intent.producerSessionId, companion.integrity_epoch
self.inventory, self.native_ns, self.baseline_ns = inventory, healthy.observedMonoTime, now_ns
return False
matched = bool(availability_only(events) and self.producer == intent.producerSessionId and
self.epoch == companion.integrity_epoch and self.inventory == inventory and
healthy.observedMonoTime >= self.native_ns and self.baseline_ns > 0 and
(self.active or 0 <= now_ns - self.baseline_ns <=
(SAFETY_MAX_AGE_NS if source_expired else AXIS_MAX_AGE_NS)))
self.active = matched
if matched:
self.native_ns = healthy.observedMonoTime
else:
self.baseline_ns = 0
return matched
except (AttributeError, KeyError, IndexError, TypeError, ValueError):
self.active = False
self.baseline_ns = 0
return False
class TransportPause:
def __init__(self, cp, session):
self.cp = cp_identity(cp)
self.session = session
self.active = False
self.producer = ''
self.epoch = None
def observe(self, *, cp, session, sm, cs, native, now_ns, companion, previous_intent,
intent, expired_healthy_source, previously_active, hard_fault, model_ready, user_disable):
"""Return (temporary inhibit, hard upgrade); require a prior accepted pair."""
# Overwritten on every observation; consumed only by the adjacent producer.
self.observed_native = None
context_current = bool(cp_identity(cp) == self.cp and session == self.session and model_ready and companion is not None)
if context_current:
self.observed_native = _healthy_transport_native(sm, cp, cs, session, now_ns, native)
eligible = bool(context_current and not hard_fault and self.observed_native is not None)
latest = companion.latest if companion is not None else None
raw = decode_intent(sm['aolIntentWire']) if sm.seen.get('aolIntentWire', False) else None
previous = previous_intent
producer = self.producer if self.active else str(previous.producerSessionId) if previous is not None else ''
eligible = bool(eligible and latest is not None and latest[1] and raw is not None and
sm.valid['aolIntentWire'] and sm.alive['aolIntentWire'] and
raw.settingsQualified and raw.producerSessionId == producer and
latest[2].producerSessionId == producer and
int(sm.logMonoTime['aolIntentWire']) == raw.carStateLogMonoTime and
0 < raw.carStateLogMonoTime <= now_ns and raw.observedMonoTime <= now_ns and
(self.epoch is None or self.epoch == companion.integrity_epoch))
if self.active:
if not eligible:
self.active = False
return False, True
if user_disable or intent is not None and not intent.allowedLatch:
self.active = False
self.epoch = companion.integrity_epoch
return False, False
return True, False
if (eligible and expired_healthy_source and previously_active and previous is not None and
previous.allowedLatch and previous.lateralArmed and raw.allowedLatch and raw.lateralArmed and
not user_disable):
self.active = True
self.producer = producer
self.epoch = companion.integrity_epoch
return True, False
if intent is not None and companion is not None:
self.epoch = companion.integrity_epoch
return False, False
class TransportPauseFeedback:
"""Card accepts pause provenance only after a healthy same-session baseline."""
def __init__(self, cp):
self.cp = cp_identity(cp)
self.session = ''
self.sequence = 0
self.signature = None
self.paused = False
self.qualified = False
self.pending_event = 0
self.awaiting = False
self.failed = False
self.lateral_baseline_ns = 0
self.ever_lateral_active = False
self.lag_withdrawal_ns = 0
self.cold_main_wait_ns = 0
self.cold_main_sparse_waiting = False
self.ccnc_main_off_source_ns = 0
self.cold_park_waiting = False
self.lateral_only_baseline = False
self.temporary_eps_gas_override = False
self.lateral_source_ns = 0
self.lateral_inventory = None
self.lateral_native_ns = 0
self.longitudinal_cancel_ns = 0
self.last_cancel_source_ns = 0
self.honda_brake_ns = 0
self.gm_withdrawal_ns = 0
self.retention_qualified = False
self.retention_pending = False
self.retention_event_ns = 0
self.retention_started_ns = 0
self.retention_verified = False
self.availability_producer = ''
self.availability_epoch = None
self.source_retention_started_ns = 0
self.ordinary_warning_retained = False
self.ordinary_warning_qualified = False
self.ordinary_warning_pending_baseline = None
self.healthy_feedback_ns = 0
self.healthy_native_ns = 0
self.healthy_inventory = None
def _first_ford_gas_lateral_grant(self, sm, cp, cs, axis, now_ns, *, latched, producer):
"""Bind the first real LAT-only grant while gas independently vetoes LONG."""
from opendbc.car import structs
from openpilot.starpilot.car.ford.aol import early_native_long_withdrawal_supported
if (not early_native_long_withdrawal_supported(cp) or not latched or self.failed or self.paused or
self.pending_event or self.retention_started_ns or self.source_retention_started_ns or
self.lateral_baseline_ns or not self.session or str(axis.sessionId) != self.session or
not producer or str(axis.intentProducerSessionId) != producer or int(axis.intentIntegrityEpoch) < 0 or
self.signature is None or self.signature[14:16] != (producer, int(axis.intentIntegrityEpoch)) or
str(axis.faultReason) != 'none' or str(axis.mode) != 'lateralOnly' or not axis.nativeAcknowledged or
not axis.desiredLateral or not axis.lateralActive or not axis.desiredLongitudinal or axis.longitudinalActive or
not 0 < axis.sourceCarStateMonoTime <= axis.observedMonoTime <= now_ns <= axis.validUntilMonoTime or
now_ns - axis.sourceCarStateMonoTime > AXIS_MAX_AGE_NS or
not cs.gasPressed or cs.brakePressed or cs.regenBraking or not cs.cruiseState.available or
not cs.cruiseState.enabled or not cs.canValid or cs.canTimeout or cs.steerFaultTemporary or
cs.steerFaultPermanent or cs.accFaulted or cs.vehicleSensorsInvalid or cs.steeringDisengage or
cs.doorOpen or cs.seatbeltUnlatched or cs.gearShifter not in
(structs.CarState.GearShifter.drive, structs.CarState.GearShifter.sport, structs.CarState.GearShifter.low) or
not sm.seen['onroadEvents'] or not sm.valid['onroadEvents'] or not sm.alive['onroadEvents'] or
not 0 < int(sm.logMonoTime['onroadEvents']) <= now_ns or
now_ns - int(sm.logMonoTime['onroadEvents']) > 1_500_000_000 or
any(event.immediateDisable or event.softDisable or event.userDisable for event in sm['onroadEvents'])):
return None
native = independent_lateral_health(sm, cp, cs, self.session, now_ns)
if (native is None or not native.pandaInventory or not native.requestedLongitudinal or native.longitudinalAllowed or
self.healthy_inventory != (native.pandaSerial, tuple(slot.hardwareSerial for slot in native.pandaInventory))):
return None
return native
def _native_long_withdrawal_lateral_current(self, sm, cp, cs, axis, now_ns, *, latched, producer):
"""Retain existing LAT intent from a fresh independently granted LAT proof.
Requested but denied LONG is never an active combined-axis baseline. This
method neither grants outputs nor exempts any native or control fault.
"""
from openpilot.starpilot.nostalgia import physical_cancel
from openpilot.starpilot.car.gm.aol import native_accepts_cp
from openpilot.starpilot.car.hyundai.aol import early_native_long_withdrawal_supported
gm = cp.brand == 'gm' and native_accepts_cp(cp, int(cp.safetyConfigs[0].safetyModel.raw), int(cp.safetyConfigs[0].safetyParam))
from openpilot.starpilot.car.hyundai.aol import qualified_ccnc_long_aol as ev9_qualified
from opendbc.car import structs
ev9 = cp.brand == 'hyundai' and ev9_qualified(cp, marked_only=True)
from openpilot.starpilot.car.ford.aol import early_native_long_withdrawal_supported as ford_early_long
from opendbc.car.ford.aol import qualified as ford_qualified
# Brake or cruise cancel can withdraw LONG before the next 10Hz request echo. This uses
# an actual independently granted LAT proof and retains intent only.
ford_withdrawal = bool(cp.brand == 'ford' and ford_qualified(cp, marked_only=True) and cp.openpilotLongitudinalControl and
(cs.brakePressed or not cs.cruiseState.enabled or physical_cancel(cs, cp)) and not cs.gasPressed and not cs.regenBraking and
cs.cruiseState.available and not cs.doorOpen and not cs.seatbeltUnlatched and
not cs.vehicleSensorsInvalid and cs.gearShifter == structs.CarState.GearShifter.drive)
early_long = gm or cp.brand == 'hyundai' and early_native_long_withdrawal_supported(cp) or ev9 or ford_early_long(cp) or ford_withdrawal
from openpilot.starpilot.car.gm.aol import f1_conventional_lateral_owner, gm_physical_pedal_withdrawal
gm_pedal = gm_physical_pedal_withdrawal(cp, cs) and not f1_conventional_lateral_owner(cp)
event_ns = int(sm.logMonoTime['onroadEvents'])
main_off_recovery = bool(0 < event_ns <= self.ccnc_main_off_source_ns <= now_ns and
now_ns - self.ccnc_main_off_source_ns <= AXIS_MAX_AGE_NS)
ev9_main_off = bool(ev9 and (not cs.cruiseState.available or main_off_recovery) and
not cs.brakePressed and not cs.gasPressed and not cs.doorOpen and not cs.seatbeltUnlatched and
cs.gearShifter in (structs.CarState.GearShifter.drive, structs.CarState.GearShifter.sport,
structs.CarState.GearShifter.low, structs.CarState.GearShifter.brake))
if (not latched or self.failed or self.paused or self.pending_event or self.retention_started_ns or
not self.session or str(axis.sessionId) != self.session or
not producer or producer != self.availability_producer or
str(getattr(axis, 'intentProducerSessionId', '')) != producer or
int(getattr(axis, 'intentIntegrityEpoch', 0)) != self.availability_epoch or
not self.lateral_inventory or not self.lateral_baseline_ns or
str(axis.faultReason) != 'none' or not early_long and str(axis.mode) != 'lateralOnly' or not axis.nativeAcknowledged or
not axis.desiredLateral or not axis.lateralActive or axis.longitudinalActive and not early_long or
not 0 < self.lateral_source_ns <= axis.sourceCarStateMonoTime <= axis.observedMonoTime <= now_ns or
now_ns - axis.sourceCarStateMonoTime > AXIS_MAX_AGE_NS or
not cs.canValid or cs.canTimeout or cs.steerFaultTemporary or cs.steerFaultPermanent or cs.accFaulted or
cs.steeringDisengage or physical_cancel(cs, cp) and not ford_withdrawal or
not sm.seen['onroadEvents'] or not sm.valid['onroadEvents'] or not sm.alive['onroadEvents'] or
not 0 < int(sm.logMonoTime['onroadEvents']) <= now_ns or
now_ns - int(sm.logMonoTime['onroadEvents']) > 1_500_000_000 or
any(event.immediateDisable or event.softDisable or
event.userDisable and not (ev9_main_off and event.name == log.OnroadEvent.EventName.wrongCarMode or
gm_pedal and event.name == log.OnroadEvent.EventName.pedalPressed or
ford_withdrawal and event.name in (log.OnroadEvent.EventName.pedalPressed, log.OnroadEvent.EventName.pcmDisable,
log.OnroadEvent.EventName.buttonCancel))
for event in sm['onroadEvents'])):
return None
native = independent_lateral_health(sm, cp, cs, self.session, now_ns)
if (native is None or not native.pandaInventory or not native.requestedLongitudinal or native.longitudinalAllowed or
native.observedMonoTime < self.lateral_native_ns or
(native.pandaSerial, tuple(slot.hardwareSerial for slot in native.pandaInventory)) != self.lateral_inventory):
return None
owners = [index for index, config in enumerate(cp.safetyConfigs)
if str(config.safetyModel) not in ('silent', 'noOutput')]
if not (len(owners) == 1 and (early_long or not native.pandaInventory[owners[0]].controlsAllowed and
not sm['pandaStates'][owners[0]].controlsAllowed)):
return None
return native
def _ordinary_warning_intent_current(self, sm, cp, cs, axis, stamp, now_ns, *, latched, producer):
"""Retain armed intent through a fresh SOFT withdrawal; grant no output."""
from openpilot.starpilot.aol.vehicle import policy_for
from openpilot.starpilot.nostalgia import physical_cancel
from opendbc.car import structs
pending_baseline = self.ordinary_warning_pending_baseline
pending = bool(pending_baseline is not None and self.pending_event)
if (not latched or self.failed or self.paused or self.pending_event and not pending or self.retention_started_ns or
not self.session or not self.lateral_baseline_ns or not self.lateral_inventory or
not (policy := policy_for(cp)).intent_supported or
policy.cruise_main_required and not cs.cruiseState.available or
str(axis.sessionId) != self.session or
not producer or producer != self.availability_producer or axis.intentProducerSessionId != producer or
axis.intentIntegrityEpoch != self.availability_epoch or
not cs.canValid or cs.canTimeout or cs.steerFaultPermanent or cs.accFaulted or cs.doorOpen or
cs.steeringDisengage or
cs.gearShifter not in (structs.CarState.GearShifter.drive, structs.CarState.GearShifter.sport,
structs.CarState.GearShifter.low, structs.CarState.GearShifter.brake) or
not 0 < self.lateral_source_ns <= axis.sourceCarStateMonoTime <= stamp <= now_ns or
now_ns - axis.sourceCarStateMonoTime > AXIS_MAX_AGE_NS or
str(axis.faultReason) not in ('none', 'availabilityPause') or
not sm.seen['onroadEvents'] or not sm.valid['onroadEvents'] or not sm.alive['onroadEvents']):
return False
event_ns = int(sm.logMonoTime['onroadEvents'])
events = sm['onroadEvents']
if (not 0 < event_ns <= now_ns or now_ns - event_ns > 1_500_000_000 or
any(event.immediateDisable for event in events)):
return False
warning = any(event.softDisable for event in events)
recovering = bool(getattr(self, 'ordinary_warning_retained', False) and not warning)
if pending and (axis.faultEventMonoTime != self.pending_event or
not 0 < self.pending_event <= now_ns or now_ns - self.pending_event > AXIS_MAX_AGE_NS):
return False
stock_user = stock_lateral_user_event(cp)
# Physical withdrawals still go through the family button/pedal owner.
# This helper cannot rearm a latch that that owner explicitly clears.
if any(event.userDisable and event.name != stock_user and not (
event.name == log.OnroadEvent.EventName.pedalPressed and (cs.brakePressed or cs.regenBraking) or
event.name == log.OnroadEvent.EventName.buttonCancel and (physical_cancel(cs, cp) or
cp.brand == 'gm' and 0 < self.gm_withdrawal_ns == event_ns <= now_ns and
now_ns - event_ns <= SAFETY_MAX_AGE_NS)) for event in events):
return False
prior = pending_baseline if pending else self.signature
# SOFT may precede its exact event. Hold intent only under the original fixed 30ms join;
# duplicate/newer withdrawals cannot move the pending occurrence.
axis_first = bool(str(axis.faultReason) == 'availabilityPause' and
not (axis.lateralActive or axis.longitudinalActive or axis.desiredLateral or
axis.desiredLongitudinal or axis.nativeAcknowledged) and
prior is not None and prior[5] == 'none' and prior[9] and prior[11] and prior[13] and
prior[14:16] == (producer, self.availability_epoch) and
0 < prior[8] <= now_ns and (pending or now_ns <= prior[4] and now_ns - prior[8] <= AXIS_MAX_AGE_NS) and
event_ns < axis.faultEventMonoTime <= stamp and now_ns - axis.faultEventMonoTime <= AXIS_MAX_AGE_NS)
if not warning and not recovering and not axis_first:
return False
active_join = bool(warning and prior is not None and str(axis.faultReason) == 'none' and
axis.lateralActive and axis.desiredLateral and axis.nativeAcknowledged and
prior[9] and prior[11] and prior[13] and prior[14:16] == (producer, self.availability_epoch) and
0 < prior[8] <= now_ns <= prior[4] and now_ns - prior[8] <= AXIS_MAX_AGE_NS and
0 < axis.faultEventMonoTime < event_ns and now_ns - event_ns <= AXIS_MAX_AGE_NS)
withdrawn = bool(not axis.lateralActive and not axis.longitudinalActive and
not axis.desiredLongitudinal and
(warning and str(axis.faultReason) == 'availabilityPause' and axis.faultEventMonoTime == event_ns <= stamp or
recovering and str(axis.faultReason) == 'none'))
if not active_join and not withdrawn and not axis_first:
return False
if pending and not axis_first and not (withdrawn and warning and event_ns == self.pending_event):
return False
native = _configured_transport_native(sm, cp, self.session, now_ns,
allow_restricted_lateral=withdrawn or axis_first or bool(cs.steerFaultTemporary),
require_longitudinal=not (withdrawn or axis_first))
if (native is None or not native.pandaInventory or
(native.pandaSerial, tuple(slot.hardwareSerial for slot in native.pandaInventory)) != self.lateral_inventory or
native.observedMonoTime < self.lateral_native_ns or
active_join and not (native.requestedLateral and native.lateralAllowed)):
return False
if axis_first:
if not pending:
self.pending_event = int(axis.faultEventMonoTime)
self.ordinary_warning_pending_baseline = prior
self.awaiting = True
return True
if pending:
self.pending_event = 0
self.ordinary_warning_pending_baseline = None
self.ordinary_warning_retained = True
return True
def _temporary_host_intent_current(self, sm, cp, cs, axis, stamp, now_ns, *, latched, producer):
"""A fresh inactive proof may retain intent, never native/output authority."""
from openpilot.starpilot.nostalgia import physical_cancel
if physical_cancel(cs, cp) or cs.steeringDisengage:
return False
belt_eps_recovery = bool(not cs.steerFaultTemporary and self.lateral_only_baseline and
getattr(self, 'temporary_eps_event_ns', 0) and axis.faultEventMonoTime == self.temporary_eps_event_ns and
not axis.desiredLongitudinal and not axis.longitudinalActive)
events = tuple(event for event in sm['onroadEvents'] if not (
belt_eps_recovery and cs.seatbeltUnlatched and event.name == log.OnroadEvent.EventName.seatbeltNotLatched and
event.softDisable and event.noEntry and not event.immediateDisable and not event.userDisable))
faults = [event for event in events if event.immediateDisable or event.softDisable]
names = (log.OnroadEvent.EventName.selfdrivedLagging, log.OnroadEvent.EventName.locationdTemporaryError)
location_fault = bool(any(event.name == log.OnroadEvent.EventName.locationdTemporaryError for event in faults) and
all(event.softDisable and not event.immediateDisable and event.name in
(log.OnroadEvent.EventName.locationdTemporaryError, log.OnroadEvent.EventName.commIssue) for event in faults))
temporary = location_fault or bool(len(faults) == 1 and faults[0].name in names and
faults[0].softDisable and not faults[0].immediateDisable)
eps_recovery = bool(not cs.steerFaultTemporary and getattr(self, 'temporary_eps_event_ns', 0) and
axis.faultEventMonoTime == self.temporary_eps_event_ns and
all(not event.immediateDisable and
(not event.softDisable or event.name == log.OnroadEvent.EventName.steerTempUnavailable) for event in events))
users = [event for event in events if event.userDisable]
if not (temporary or eps_recovery or users):
return False
from opendbc.car.chrysler.aol_contract import qualified as chrysler_qualified
from openpilot.starpilot.car.nissan.aol import qualified as nissan_qualified
from opendbc.car.ford.aol import qualified as ford_qualified
from opendbc.car.rivian.stock_aol import qualified as rivian_qualified
from openpilot.starpilot.car.volkswagen.aol import qualified as volkswagen_qualified
from opendbc.car.mazda.stock_aol import qualified as mazda_qualified
from opendbc.car.subaru.stock_aol import qualified as subaru_qualified
from opendbc.car.hyundai.canfd_angle_aol import qualified as angle_qualified
from opendbc.car.hyundai.canfd_stock_aol import qualified as stock_canfd_qualified
from opendbc.car.hyundai.classic_scc_aol import qualified as stock_classic_qualified
from opendbc.car import structs
gears = structs.CarState.GearShifter
# Stock PCM off is not the AOL toggle. After output withdrawal, retain prior intent through
# location faults or matched EPS recovery only; native/session/source checks still apply.
stock_angle = cp.brand == 'hyundai' and angle_qualified(cp, marked_only=True)
stock_hkg = cp.brand == 'hyundai' and (stock_angle or stock_canfd_qualified(cp, marked_only=True) or
stock_classic_qualified(cp, marked_only=True))
stock_user = stock_lateral_user_event(cp)
stock_temporary_user = bool((location_fault or eps_recovery) and (stock_hkg or cp.brand == 'chrysler' and chrysler_qualified(cp, marked_only=True) or
cp.brand == 'ford' and ford_qualified(cp, marked_only=True) or cp.brand == 'nissan' and nissan_qualified(cp, marked_only=True)
or cp.brand == 'subaru' and subaru_qualified(cp, marked_only=True)
or cp.brand == 'mazda' and mazda_qualified(cp, marked_only=True)
or cp.brand == 'rivian' and rivian_qualified(cp, marked_only=True)
or cp.brand == 'volkswagen' and volkswagen_qualified(cp, marked_only=True)) and users and
not axis.desiredLongitudinal and not axis.longitudinalActive and
cs.cruiseState.available and not cs.cruiseState.enabled and
cs.gearShifter in (gears.drive, gears.low, gears.sport, gears.brake) and
not cs.doorOpen and (not cs.seatbeltUnlatched or belt_eps_recovery) and not cs.brakePressed and not cs.regenBraking and
(not cs.gasPressed or stock_angle) and
all(event.name == stock_user and not event.softDisable and
not event.immediateDisable for event in users))
from openpilot.starpilot.car.ford.aol import temporary_eps_pedal_recovery
stock_temporary_user |= bool(cp.brand == 'ford' and eps_recovery and temporary_eps_pedal_recovery(cp, cs) and users and
not axis.desiredLongitudinal and not axis.longitudinalActive and
all(event.name in (stock_user, log.OnroadEvent.EventName.pedalPressed) and
not event.softDisable and not event.immediateDisable for event in users))
from openpilot.starpilot.car.gm.aol import f1_conventional_lateral_owner, gm_physical_pedal_withdrawal
# F1 physical withdrawal belongs to the receipt-bound GM owner below.
pedal = bool(not f1_conventional_lateral_owner(cp) and
(cs.brakePressed or gm_physical_pedal_withdrawal(cp, cs)) and users and all(
event.name == log.OnroadEvent.EventName.pedalPressed and
not event.softDisable and not event.immediateDisable for event in users) and not faults)
if axis.longitudinalActive and not location_fault or not (temporary or eps_recovery or pedal):
return False
if (not latched or self.failed or self.paused or self.pending_event or self.retention_started_ns or
not self.session or str(axis.sessionId) != self.session or
not producer or producer != self.availability_producer or
str(getattr(axis, 'intentProducerSessionId', '')) != producer or
int(getattr(axis, 'intentIntegrityEpoch', 0)) != self.availability_epoch or
not self.lateral_inventory or not self.lateral_baseline_ns or
not cs.canValid or cs.canTimeout or cs.steerFaultPermanent or cs.accFaulted or cs.steerFaultTemporary or
users and not (pedal or stock_temporary_user) or str(axis.faultReason) not in ('none', 'critical') or
not 0 < self.lateral_source_ns <= axis.sourceCarStateMonoTime <= stamp <= now_ns or
now_ns - axis.sourceCarStateMonoTime > AXIS_MAX_AGE_NS or
not sm.seen['onroadEvents'] or not sm.valid['onroadEvents'] or not sm.alive['onroadEvents']):
return False
event_ns = int(sm.logMonoTime['onroadEvents'])
if not 0 < event_ns <= now_ns or now_ns - event_ns > 1_500_000_000:
return False
withdrawn = not axis.desiredLateral and not axis.lateralActive and not axis.desiredLongitudinal and not axis.longitudinalActive
event_first = bool(temporary and str(axis.faultReason) == 'none' and
self.signature is not None and self.signature[9] and self.signature[11] and self.signature[13] and
axis.sequence >= self.sequence and stamp >= self.signature[2] and
temporary and axis.desiredLateral and axis.lateralActive and axis.nativeAcknowledged and
0 < axis.faultEventMonoTime < event_ns and now_ns - event_ns <= AXIS_MAX_AGE_NS)
if not (event_first or temporary and axis.faultEventMonoTime == event_ns and
(withdrawn or str(axis.faultReason) == 'none' and axis.desiredLateral and
axis.lateralActive and axis.nativeAcknowledged) or eps_recovery and withdrawn or
pedal and str(axis.faultReason) == 'none' and axis.desiredLateral and axis.lateralActive and
not axis.desiredLongitudinal and not axis.longitudinalActive and
axis.nativeAcknowledged and axis.faultEventMonoTime == event_ns):
return False
native = _configured_transport_native(sm, cp, self.session, now_ns, require_longitudinal=not pedal)
if (native is None or not native.pandaInventory or native.observedMonoTime < self.lateral_native_ns or
(native.pandaSerial, tuple(p.hardwareSerial for p in native.pandaInventory)) != self.lateral_inventory or
native.requestedLateral and not native.lateralAllowed or
pedal and not (native.requestedLateral and native.lateralAllowed) or
axis.lateralActive and not (native.requestedLateral and native.lateralAllowed) or
axis.longitudinalActive and not (native.requestedLongitudinal and native.longitudinalAllowed)):
return False
from openpilot.starpilot.aol.vehicle import policy_for
if not policy_for(cp).intent_supported:
return False
if pedal and not temporary and not eps_recovery and not native.requestedLongitudinal:
# Healthy LAT-only braking belongs to the normal baseline refresh below.
# The exception is needed only while native LONG withdrawal is pending.
return False
self.temporary_host_qualified = True
return True
def _temporary_lag_intent_current(self, sm, cp, cs, axis, stamp, now_ns, *, latched, producer, signature):
"""Retain intent only through isolated lag or its bounded critical/event join."""
reason = str(axis.faultReason)
events = sm['onroadEvents']
faults = [event for event in events if event.immediateDisable or event.softDisable]
isolated = bool(len(faults) == 1 and faults[0].name == log.OnroadEvent.EventName.selfdrivedLagging and
faults[0].softDisable and not faults[0].immediateDisable)
# Healthy cycles never reach policy/native/provenance work. A critical
# proof can precede its event, but cannot yet establish a lag exemption.
recovering = bool(cp.brand == 'gm' and not faults and reason == 'none' and
0 < self.lag_withdrawal_ns <= now_ns <= self.lag_withdrawal_ns + SAFETY_MAX_AGE_NS and
axis.desiredLateral and not axis.lateralActive and axis.nativeAcknowledged and
not axis.desiredLongitudinal and not axis.longitudinalActive)
if not recovering and not isolated and (reason != 'critical' or faults):
return False
previous = self.signature
joining = bool(self.pending_event and previous is not None and previous[5] == 'critical' and
previous[6] == self.pending_event)
if (not latched or self.failed or self.paused or self.pending_event and not joining or self.retention_started_ns or
not self.session or str(axis.sessionId) != self.session or reason not in ('none', 'critical') or
not producer or producer != self.availability_producer or
str(getattr(axis, 'intentProducerSessionId', '')) != producer or
int(getattr(axis, 'intentIntegrityEpoch', 0)) != self.availability_epoch or
not self.lateral_baseline_ns or not self.lateral_inventory or
not cs.canValid or cs.canTimeout or cs.steerFaultTemporary or cs.steerFaultPermanent or cs.accFaulted or
not 0 < axis.sourceCarStateMonoTime <= stamp <= now_ns or
now_ns - axis.sourceCarStateMonoTime > AXIS_MAX_AGE_NS):
return False
event_ns = int(sm.logMonoTime['onroadEvents'])
if (not sm.seen['onroadEvents'] or not sm.valid['onroadEvents'] or not sm.alive['onroadEvents'] or
not 0 < event_ns <= now_ns or now_ns - event_ns > 1_500_000_000 or
joining and
(axis.faultEventMonoTime != self.pending_event or now_ns - self.pending_event > AXIS_MAX_AGE_NS)):
return False
withdrawn = bool(reason == 'critical' and not axis.desiredLateral and not axis.desiredLongitudinal and
not axis.lateralActive and not axis.longitudinalActive)
matched = bool(withdrawn and isolated and axis.faultEventMonoTime == event_ns <= stamp)
held_original = bool(reason == 'none' and isolated and signature == previous and
axis.desiredLateral and axis.lateralActive and axis.nativeAcknowledged and
0 < axis.faultEventMonoTime < event_ns and now_ns - event_ns <= AXIS_MAX_AGE_NS)
known_lag = bool(isolated and previous is not None and previous[5] == 'critical' and previous[6] == event_ns)
pending = bool(withdrawn and event_ns < axis.faultEventMonoTime <= stamp and
now_ns - axis.faultEventMonoTime <= AXIS_MAX_AGE_NS and
(joining or known_lag or not faults and previous is not None and previous[5] == 'none' and
0 <= now_ns - self.lateral_baseline_ns <= AXIS_MAX_AGE_NS))
if not (matched or held_original or pending or recovering):
return False
from openpilot.starpilot.aol.vehicle import policy_for
if not policy_for(cp).intent_supported:
return False
native = _healthy_transport_native(sm, cp, cs, self.session, now_ns)
if (native is None or not native.pandaInventory or
held_original and not (native.requestedLateral and native.lateralAllowed) or
native.observedMonoTime < self.lateral_native_ns or
(native.pandaSerial, tuple(p.hardwareSerial for p in native.pandaInventory)) != self.lateral_inventory):
return False
users = [event for event in events if event.userDisable]
if users:
from opendbc.car.gm.values import is_volt_sdgm_accepted_envelope, is_bolt_pedal_profile
from openpilot.starpilot.nostalgia import physical_cancel
# Accepted Volt SDGM/Bolt LAT-only brake/regen emits pedalPressed/USER_DISABLE.
# Preserve intent through source-qualified temporary lag, never an axis or lease.
gm_pedal = bool(self.lateral_only_baseline and (is_volt_sdgm_accepted_envelope(cp) or is_bolt_pedal_profile(cp)) and
(cs.brakePressed or cs.regenBraking) and cs.cruiseState.available and
not cs.doorOpen and not cs.seatbeltUnlatched and not cs.steeringDisengage and not physical_cancel(cs, cp) and
not axis.desiredLongitudinal and not axis.longitudinalActive and
not native.requestedLongitudinal and not native.longitudinalAllowed and
all(event.name == log.OnroadEvent.EventName.pedalPressed and event.noEntry and
not event.softDisable and not event.immediateDisable for event in users))
stock_user = stock_lateral_user_event(cp)
# Stock GM emits PCM-off/USER during host-lag LAT withdrawal. An exact fresh OFF receipt
# retains existing intent only, never permission or output.
gm_stock_withdrawal = bool(cp.brand == 'gm' and cp.pcmCruise and self.lateral_only_baseline and
(withdrawn or recovering) and cs.cruiseState.available and not cs.cruiseState.enabled and
not cs.brakePressed and not cs.regenBraking and not cs.gasPressed and
not cs.doorOpen and not cs.seatbeltUnlatched and not cs.steeringDisengage and
not physical_cancel(cs, cp) and not native.requestedLateral and not native.lateralAllowed and
not native.requestedLongitudinal and not native.longitudinalAllowed and
all(event.name == stock_user and not event.softDisable and not event.immediateDisable for event in users))
if not gm_pedal and not gm_stock_withdrawal and (not getattr(self, 'lateral_only_baseline', False) or stock_user is None or
any(event.name != stock_user or event.softDisable or event.immediateDisable for event in users) or
not stock_lateral_off(cp, cs, native)):
return False
if pending:
if not self.pending_event:
self.pending_event = int(axis.faultEventMonoTime)
self.awaiting = True
elif joining:
self.pending_event = 0
if matched and cp.brand == 'gm':
# Track the latest verified inactive proof, not fault age. Fresh lag withdrawals renew
# no output, native permission, source lease, or healthy baseline.
self.lag_withdrawal_ns = stamp
return True
def _ford_gas_release_eps_join_current(self, sm, cp, cs, axis, stamp, now_ns, *, producer, latched):
from openpilot.starpilot.car.ford.aol import temporary_eps_restriction
gas_was_pressed = self.temporary_eps_gas_override
previous = self.signature
if (cp.brand != 'ford' or cp.openpilotLongitudinalControl or
not cp.safetyConfigs[-1].safetyParam & 128 or
not latched or not gas_was_pressed or cs.gasPressed or
not temporary_eps_restriction(cp, cs) or not self.lateral_only_baseline or
self.failed or self.paused or self.pending_event or self.retention_started_ns or
not self.ever_lateral_active or cp_identity(cp) != self.cp or previous is None or
not self.temporary_eps_event_ns or not self.lateral_inventory or not self.lateral_baseline_ns or
previous[0] != self.session or previous[7] != self.session or previous[1] != self.sequence or
previous[5] != 'none' or any(previous[9:13]) or not previous[13] or
previous[6] != self.temporary_eps_event_ns or
previous[14] != producer or previous[15] != self.availability_epoch or
not 0 < previous[8] <= previous[2] <= now_ns <= previous[4] or
now_ns - previous[8] > AXIS_MAX_AGE_NS):
return False
if (not axis.qualified or str(axis.sessionId) != self.session or str(axis.faultSessionId) != self.session or
str(axis.intentProducerSessionId) != producer or int(axis.intentIntegrityEpoch) != self.availability_epoch or
int(axis.sequence) < self.sequence or str(axis.faultReason) != 'none' or str(axis.mode) != 'off' or
not axis.nativeAcknowledged or any((axis.desiredLateral,axis.lateralActive,axis.desiredLongitudinal,axis.longitudinalActive)) or
not sm.seen['aolAxisState'] or not sm.valid['aolAxisState'] or not sm.alive['aolAxisState'] or
not previous[8] <= axis.sourceCarStateMonoTime <= stamp == axis.observedMonoTime <= now_ns <= axis.validUntilMonoTime or
now_ns - axis.sourceCarStateMonoTime > AXIS_MAX_AGE_NS or
axis.validUntilMonoTime - stamp > AXIS_MAX_AGE_NS):
return False
event_ns = int(sm.logMonoTime['onroadEvents'])
events = sm['onroadEvents']
temporary_names = ('steerTempUnavailable','steerTempUnavailableSilent')
if (axis.faultEventMonoTime == event_ns or
min(axis.faultEventMonoTime,event_ns) != self.temporary_eps_event_ns or
not 0 < max(axis.faultEventMonoTime,event_ns) <= now_ns or
now_ns-max(axis.faultEventMonoTime,event_ns) > AXIS_MAX_AGE_NS or
not sm.seen['onroadEvents'] or not sm.valid['onroadEvents'] or not sm.alive['onroadEvents'] or
now_ns-event_ns > 1_500_000_000 or
not any(str(e.name)in temporary_names for e in events) or
any(e.immediateDisable or e.softDisable and str(e.name)!='steerTempUnavailable' or
e.userDisable and str(e.name)!='pcmDisable' or
str(e.name)not in (*temporary_names,'pcmDisable','gasPressedOverride','steerOverride') for e in events)):
return False
native = _configured_transport_native(sm,cp,self.session,now_ns,allow_restricted_lateral=True)
return bool(native is not None and native.pandaInventory and
not any((native.requestedLateral,native.lateralAllowed,native.requestedLongitudinal,native.longitudinalAllowed)) and
native.observedMonoTime>=self.lateral_native_ns and
self.lateral_inventory==(native.pandaSerial,tuple(p.hardwareSerial for p in native.pandaInventory)))
def _temporary_steering_intent_current(self, sm, cp, cs, axis, stamp, now_ns, *, latched, producer, signature):
"""Keep an existing armed intent during isolated temporary EPS withdrawal."""
if (not latched or self.failed or self.paused or self.retention_started_ns or
not self.session or str(axis.sessionId) != self.session or not cs.steerFaultTemporary or
cs.steerFaultPermanent or not cs.canValid or cs.canTimeout or
str(axis.faultReason) != 'none' or
not producer or producer != self.availability_producer or
str(getattr(axis, 'intentProducerSessionId', '')) != producer or
int(getattr(axis, 'intentIntegrityEpoch', 0)) != self.availability_epoch or
not self.lateral_baseline_ns or not self.lateral_inventory or
not 0 < axis.sourceCarStateMonoTime <= stamp <= now_ns or
now_ns - axis.sourceCarStateMonoTime > AXIS_MAX_AGE_NS):
return False
withdrawn = not axis.desiredLateral and not axis.lateralActive
previous = self.signature
pending = bool(self.pending_event)
all_off = bool(withdrawn and not axis.desiredLongitudinal and not axis.longitudinalActive and str(axis.mode) == 'off')
if pending and (not all_off or previous is None or previous[5] != 'none' or
previous[0] != self.session or previous[7] != self.session or
previous[1] != self.sequence or previous[6] != self.pending_event or
previous[9] or previous[10] or previous[11] or previous[12] or
previous[14] != producer or previous[15] != self.availability_epoch or
axis.faultEventMonoTime != self.pending_event or
axis.sourceCarStateMonoTime < previous[8] or stamp < previous[2] or
not 0 < self.pending_event <= now_ns or now_ns - self.pending_event > AXIS_MAX_AGE_NS):
return False
# Prior healthy ACTIVE may arrive in Card's first temporary-EPS cycle. Accept identity
# only within the previous ACTIVE's original source/output lease; renew no permission
# deadline or healthy baseline.
fresh_active_successor = bool(previous is not None and axis.sequence > self.sequence and
previous[5] == 'none' and previous[9] and previous[11] and previous[13] and
previous[6] == axis.faultEventMonoTime and previous[14] == producer and
previous[15] == self.availability_epoch and
axis.sourceCarStateMonoTime >= previous[8] and stamp >= previous[2] and
0 < previous[8] <= previous[2] <= now_ns <= previous[4] and
now_ns - previous[8] <= AXIS_MAX_AGE_NS and
0 < self.lateral_source_ns <= now_ns and
now_ns - self.lateral_source_ns <= AXIS_MAX_AGE_NS)
held_original = bool(axis.desiredLateral and axis.lateralActive and axis.nativeAcknowledged and
(signature == previous or fresh_active_successor))
if not withdrawn and not held_original:
return False
event_ns = int(sm.logMonoTime['onroadEvents'])
# Seatbelt warnings block ordinary LONG, not already admitted independent
# LAT intent. Keep the published warning and all native/output checks.
events = tuple(event for event in sm['onroadEvents'] if not (
self.lateral_only_baseline and cs.seatbeltUnlatched and not axis.desiredLongitudinal and
not axis.longitudinalActive and event.name == log.OnroadEvent.EventName.seatbeltNotLatched and
event.softDisable and event.noEntry and not event.immediateDisable and not event.userDisable))
temporary_names = (log.OnroadEvent.EventName.steerTempUnavailable,
log.OnroadEvent.EventName.steerTempUnavailableSilent)
if (not sm.seen['onroadEvents'] or not sm.valid['onroadEvents'] or not sm.alive['onroadEvents'] or
not 0 < event_ns <= now_ns or now_ns - event_ns > 1_500_000_000 or
any(event.immediateDisable or event.softDisable and event.name != temporary_names[0] for event in events) or
pending and any(event.userDisable for event in events)):
return False
temporary_event = any(event.name in temporary_names for event in events)
matched_withdrawal = bool(temporary_event and axis.faultEventMonoTime == event_ns <= stamp)
original_active = bool(previous is not None and previous[0] == self.session and
previous[7] == self.session and previous[5] == 'none' and
previous[9] and previous[11] and previous[13] and previous[6] == event_ns and
axis.sourceCarStateMonoTime >= previous[8] and stamp >= previous[2] and
previous[14] == producer and previous[15] == self.availability_epoch and
0 < self.lateral_source_ns <= previous[8] <= previous[2] <= now_ns <= previous[4] and
now_ns - previous[8] <= AXIS_MAX_AGE_NS)
pending_withdrawal = bool(all_off and not any(event.softDisable or event.userDisable for event in events) and
not temporary_event and 0 < event_ns < axis.faultEventMonoTime <= stamp and
now_ns - axis.faultEventMonoTime <= AXIS_MAX_AGE_NS and
(pending or original_active and axis.sequence > self.sequence))
if withdrawn and not (matched_withdrawal or pending_withdrawal):
return False
if held_original and not (
axis.faultEventMonoTime == event_ns <= stamp and not any(event.softDisable for event in events) or
temporary_event and 0 < axis.faultEventMonoTime < event_ns and now_ns - event_ns <= AXIS_MAX_AGE_NS):
return False
# This exception validates intent only. The normal vehicle-health helper
# continues to reject temporary EPS for transport and availability proofs.
from openpilot.starpilot.car.nissan.aol import temporary_eps_restriction
from openpilot.starpilot.car.ford.aol import temporary_eps_restriction as ford_temporary_eps_restriction
stock_ford_eps = bool(ford_temporary_eps_restriction(cp, cs) and
all(not event.userDisable or event.name in (log.OnroadEvent.EventName.pcmDisable,
log.OnroadEvent.EventName.pedalPressed) and not event.softDisable and not event.immediateDisable for event in events))
from opendbc.car import structs
from opendbc.car.mazda.stock_aol import qualified as mazda_qualified
stock_mazda_eps = bool(mazda_qualified(cp, marked_only=True) and
cs.cruiseState.available and not cs.cruiseState.enabled and
cs.gearShifter == structs.CarState.GearShifter.drive and
not cs.brakePressed and not cs.regenBraking and not cs.gasPressed and
not cs.doorOpen and not cs.accFaulted and
not cs.vehicleSensorsInvalid and not cs.steeringDisengage and not cs.buttonEvents and
all(not event.userDisable or event.name == log.OnroadEvent.EventName.pcmDisable and
not event.softDisable and not event.immediateDisable for event in events))
from opendbc.car.rivian.stock_aol import temporary_eps_restriction as rivian_temporary_eps_restriction
stock_rivian_eps = bool(rivian_temporary_eps_restriction(cp, cs) and
all(not event.userDisable or event.name == log.OnroadEvent.EventName.pcmDisable and
not event.softDisable and not event.immediateDisable for event in events))
from openpilot.starpilot.car.volkswagen.aol import temporary_eps_restriction as volkswagen_temporary_eps_restriction
stock_volkswagen_eps = bool(volkswagen_temporary_eps_restriction(cp, cs) and
all(not event.userDisable or event.name == log.OnroadEvent.EventName.pcmDisable and
not event.softDisable and not event.immediateDisable for event in events))
restricted_eps = bool((temporary_eps_restriction(cp, cs) or stock_ford_eps or stock_mazda_eps or stock_rivian_eps or
stock_volkswagen_eps) and self.lateral_only_baseline and
not axis.desiredLongitudinal and not axis.longitudinalActive)
native = _configured_transport_native(sm, cp, self.session, now_ns, allow_restricted_lateral=restricted_eps)
if (native is None or not native.pandaInventory or
held_original and not (native.requestedLateral and (native.lateralAllowed or
restricted_eps and not native.requestedLongitudinal and not native.longitudinalAllowed)) or
axis.longitudinalActive and not native.longitudinalAllowed or
native.observedMonoTime < self.lateral_native_ns or
(native.pandaSerial, tuple(p.hardwareSerial for p in native.pandaInventory)) != self.lateral_inventory):
return False
if stock_volkswagen_eps and matched_withdrawal:
self.volkswagen_eps_source_ns = int(axis.sourceCarStateMonoTime)
if cs.steerFaultTemporary and matched_withdrawal:
self.temporary_eps_event_ns = int(axis.faultEventMonoTime)
if cp.brand == 'ford':
# Bind the prior gas state to this accepted event receipt, not a newer
# parsed CS that may already have released gas on the other socket.
self.temporary_eps_gas_override = any(
event.name == log.OnroadEvent.EventName.gasPressedOverride for event in events)
if pending_withdrawal:
# Keep only intent while this exact physical-EPS occurrence awaits its
# event socket. Duplicate/newer proofs cannot move the original anchor.
if not pending:
self.pending_event = int(axis.faultEventMonoTime)
self.awaiting = True
elif pending:
self.pending_event = 0
return True
def _honda_brake_lateral_current(self, sm, cp, cs, axis, now_ns, *, latched, brake_source_ns):
"""Preserve existing LAT intent through brake's LONG withdrawal, never output."""
from opendbc.car.honda.stock_aol import qualified
from opendbc.car.structs import car
source_ns = self.honda_brake_ns or (brake_source_ns if cs.brakePressed else 0)
if (not qualified(cp, marked_only=True) or not latched or self.failed or self.paused or self.pending_event or
not self.session or str(axis.sessionId) != self.session or
not self.healthy_feedback_ns or not 0 <= now_ns - self.healthy_feedback_ns <= AXIS_MAX_AGE_NS or
not 0 < source_ns <= now_ns or now_ns - source_ns > SAFETY_MAX_AGE_NS or
(not self.honda_brake_ns and now_ns - source_ns > AXIS_MAX_AGE_NS) or
cs.accFaulted or cs.seatbeltUnlatched or
cs.gearShifter not in (car.CarState.GearShifter.drive, car.CarState.GearShifter.sport,
car.CarState.GearShifter.low, car.CarState.GearShifter.brake) or
str(axis.faultReason) != 'none' or not axis.desiredLateral or not axis.lateralActive or
(not axis.nativeAcknowledged and (axis.desiredLongitudinal or axis.longitudinalActive)) or
not 0 < axis.sourceCarStateMonoTime <= axis.observedMonoTime or
axis.observedMonoTime - axis.sourceCarStateMonoTime > AXIS_MAX_AGE_NS):
return None
event_ns = int(sm.logMonoTime['onroadEvents'])
if (not sm.seen['onroadEvents'] or not sm.valid['onroadEvents'] or not sm.alive['onroadEvents'] or
not 0 < event_ns <= now_ns or now_ns - event_ns > 1_500_000_000 or
any(e.immediateDisable or e.softDisable for e in sm['onroadEvents'])):
return None
native = independent_lateral_health(sm, cp, cs, self.session, now_ns)
if (native is None or not native.requestedLateral or not native.lateralAllowed or
not native.requestedLongitudinal or native.observedMonoTime < self.healthy_native_ns or
(native.pandaSerial, tuple(p.hardwareSerial for p in native.pandaInventory)) != self.healthy_inventory):
return None
self.honda_brake_ns = source_ns
return native
def _longitudinal_cancel_current(self, sm, cp, cs, axis, now_ns, *, latched, cancel_source_ns, withdrawal_required=True) -> SafetyState | None:
"""Retain existing intent during Cancel's bounded LONG withdrawal handshake."""
from opendbc.car.hyundai.ev6_aol import qualified
from openpilot.starpilot.car.hyundai.aol import qualified_ccnc_long_aol as ev9_qualified
from opendbc.car.structs import car
if (not latched or self.failed or self.paused or self.pending_event or
not self.session or str(axis.sessionId) != self.session or
not (qualified(cp, marked_only=True) or ev9_qualified(cp, marked_only=True)) or
not self.lateral_baseline_ns or not 0 <= now_ns - self.lateral_baseline_ns <= AXIS_MAX_AGE_NS or
str(axis.faultReason) != 'none' or not axis.nativeAcknowledged or
not axis.desiredLateral or not axis.lateralActive or cs.accFaulted or
not cs.canValid or cs.canTimeout or cs.steerFaultTemporary or cs.steerFaultPermanent):
return None
cancel = any(e.type == car.CarState.ButtonEvent.Type.cancel and e.pressed for e in cs.buttonEvents)
fresh_cancel = bool(cancel and self.last_cancel_source_ns < cancel_source_ns <= now_ns and
now_ns - cancel_source_ns <= AXIS_MAX_AGE_NS)
if not self.longitudinal_cancel_ns and not fresh_cancel:
return None
if not withdrawal_required and (self.longitudinal_cancel_ns or not fresh_cancel):
return None
if self.longitudinal_cancel_ns and not 0 <= now_ns - self.longitudinal_cancel_ns <= SAFETY_MAX_AGE_NS:
return None
event_ns = int(sm.logMonoTime['onroadEvents'])
if (not sm.seen['onroadEvents'] or not sm.valid['onroadEvents'] or not sm.alive['onroadEvents'] or
not 0 < event_ns <= now_ns or now_ns - event_ns > 1_500_000_000 or
any(e.immediateDisable or e.softDisable for e in sm['onroadEvents'])):
return None
native = current_native(sm, cp, now_ns=now_ns, axis_session_id=self.session)
if (native is None or not native.pandaInventory or not native.requestedLateral or not native.lateralAllowed or
not native.requestedLongitudinal or withdrawal_required and native.longitudinalAllowed or
native.observedMonoTime < self.lateral_native_ns or
not native_inventory_matches_cp(native, cp) or
(native.pandaSerial, tuple(p.hardwareSerial for p in native.pandaInventory)) != self.lateral_inventory):
return None
stamp = int(sm.logMonoTime['pandaStates'])
pandas = sm['pandaStates']
if (not sm.seen['pandaStates'] or not sm.valid['pandaStates'] or not sm.alive['pandaStates'] or stamp <= 0 or
len(pandas) != len(cp.safetyConfigs)):
return None
# controlsAllowed represents the withdrawn normal/LONG axis here. Preserve
# every latest raw configuration/fault veto and exact producer-read inventory.
current_pandas = all(int(p.safetyModel.raw) == int(c.safetyModel.raw) and p.safetyParam == c.safetyParam and
p.alternativeExperience == cp.alternativeExperience and not p.safetyRxChecksInvalid and
not p.heartbeatLost and not blocking_fault_list(p.faults, cp) and
(str(c.safetyModel) not in ('silent', 'noOutput') or not p.controlsAllowed)
for p, c in zip(pandas, cp.safetyConfigs, strict=True))
return native if current_pandas else None
def _availability_retention(self, sm, cp, cs, axis, stamp, now_ns, *, latched, current, continuity, intent_producer_session):
reason = str(axis.faultReason)
events = sm['onroadEvents']
if reason not in ('none', 'availabilityPause') or reason == 'none' and not availability_only(events):
return False
if not (latched and current and continuity and not self.paused and not self.pending_event and
cp_identity(cp) == self.cp and intent_producer_session and
getattr(axis, 'intentProducerSessionId', '') == intent_producer_session == self.availability_producer and
int(getattr(axis, 'intentIntegrityEpoch', 0)) == self.availability_epoch and
self.session and
self.lateral_inventory and axis.desiredLateral and
(str(axis.faultReason) == 'none' or not axis.desiredLongitudinal) and
axis.nativeAcknowledged and (
0 < axis.sourceCarStateMonoTime <= stamp and stamp - axis.sourceCarStateMonoTime <= AXIS_MAX_AGE_NS or
reason == 'availabilityPause' and axis.sourceCarStateMonoTime == 0 and
not axis.lateralActive and not axis.longitudinalActive)):
return False
native = _healthy_transport_native(sm, cp, cs, str(axis.sessionId), now_ns)
if (native is None or not native.requestedLateral or not native.lateralAllowed or
native.observedMonoTime < self.lateral_native_ns or
(native.pandaSerial, tuple(p.hardwareSerial for p in native.pandaInventory)) != self.lateral_inventory):
return False
# Qualified stock USER describes disabled LONG, not LAT cancellation. Check this inactive
# source-zero proof against its accepted LAT-only baseline and current real native grant.
previous = self.signature
from openpilot.starpilot.car.toyota.aol import qualified as toyota_qualified
toyota_pedal = bool(toyota_qualified(cp, marked_only=True) and cs.brakePressed != cs.gasPressed and
not cs.regenBraking and self.lateral_only_baseline and
not native.requestedLongitudinal and not native.longitudinalAllowed)
stock_user = stock_lateral_user_event(cp)
stock_lateral = bool(reason == 'availabilityPause' and axis.sourceCarStateMonoTime == 0 and
not axis.lateralActive and not axis.longitudinalActive and not axis.desiredLongitudinal and
stock_lateral_off(cp, cs, native, allow_independent_brake=toyota_pedal,
allow_independent_gas=toyota_pedal and cs.gasPressed) and previous is not None and
previous[0] == self.session and previous[7] == self.session and
previous[14] == intent_producer_session and previous[15] == self.availability_epoch and
(previous[11] and not previous[12] and previous[13] and not previous[10] and
(previous[9] and previous[5] == 'none' or (self.retention_verified or self.retention_started_ns) and
previous[5] == 'availabilityPause' and previous[8] == 0 and not previous[9] and
previous[6] == axis.faultEventMonoTime) or
# Only the matched temporary-lag branch can accept a critical signature.
# Unmatched joins retain pending_event; every other critical path fails
# and clears the LAT-only baseline before changing the signature.
self.lateral_only_baseline and not self.failed and not self.pending_event and
(previous[5] == 'critical' or previous[5] == 'availabilityPause' and self.ordinary_warning_retained) and
previous[1] == self.sequence and not any(previous[9:14]) and
0 < previous[6] <= previous[2] <= axis.faultEventMonoTime and
0 < self.lateral_source_ns <= previous[8] <= previous[2] and
previous[2] - previous[8] <= AXIS_MAX_AGE_NS and
0 <= now_ns - previous[8] <= SAFETY_MAX_AGE_NS))
if stock_lateral:
users = [event for event in events if event.userDisable]
if any((event.name != stock_user and not (toyota_pedal and event.name == log.OnroadEvent.EventName.pedalPressed)) or
event.softDisable or event.immediateDisable for event in users):
return False
events = [event for event in events if not ((event.name == stock_user or
toyota_pedal and event.name == log.OnroadEvent.EventName.pedalPressed) and
event.userDisable and not event.softDisable and not event.immediateDisable)]
if cp.brand == 'gm':
from openpilot.starpilot.car.gm.aol import sdgm_lateral_pedal_source_zero
if sdgm_lateral_pedal_source_zero(self, cp, cs, axis, native, now_ns,
producer=intent_producer_session):
events = [event for event in events if not (event.name == log.OnroadEvent.EventName.pedalPressed and
event.userDisable and not event.softDisable and not event.immediateDisable)]
event_ns = int(sm.logMonoTime['onroadEvents'])
faults = [event for event in events if event.immediateDisable or event.softDisable]
live_event = bool(sm.valid['onroadEvents'] and sm.alive['onroadEvents'] and
0 < event_ns <= now_ns and now_ns - event_ns <= 1_500_000_000)
host_source_off = bool(reason == 'availabilityPause' and axis.sourceCarStateMonoTime == 0 and
not axis.lateralActive and not axis.longitudinalActive)
issue = live_event and (availability_only(events) or host_source_off and host_source_availability_only(events))
if reason not in ('none', 'availabilityPause') or faults and not issue:
return False
typed = bool(reason == 'availabilityPause' and not axis.lateralActive and not axis.longitudinalActive and
0 < axis.faultEventMonoTime <= stamp)
source_expired = bool(typed and axis.sourceCarStateMonoTime == 0)
# The original 200ms source bound admits an episode, never active output. After exact
# event/proof verification, fresh OFF source-zero proofs retain intent only with CURRENT
# real native LAT and unchanged producer/epoch/configuration/inventory. Missing/mismatched
# events keep the fixed 30ms join; all other deadlines and branches remain unchanged.
continuing_intent = bool(source_expired and self.retention_verified and issue)
if source_expired and not (0 < self.lateral_source_ns <= now_ns and
(now_ns <= self.lateral_source_ns + SAFETY_MAX_AGE_NS or continuing_intent)):
return False
baseline_age_limit = SAFETY_MAX_AGE_NS if source_expired else AXIS_MAX_AGE_NS
matched = typed and issue and axis.faultEventMonoTime == event_ns
occurrence = max(int(axis.faultEventMonoTime) if typed else 0, event_ns if issue else 0)
if not occurrence or occurrence < self.retention_event_ns:
return False
if matched:
if not self.retention_verified and not 0 <= now_ns - self.lateral_baseline_ns <= baseline_age_limit:
return False
if self.retention_started_ns and now_ns - self.retention_started_ns > AXIS_MAX_AGE_NS:
return False
self.retention_verified = True
self.retention_started_ns = 0
self.retention_event_ns = occurrence
else:
if not self.retention_started_ns:
if not self.retention_verified and not 0 <= now_ns - self.lateral_baseline_ns <= baseline_age_limit:
return False
self.retention_started_ns = now_ns
self.retention_event_ns = occurrence
if occurrence != self.retention_event_ns or now_ns - self.retention_started_ns > AXIS_MAX_AGE_NS:
return False
self.retention_qualified, self.retention_pending = matched, not matched
self.lateral_native_ns = native.observedMonoTime
return True
def _availability_recovery_current(self, sm, cp, cs, axis, stamp, now_ns, *, latched, current, continuity, producer):
"""Join a verified pause's healthy recovery pair; this never grants output."""
event_ns = int(sm.logMonoTime['onroadEvents'])
# Both owners validate an accepted SOFT withdrawal. Closing its already
# pending healthy pair still requires every original deadline, source,
# event, producer/epoch, inventory and current native LAT grant below.
verified_pause = self.retention_verified or self.ordinary_warning_retained
if (not latched or self.failed or self.paused or self.pending_event or not verified_pause or
not self.retention_started_ns or not 0 <= now_ns - self.retention_started_ns <= AXIS_MAX_AGE_NS or
not current or not continuity or str(axis.sessionId) != self.session or
not producer or producer != self.availability_producer or
str(getattr(axis, 'intentProducerSessionId', '')) != producer or
int(getattr(axis, 'intentIntegrityEpoch', 0)) != self.availability_epoch or
str(axis.faultReason) != 'none' or not axis.nativeAcknowledged or
not axis.desiredLateral or not axis.lateralActive or
not 0 < axis.sourceCarStateMonoTime <= stamp <= now_ns or
now_ns - axis.sourceCarStateMonoTime > AXIS_MAX_AGE_NS or
not sm.seen['onroadEvents'] or not sm.valid['onroadEvents'] or not sm.alive['onroadEvents'] or
not 0 < event_ns == axis.faultEventMonoTime <= stamp):
return False
events = sm['onroadEvents']
faults = [event for event in events if event.userDisable or event.softDisable or event.immediateDisable]
combined = bool(axis.desiredLongitudinal and axis.longitudinalActive)
if combined:
# An event-first receiver has already recorded this NEW occurrence while
# holding the verified inactive source-zero pause. Close that exact join;
# neither the pending deadline nor any old command lease is renewed.
previous = self.signature
if (previous is None or previous[0] != self.session or previous[5] != 'availabilityPause' or
previous[7] != self.session or previous[8] != 0 or previous[9] or previous[10] or
not previous[11] or previous[12] or not previous[13] or
previous[14] != producer or previous[15] != self.availability_epoch or
not 0 < previous[6] < event_ns or self.retention_event_ns != event_ns or
len(faults) != 1 or faults[0].name != log.OnroadEvent.EventName.selfdrivedLagging or
not faults[0].softDisable or faults[0].userDisable or faults[0].immediateDisable or
any(event.noEntry and event.name != log.OnroadEvent.EventName.selfdrivedLagging for event in events)):
return False
elif (axis.desiredLongitudinal or axis.longitudinalActive or
not self.retention_event_ns < event_ns or faults):
return False
native = _healthy_transport_native(sm, cp, cs, self.session, now_ns)
return bool(native is not None and native.requestedLateral and native.lateralAllowed and
(not combined or native.requestedLongitudinal and native.longitudinalAllowed) and
native.observedMonoTime >= self.lateral_native_ns and
(native.pandaSerial, tuple(p.hardwareSerial for p in native.pandaInventory)) == self.lateral_inventory)
def _new_expired_combined_source(self, sm, cp, axis, stamp, now_ns, signature):
"""An established combined producer advanced while Card missed its output lease."""
previous = self.signature
if (now_ns <= signature[4] or previous is None or self.retention_started_ns or
not (sm.seen['aolAxisState'] and sm.valid['aolAxisState'] and sm.alive['aolAxisState']) or
not axis.desiredLongitudinal or not axis.longitudinalActive or
not all(previous[index] for index in (9, 10, 11, 12, 13)) or previous[5] != 'none' or
signature[1] <= self.sequence or stamp <= previous[2] or
not 0 < self.lateral_source_ns <= previous[8] < signature[8] <= stamp or
stamp - signature[8] > AXIS_MAX_AGE_NS or
signature[4] != stamp + AXIS_MAX_AGE_NS):
return False
from openpilot.starpilot.car.hyundai.aol import qualified_ioniq6
return qualified_ioniq6(cp)
def _source_availability_retention(self, sm, cp, cs, axis, stamp, now_ns, *, latched, continuity, producer, signature):
held = bool(signature == self.signature and not self.retention_started_ns)
output_missing = not (sm.seen['aolAxisState'] and sm.valid['aolAxisState'] and sm.alive['aolAxisState'])
matched_lag = bool((str(axis.faultReason) == 'critical' or
str(axis.faultReason) == 'availabilityPause' and self.ordinary_warning_retained) and signature == self.signature and
self.lateral_only_baseline and not self.failed and not self.pending_event and
signature[0] == self.session and signature[7] == self.session and signature[1] == self.sequence and
signature[14] == producer == self.availability_producer and signature[15] == self.availability_epoch and
not any(signature[9:14]) and 0 < signature[6] <= stamp and
0 < self.lateral_source_ns <= signature[8] <= stamp and stamp - signature[8] <= AXIS_MAX_AGE_NS)
if (not latched or self.failed or self.paused or self.pending_event or not self.session or
cp_identity(cp) != self.cp or not continuity or
str(axis.sessionId) != self.session or str(axis.faultSessionId) != self.session or
not axis.qualified or (str(axis.faultReason) != 'none' or not axis.nativeAcknowledged or
not axis.desiredLateral or not axis.lateralActive) and not matched_lag or
(axis.desiredLongitudinal or axis.longitudinalActive) and not held and
not self._new_expired_combined_source(sm, cp, axis, stamp, now_ns, signature) or
(not sm.seen['aolAxisState'] or not sm.valid['aolAxisState']) and not held or
int(axis.observedMonoTime) != stamp or not 0 < axis.sourceCarStateMonoTime <= stamp <= now_ns or
not 0 <= axis.validUntilMonoTime - stamp <= AXIS_MAX_AGE_NS or
now_ns - axis.sourceCarStateMonoTime > SAFETY_MAX_AGE_NS or
not (stamp - axis.sourceCarStateMonoTime > AXIS_MAX_AGE_NS or now_ns > axis.validUntilMonoTime or
held and output_missing) or
not producer or getattr(axis, 'intentProducerSessionId', '') != producer or
producer != self.availability_producer or
int(getattr(axis, 'intentIntegrityEpoch', 0)) != self.availability_epoch):
return False
if not 0 < self.lateral_source_ns <= now_ns <= self.lateral_source_ns + SAFETY_MAX_AGE_NS:
return False
if not self.source_retention_started_ns:
if not self.lateral_baseline_ns or not 0 <= now_ns - self.lateral_baseline_ns <= SAFETY_MAX_AGE_NS:
return False
self.source_retention_started_ns = now_ns
if not 0 <= now_ns - self.source_retention_started_ns <= SAFETY_MAX_AGE_NS:
return False
event_ns = int(sm.logMonoTime['onroadEvents'])
events = sm['onroadEvents']
faults = [e for e in events if e.immediateDisable or e.softDisable]
users = [e for e in events if e.userDisable]
stock_user = stock_lateral_user_event(cp)
nominal_users = bool(stock_user is not None and users and all(e.name == stock_user and
not e.softDisable and not e.immediateDisable for e in users))
host_events = [e for e in events if not (e.name == stock_user and e.userDisable and
not e.softDisable and not e.immediateDisable)]
stock_event_first = bool(signature == self.signature and
not axis.desiredLongitudinal and not axis.longitudinalActive and
now_ns > axis.validUntilMonoTime and nominal_users and host_source_availability_only(host_events) and
0 < axis.faultEventMonoTime < event_ns <= now_ns and now_ns - event_ns <= AXIS_MAX_AGE_NS)
stock_pending = bool(cp.pcmCruise and self.retention_started_ns and signature == self.signature and
not axis.desiredLongitudinal and not axis.longitudinalActive and
0 < axis.faultEventMonoTime < self.retention_event_ns)
if (not sm.seen['onroadEvents'] or not sm.valid['onroadEvents'] or not sm.alive['onroadEvents'] or
not 0 < event_ns <= now_ns or now_ns - event_ns > 1_500_000_000 or
bool(faults) and not stock_event_first or stock_pending and not stock_event_first or
matched_lag and not stock_event_first):
return False
native = _healthy_transport_native(sm, cp, cs, self.session, now_ns)
inactive_native = bool(held and self.source_retention_started_ns and native is not None and
not native.requestedLateral and not native.lateralAllowed and
not native.requestedLongitudinal and not native.longitudinalAllowed)
if (native is None or not native.pandaInventory or
(not native.requestedLateral or not native.lateralAllowed) and not inactive_native or
(axis.desiredLongitudinal or axis.longitudinalActive) and not held and
not (native.requestedLongitudinal and native.longitudinalAllowed) or
native.observedMonoTime < self.lateral_native_ns or
(native.pandaSerial, tuple(p.hardwareSerial for p in native.pandaInventory)) != self.lateral_inventory):
return False
if stock_event_first:
if not stock_lateral_off(cp, cs, native):
return False
if self.retention_started_ns:
if (self.retention_event_ns != event_ns or
not 0 <= now_ns - self.retention_started_ns <= AXIS_MAX_AGE_NS):
return False
else:
self.retention_started_ns = now_ns
self.retention_event_ns = event_ns
self.retention_pending = True
return True
def _event_first_retention(self, sm, cp, axis, stamp, now_ns, *, latched, signature, native):
if now_ns <= axis.validUntilMonoTime or signature != self.signature:
return False
if (not latched or self.failed or self.paused or not self.session or native is None or
cp_identity(cp) != self.cp or
str(axis.sessionId) != self.session or
str(axis.faultSessionId) != self.session or str(axis.faultReason) != 'none' or
not axis.qualified or not axis.nativeAcknowledged or not axis.desiredLateral or not axis.lateralActive or
not sm.seen['aolAxisState'] or not sm.valid['aolAxisState'] or not sm.alive['aolAxisState'] or
not 0 < axis.sourceCarStateMonoTime <= stamp <= now_ns or
not self.pending_event and now_ns - stamp > AXIS_MAX_AGE_NS or
stamp - axis.sourceCarStateMonoTime > AXIS_MAX_AGE_NS or
axis.validUntilMonoTime != axis.sourceCarStateMonoTime + AXIS_MAX_AGE_NS or
not stamp <= axis.validUntilMonoTime < stamp + AXIS_MAX_AGE_NS or
native.observedMonoTime < self.healthy_native_ns or
(native.pandaSerial, tuple(p.hardwareSerial for p in native.pandaInventory)) != self.healthy_inventory):
return False
event_ns = int(sm.logMonoTime['onroadEvents'])
faults = [event for event in sm['onroadEvents'] if event.immediateDisable or event.softDisable]
isolated = bool(len(faults) == 1 and faults[0].name == log.OnroadEvent.EventName.controlsMismatch and
faults[0].immediateDisable)
if (not isolated or not sm.seen['onroadEvents'] or not sm.valid['onroadEvents'] or not sm.alive['onroadEvents'] or
not 0 < axis.faultEventMonoTime < event_ns <= now_ns or now_ns - event_ns > AXIS_MAX_AGE_NS):
return False
if not self.pending_event:
if not self.healthy_feedback_ns or not 0 <= now_ns - self.healthy_feedback_ns <= AXIS_MAX_AGE_NS:
return False
self.pending_event = event_ns
if event_ns != self.pending_event or now_ns - self.pending_event > AXIS_MAX_AGE_NS:
return False
self.awaiting = True
return True
def _angle_stop_intent_current(self, sm, cp, cs, axis, stamp, now_ns, *, latched, producer):
from opendbc.car.structs import car
from opendbc.car.hyundai.canfd_angle_aol import qualified, temporary_restriction
from opendbc.car.mazda.stock_aol import qualified as mazda_qualified, temporary_restriction as mazda_restriction
from opendbc.car.subaru.stock_aol import temporary_restriction as subaru_restriction
subaru_stop = cs.standstill and subaru_restriction(cp, cs)
if (not (qualified(cp, marked_only=True) or mazda_qualified(cp, marked_only=True) or subaru_stop) or cs.gearShifter != car.CarState.GearShifter.drive or
not (temporary_restriction(cp, cs) or mazda_restriction(cp, cs) or subaru_stop) or cs.steerFaultTemporary or cs.steerFaultPermanent or
not latched or self.failed or self.paused or self.pending_event or self.retention_started_ns or
not self.lateral_only_baseline or not self.lateral_inventory or not self.lateral_baseline_ns or
not self.session or axis.sessionId != self.session or str(axis.faultReason) != 'none' or
not producer or producer != self.availability_producer or
axis.intentProducerSessionId != producer or axis.intentIntegrityEpoch != self.availability_epoch or
not (axis.desiredLateral or subaru_stop and not axis.lateralActive) or not axis.nativeAcknowledged or
axis.desiredLongitudinal or axis.longitudinalActive or
not 0 < axis.sourceCarStateMonoTime <= stamp <= now_ns or
now_ns - axis.sourceCarStateMonoTime > AXIS_MAX_AGE_NS):
return False
event_ns = int(sm.logMonoTime['onroadEvents'])
if (not sm.seen['onroadEvents'] or not sm.valid['onroadEvents'] or not sm.alive['onroadEvents'] or
not 0 < event_ns <= now_ns or now_ns - event_ns > 1_500_000_000 or
any(event.immediateDisable or event.softDisable or event.userDisable and
event.name not in (log.OnroadEvent.EventName.pcmDisable, log.OnroadEvent.EventName.pedalPressed)
for event in sm['onroadEvents'])):
return False
native = _configured_transport_native(sm, cp, self.session, now_ns, allow_restricted_lateral=True)
return bool(native is not None and native.pandaInventory and native.requestedLateral and
not native.lateralAllowed and not native.requestedLongitudinal and
native.observedMonoTime >= self.lateral_native_ns and
(native.pandaSerial, tuple(p.hardwareSerial for p in native.pandaInventory)) == self.lateral_inventory)
def _inactive_gear_source_gap(self, sm, cp, cs, axis, stamp, now_ns, *, latched, producer):
"""Keep existing intent through a source-zero OFF sample while reversing.
Both axes must already be OFF in the host and native inventory. Only the
original healthy source's 200ms intent-retention bound applies; this never
grants output or advances any source, native, output or baseline lease.
"""
from opendbc.car import structs
previous = self.signature
if (not latched or self.failed or self.paused or self.pending_event or self.retention_started_ns or
self.source_retention_started_ns or not self.ever_lateral_active or previous is None or
not self.session or cp_identity(cp) != self.cp or previous[0] != self.session or
previous[7] != self.session or previous[5] != 'none' or any(previous[9:13]) or not previous[13] or
not producer or previous[14] != producer or
not 0 < previous[8] <= previous[2] <= self.healthy_feedback_ns <= now_ns or
now_ns - previous[8] > SAFETY_MAX_AGE_NS or
cs.gearShifter not in (structs.CarState.GearShifter.reverse, structs.CarState.GearShifter.neutral) or
not cs.canValid or cs.canTimeout or cs.steerFaultTemporary or cs.steerFaultPermanent or
cs.accFaulted or cs.vehicleSensorsInvalid or cs.doorOpen or cs.seatbeltUnlatched or
cs.steeringDisengage or not cs.cruiseState.available or cs.buttonEvents or
not sm.seen['aolAxisState'] or not sm.alive['aolAxisState'] or sm.valid['aolAxisState'] or
axis.qualified or axis.sourceCarStateMonoTime != 0 or str(axis.mode) != 'off' or
axis.desiredLateral or axis.desiredLongitudinal or axis.lateralActive or axis.longitudinalActive or
axis.nativeAcknowledged or str(axis.faultReason) != 'none' or
str(axis.sessionId) != self.session or str(axis.faultSessionId) != self.session or
str(axis.intentProducerSessionId) != producer or int(axis.intentIntegrityEpoch) != previous[15] or
axis.sequence <= self.sequence or not previous[2] < stamp == axis.observedMonoTime <= now_ns <= axis.validUntilMonoTime or
axis.validUntilMonoTime - stamp != AXIS_MAX_AGE_NS):
return False
event_ns = int(sm.logMonoTime['onroadEvents'])
allowed = (log.OnroadEvent.EventName.wrongGear, log.OnroadEvent.EventName.reverseGear,
log.OnroadEvent.EventName.preEnableStandstill, log.OnroadEvent.EventName.pedalPressed,
log.OnroadEvent.EventName.gasPressedOverride, log.OnroadEvent.EventName.steerOverride,
log.OnroadEvent.EventName.pcmDisable)
if (not sm.seen['onroadEvents'] or not sm.valid['onroadEvents'] or not sm.alive['onroadEvents'] or
not 0 < event_ns == axis.faultEventMonoTime <= stamp or now_ns - event_ns > 1_500_000_000 or
any(event.name not in allowed or event.immediateDisable or
event.softDisable and event.name != log.OnroadEvent.EventName.wrongGear or
event.userDisable and event.name not in (log.OnroadEvent.EventName.reverseGear,
log.OnroadEvent.EventName.pedalPressed, log.OnroadEvent.EventName.pcmDisable)
for event in sm['onroadEvents'])):
return False
native = _healthy_transport_native(sm, cp, cs, self.session, now_ns)
return bool(native is not None and native.pandaInventory and
not (native.requestedLateral or native.lateralAllowed or native.requestedLongitudinal or native.longitudinalAllowed) and
native.observedMonoTime >= self.healthy_native_ns and self.healthy_inventory ==
(native.pandaSerial, tuple(slot.hardwareSerial for slot in native.pandaInventory)))
def _inactive_source_pause_current(self, sm, cp, cs, axis, stamp, now_ns, *, latched, producer):
"""Retain accepted intent through a bounded, fully withdrawn source pause."""
from opendbc.car import structs
previous = self.signature
if (not latched or self.failed or self.paused or self.pending_event or self.retention_started_ns or
self.source_retention_started_ns or not self.ever_lateral_active or previous is None or
not self.session or cp_identity(cp) != self.cp or previous[0] != self.session or
previous[7] != self.session or previous[5] != 'none' or not previous[11] or not previous[13] or
not producer or previous[14] != producer or
not 0 < previous[8] <= previous[2] <= self.healthy_feedback_ns <= now_ns or
now_ns - previous[8] > SAFETY_MAX_AGE_NS or
cs.gearShifter not in (structs.CarState.GearShifter.drive, structs.CarState.GearShifter.low,
structs.CarState.GearShifter.sport, structs.CarState.GearShifter.brake) or
not cs.canValid or cs.canTimeout or cs.steerFaultTemporary or cs.steerFaultPermanent or
cs.accFaulted or cs.vehicleSensorsInvalid or cs.doorOpen or cs.seatbeltUnlatched or
cs.steeringDisengage or not cs.cruiseState.available or cs.buttonEvents or
not sm.seen['aolAxisState'] or not sm.alive['aolAxisState'] or not sm.valid['aolAxisState'] or
not axis.qualified or axis.sourceCarStateMonoTime != 0 or str(axis.mode) != 'off' or
axis.desiredLateral or axis.desiredLongitudinal or axis.lateralActive or axis.longitudinalActive or
axis.nativeAcknowledged or str(axis.faultReason) != 'availabilityPause' or
str(axis.sessionId) != self.session or str(axis.faultSessionId) != self.session or
str(axis.intentProducerSessionId) != producer or int(axis.intentIntegrityEpoch) != previous[15] or
axis.sequence <= self.sequence or not previous[2] < stamp == axis.observedMonoTime <= now_ns <= axis.validUntilMonoTime or
axis.validUntilMonoTime - stamp != AXIS_MAX_AGE_NS or not 0 < axis.faultEventMonoTime <= stamp):
return False
event_ns = int(sm.logMonoTime['onroadEvents'])
events = sm['onroadEvents']
matched = event_ns == axis.faultEventMonoTime
if (not sm.seen['onroadEvents'] or not sm.valid['onroadEvents'] or not sm.alive['onroadEvents'] or
not 0 < event_ns <= now_ns or now_ns - event_ns > 1_500_000_000 or
(not host_source_availability_only(events) if matched else
any(event.immediateDisable or event.softDisable or event.userDisable for event in events))):
return False
native = _healthy_transport_native(sm, cp, cs, self.session, now_ns)
if native is None or not native.pandaInventory:
return False
granted = bool(native.requestedLateral and native.lateralAllowed and
native.requestedLongitudinal == previous[12] and native.longitudinalAllowed == previous[12])
withdrawn = not (native.requestedLateral or native.lateralAllowed or native.requestedLongitudinal or native.longitudinalAllowed)
return bool((granted or withdrawn) and native.observedMonoTime >= self.healthy_native_ns and
self.healthy_inventory == (native.pandaSerial, tuple(slot.hardwareSerial for slot in native.pandaInventory)))
def observe(self, sm, cp, cs, now_ns, *, latched=True, cancel_source_ns=0, brake_source_ns=0,
gm_withdrawal_source_ns=0, intent_producer_session='', main_arm_ns=0, startup_calibration_pending=False, intent_paused=False):
self.ordinary_warning_qualified = False
self.temporary_host_qualified = False
self.qualified = False
self.awaiting = False
self.retention_qualified = False
self.retention_pending = False
try:
axis = sm['aolAxisState']
if not latched or cp_identity(cp) != self.cp or self.session and str(axis.sessionId) != self.session:
self.ordinary_warning_retained = False
self.ordinary_warning_pending_baseline = None
self.temporary_eps_event_ns = 0
self.ccnc_main_off_source_ns = 0
self.cold_park_waiting = False
self.cold_main_sparse_waiting = False
stamp = int(sm.logMonoTime['aolAxisState'])
reason = str(axis.faultReason)
signature = (str(axis.sessionId), int(axis.sequence), stamp, int(axis.observedMonoTime),
int(axis.validUntilMonoTime), reason, int(axis.faultEventMonoTime), str(axis.faultSessionId),
int(axis.sourceCarStateMonoTime), bool(axis.lateralActive), bool(axis.longitudinalActive),
bool(axis.desiredLateral), bool(axis.desiredLongitudinal), bool(axis.nativeAcknowledged),
str(getattr(axis, 'intentProducerSessionId', '')), int(getattr(axis, 'intentIntegrityEpoch', 0)))
current = bool(sm.seen['aolAxisState'] and sm.valid['aolAxisState'] and sm.alive['aolAxisState'] and
axis.qualified and axis.sessionId and axis.sequence > 0 and stamp == axis.observedMonoTime and
0 < stamp <= now_ns <= axis.validUntilMonoTime and now_ns - stamp <= AXIS_MAX_AGE_NS and
axis.validUntilMonoTime - stamp <= AXIS_MAX_AGE_NS and axis.faultSessionId == axis.sessionId and
cp_identity(cp) == self.cp)
continuity = bool(not self.session or axis.sessionId == self.session and
(axis.sequence > self.sequence or axis.sequence == self.sequence and signature == self.signature))
if not current and continuity and self._inactive_gear_source_gap(sm, cp, cs, axis, stamp, now_ns, latched=latched,
producer=intent_producer_session):
return False
if current and continuity and reason == 'availabilityPause' and self._inactive_source_pause_current(
sm, cp, cs, axis, stamp, now_ns, latched=latched, producer=intent_producer_session):
self.retention_qualified = int(sm.logMonoTime['onroadEvents']) == axis.faultEventMonoTime
self.retention_pending = not self.retention_qualified
return False
from openpilot.starpilot.car.gm.aol import sdgm_alpha_lateral_owner
if (sdgm_alpha_lateral_owner(cp) and latched and current and continuity and self.signature is not None and
signature[14:16] != self.signature[14:16]):
self.failed = True
return True
if ((self.cold_main_wait_ns or self.cold_park_waiting) and current and continuity and self.signature is not None and
signature[14:16] != self.signature[14:16]):
self.failed = True
return True
if (cp.brand == 'gm' and current and continuity and latched and not self.failed and
not self.ever_lateral_active and not self.pending_event and reason == 'none' and
axis.nativeAcknowledged and not any(signature[9:13]) and
intent_producer_session and signature[14] == intent_producer_session and
(self.signature is None or signature[14:16] == self.signature[14:16]) and
0 < axis.sourceCarStateMonoTime <= stamp and now_ns - axis.sourceCarStateMonoTime <= AXIS_MAX_AGE_NS):
from openpilot.starpilot.car.gm.aol import cold_park_readiness
native = _healthy_transport_native(sm, cp, cs, str(axis.sessionId), now_ns)
event_ns = int(sm.logMonoTime['onroadEvents'])
if (axis.faultEventMonoTime == event_ns and sm.seen['onroadEvents'] and
sm.valid['onroadEvents'] and sm.alive['onroadEvents'] and
0 < event_ns <= stamp and now_ns - event_ns <= 1_500_000_000 and
cold_park_readiness(cp, cs, native, sm['onroadEvents'])):
self.cold_park_waiting = True
self.session = str(axis.sessionId)
self.sequence, self.signature = int(axis.sequence), signature
self.temporary_host_qualified = True
return False
if cp.brand == 'ford' and latched:
from openpilot.starpilot.car.ford.command_pause import retain_command_pause_intent
if retain_command_pause_intent(self, sm, cp, cs, axis, now_ns, latched=latched, producer=intent_producer_session):
return False
if (cp.brand == 'chrysler' and current and continuity and latched and
not self.failed and not self.ever_lateral_active):
from openpilot.starpilot.car.chrysler.aol import cold_calibration_intent_current
native = _healthy_transport_native(sm, cp, cs, str(axis.sessionId), now_ns)
if cold_calibration_intent_current(self, sm, cp, cs, axis, native, now_ns,
pending=startup_calibration_pending, producer=intent_producer_session):
self.session = str(axis.sessionId)
self.sequence, self.signature = int(axis.sequence), signature
return False
if current and continuity and 0 < main_arm_ns <= now_ns <= main_arm_ns + AXIS_MAX_AGE_NS:
from openpilot.starpilot.car.gm.aol import prior_main_off_intent_current
if prior_main_off_intent_current(self, sm, cp, cs, axis, now_ns,
latched=latched, main_arm_ns=main_arm_ns, producer=intent_producer_session):
self.sequence, self.signature = int(axis.sequence), signature
return False
if cp.brand == 'gm' and current and continuity and latched:
from openpilot.starpilot.car.gm.aol import cold_gm_main_intent_current
native = (_healthy_transport_native(sm, cp, cs, str(axis.sessionId), now_ns)
if cp.brand == 'gm' else None)
if cold_gm_main_intent_current(self, sm, cp, cs, axis, native, now_ns,
producer=intent_producer_session):
self.session = str(axis.sessionId)
self.sequence, self.signature = int(axis.sequence), signature
event_ns = int(sm.logMonoTime['onroadEvents'])
if not self.cold_main_wait_ns:
self.cold_main_wait_ns = event_ns
self.cold_main_sparse_waiting |= now_ns - event_ns > AXIS_MAX_AGE_NS
self.temporary_host_qualified = True
return False
if (cp.brand == 'gm' and current and continuity and latched and not self.failed and
not self.ever_lateral_active and not self.pending_event):
from openpilot.starpilot.car.gm.aol import cold_main_readiness
native = _healthy_transport_native(sm, cp, cs, str(axis.sessionId), now_ns)
event_ns = int(sm.logMonoTime['onroadEvents'])
recovering = bool(reason == 'none' and axis.desiredLateral and not axis.desiredLongitudinal and
not axis.lateralActive and not axis.longitudinalActive and axis.nativeAcknowledged and
0 < self.cold_main_wait_ns <= now_ns and
(self.cold_main_sparse_waiting or now_ns <= self.cold_main_wait_ns + SAFETY_MAX_AGE_NS) and
0 < axis.sourceCarStateMonoTime <= stamp and now_ns - axis.sourceCarStateMonoTime <= AXIS_MAX_AGE_NS)
if ((reason == 'availabilityPause' and not any(signature[9:13]) or recovering) and
intent_producer_session and signature[14] == intent_producer_session and
(self.signature is None or signature[14:16] == self.signature[14:16]) and
axis.faultEventMonoTime == event_ns and sm.seen['onroadEvents'] and
sm.valid['onroadEvents'] and sm.alive['onroadEvents'] and 0 < event_ns <= stamp and
now_ns - event_ns <= AXIS_MAX_AGE_NS and
cold_main_readiness(cp, cs, native, sm['onroadEvents'], recovering=recovering)):
if recovering:
self.cold_main_wait_ns = 0
self.cold_main_sparse_waiting = False
else:
self.cold_main_wait_ns = event_ns
self.session = str(axis.sessionId)
self.sequence, self.signature = int(axis.sequence), signature
self.temporary_host_qualified = True
return False
if (self.cold_main_wait_ns and current and continuity and reason == 'none' and
axis.nativeAcknowledged and axis.desiredLateral and not axis.lateralActive):
event_ns = int(sm.logMonoTime['onroadEvents'])
recovery_ahead = bool(sm.seen['onroadEvents'] and sm.valid['onroadEvents'] and
sm.alive['onroadEvents'] and 0 < event_ns < axis.faultEventMonoTime <= stamp and
now_ns - event_ns <= AXIS_MAX_AGE_NS)
if not recovery_ahead:
self.failed = True
return True
if current and continuity and self._angle_stop_intent_current(sm, cp, cs, axis, stamp, now_ns,
latched=latched, producer=intent_producer_session):
self.sequence, self.signature = int(axis.sequence), signature
return False
if current and continuity and (reason == 'critical' or self.lag_withdrawal_ns and not axis.lateralActive or
getattr(sm, 'updated', {}).get('onroadEvents', False)) and self._temporary_lag_intent_current(sm, cp, cs, axis, stamp, now_ns,
latched=latched, producer=intent_producer_session, signature=signature):
self.sequence, self.signature = int(axis.sequence), signature
return False
if (cp.brand == 'gm' and self.lag_withdrawal_ns and current and continuity and reason == 'none' and
axis.desiredLateral and not axis.lateralActive):
self.failed = True
return True
if cp.brand == 'volkswagen' and current and continuity:
from openpilot.starpilot.car.volkswagen.aol import retain_eps_recovery
if retain_eps_recovery(self, sm, cp, cs, axis, now_ns, latched=latched, producer=intent_producer_session):
self.sequence, self.signature = int(axis.sequence), signature
return False
if current and continuity and self._ordinary_warning_intent_current(sm, cp, cs, axis, stamp, now_ns,
latched=latched, producer=intent_producer_session):
self.ordinary_warning_qualified = any(event.softDisable for event in sm['onroadEvents'])
self.sequence, self.signature = int(axis.sequence), signature
return False
if current and continuity and self._temporary_host_intent_current(sm, cp, cs, axis, stamp, now_ns,
latched=latched, producer=intent_producer_session):
self.sequence, self.signature = int(axis.sequence), signature
return False
if (cp.brand == 'ford' and current and continuity and
self._ford_gas_release_eps_join_current(sm, cp, cs, axis, stamp, now_ns,
latched=latched, producer=intent_producer_session)):
return False
if current and continuity and self._temporary_steering_intent_current(sm, cp, cs, axis, stamp, now_ns,
latched=latched, producer=intent_producer_session, signature=signature):
self.sequence, self.signature = int(axis.sequence), signature
return False
if cp.brand == 'honda' and current and continuity:
from opendbc.car.honda.stock_aol import qualified as honda_stock_qualified
from openpilot.starpilot.aol.reverse_intent import retain_reverse_intent
if retain_reverse_intent(self, sm, cp, cs, axis, now_ns, latched=latched, producer=intent_producer_session,
qualified_cp=honda_stock_qualified(cp, marked_only=True),
extra_user_events=(log.OnroadEvent.EventName.cruiseDisabled,),
informational_events=(log.OnroadEvent.EventName.userBookmarkNotPaired,), allow_withdrawal_join=True):
return False
if cp.brand == 'mazda' and current and continuity:
from opendbc.car.mazda.stock_aol import qualified as mazda_qualified
from openpilot.starpilot.aol.reverse_intent import retain_reverse_intent
if retain_reverse_intent(self, sm, cp, cs, axis, now_ns, latched=latched, producer=intent_producer_session,
qualified_cp=mazda_qualified(cp, marked_only=True),
informational_events=(log.OnroadEvent.EventName.userBookmarkNotPaired,), allow_withdrawal_join=True):
return False
if cp.brand == 'rivian' and current and continuity:
from opendbc.car.rivian.stock_aol import qualified as rivian_qualified
from openpilot.starpilot.aol.reverse_intent import retain_reverse_intent
if retain_reverse_intent(self, sm, cp, cs, axis, now_ns, latched=latched, producer=intent_producer_session,
qualified_cp=rivian_qualified(cp, marked_only=True),
informational_events=(log.OnroadEvent.EventName.userBookmarkNotPaired,), allow_withdrawal_join=True):
return False
if cp.brand == 'nissan' and current and continuity:
from openpilot.starpilot.car.nissan.aol import qualified as nissan_qualified
from openpilot.starpilot.aol.reverse_intent import retain_reverse_intent
if retain_reverse_intent(self, sm, cp, cs, axis, now_ns, latched=latched, producer=intent_producer_session,
qualified_cp=nissan_qualified(cp, marked_only=True),
informational_events=(log.OnroadEvent.EventName.userBookmarkNotPaired,), allow_withdrawal_join=True):
return False
if cp.brand == 'subaru' and current and continuity:
from opendbc.car.subaru.stock_aol import qualified as subaru_qualified
from openpilot.starpilot.aol.reverse_intent import retain_reverse_intent
if retain_reverse_intent(self, sm, cp, cs, axis, now_ns, latched=latched, producer=intent_producer_session,
qualified_cp=subaru_qualified(cp, marked_only=True),
informational_events=(log.OnroadEvent.EventName.userBookmarkNotPaired,), allow_withdrawal_join=True):
return False
if cp.brand == 'ford' and current and continuity:
from openpilot.starpilot.car.ford.reverse_intent import retain_reverse_intent
from openpilot.starpilot.car.ford.physical_pause import retain_physical_pause_intent
from openpilot.starpilot.car.ford.gas_override import retained_gas_lateral_native
if retain_reverse_intent(self, sm, cp, cs, axis, now_ns, latched=latched, producer=intent_producer_session):
return False
if retain_physical_pause_intent(self, sm, cp, cs, axis, now_ns, latched=latched, producer=intent_producer_session):
return False
gas_native = retained_gas_lateral_native(self, sm, cp, cs, axis, now_ns, latched=latched, producer=intent_producer_session)
if gas_native is not None:
self.lateral_baseline_ns = stamp
self.lateral_source_ns = int(axis.sourceCarStateMonoTime)
self.lateral_native_ns = int(gas_native.observedMonoTime)
self.sequence, self.signature = int(axis.sequence), signature
return False
brake_native = (self._honda_brake_lateral_current(sm, cp, cs, axis, now_ns,
latched=latched, brake_source_ns=brake_source_ns) if current and continuity else None)
if brake_native is not None:
self.healthy_feedback_ns = stamp
self.healthy_native_ns = int(brake_native.observedMonoTime)
self.sequence, self.signature = int(axis.sequence), signature
return False
if current and continuity and (gm_withdrawal_source_ns or self.gm_withdrawal_ns):
from openpilot.starpilot.car.gm.aol import retained_physical_longitudinal_intent
gm_native = retained_physical_longitudinal_intent(self, sm, cp, cs, axis, now_ns,
latched=latched, source_ns=gm_withdrawal_source_ns, producer=intent_producer_session)
if gm_native is not None:
self.healthy_feedback_ns = stamp
self.healthy_native_ns = int(gm_native.observedMonoTime)
self.sequence, self.signature = int(axis.sequence), signature
return False
if self._source_availability_retention(sm, cp, cs, axis, stamp, now_ns,
latched=latched, continuity=continuity, producer=intent_producer_session, signature=signature):
self.sequence, self.signature = int(axis.sequence), signature
return False
if not self.failed and self._availability_retention(sm, cp, cs, axis, stamp, now_ns,
latched=latched, current=current, continuity=continuity, intent_producer_session=intent_producer_session):
self.sequence, self.signature = int(axis.sequence), signature
return False
if self._availability_recovery_current(sm, cp, cs, axis, stamp, now_ns,
latched=latched, current=current, continuity=continuity, producer=intent_producer_session):
self.retention_started_ns = self.retention_event_ns = 0
self.retention_verified = False
if self.retention_started_ns:
self.retention_started_ns = self.retention_event_ns = 0
self.retention_verified = False
self.failed = True
self.lateral_only_baseline = False
return True
if reason != 'availabilityPause' and not availability_only(sm['onroadEvents']):
self.retention_started_ns = self.retention_event_ns = 0
self.retention_verified = False
native = _healthy_transport_native(sm, cp, cs, str(axis.sessionId), now_ns)
if (native is None and intent_paused and cs.canValid and not cs.canTimeout and
not cs.steerFaultPermanent and not any(signature[9:13])):
native = _configured_transport_native(sm, cp, str(axis.sessionId), now_ns)
from opendbc.car import structs
previous = self.signature
inactive = bool(not self.failed and self.session and previous is not None and
previous[5] == 'none' and previous[14:16] == signature[14:16] and
intent_producer_session and signature[14] == intent_producer_session and
(intent_paused or bool(getattr(self, 'temporary_eps_event_ns', 0)) or not any(previous[9:13])) and
str(axis.mode) == 'off' and not any(signature[9:13]) and
cs.cruiseState.available and not cs.accFaulted and not cs.vehicleSensorsInvalid and
not cs.doorOpen and not cs.steeringDisengage and
(cs.gearShifter in (structs.CarState.GearShifter.drive, structs.CarState.GearShifter.sport,
structs.CarState.GearShifter.low, structs.CarState.GearShifter.brake) or
intent_paused and cs.gearShifter in (structs.CarState.GearShifter.reverse, structs.CarState.GearShifter.neutral)) and
sm.seen['onroadEvents'] and sm.valid['onroadEvents'] and sm.alive['onroadEvents'] and
0 < int(sm.logMonoTime['onroadEvents']) <= now_ns and
now_ns - int(sm.logMonoTime['onroadEvents']) <= 1_500_000_000 and
all(not event.immediateDisable and
(not event.softDisable or intent_paused and event.name in
(log.OnroadEvent.EventName.wrongGear, log.OnroadEvent.EventName.steerTempUnavailable) or
cs.seatbeltUnlatched and event.name == log.OnroadEvent.EventName.seatbeltNotLatched and
event.noEntry and not event.userDisable) and
(not event.userDisable or event.name in
(log.OnroadEvent.EventName.pcmDisable, log.OnroadEvent.EventName.buttonCancel,
log.OnroadEvent.EventName.reverseGear) or intent_paused and event.name == log.OnroadEvent.EventName.wrongGear)
for event in sm['onroadEvents']) and
native is not None and native.pandaInventory and self.healthy_inventory ==
(native.pandaSerial, tuple(slot.hardwareSerial for slot in native.pandaInventory)) and
not native.requestedLateral and not native.lateralAllowed and
not native.requestedLongitudinal and not native.longitudinalAllowed)
from openpilot.starpilot.car.gm.aol import main_off_idle_native_baseline
gm_main_off = bool(not latched and current and continuity and
sm.seen['onroadEvents'] and sm.valid['onroadEvents'] and sm.alive['onroadEvents'] and
0 < int(sm.logMonoTime['onroadEvents']) <= now_ns and
now_ns - int(sm.logMonoTime['onroadEvents']) <= 1_500_000_000 and
axis.faultEventMonoTime == int(sm.logMonoTime['onroadEvents']) and
main_off_idle_native_baseline(cp, cs, axis, native, sm['onroadEvents'], producer=intent_producer_session))
baseline = bool(reason == 'none' and (axis.nativeAcknowledged or inactive or gm_main_off) and
0 < axis.sourceCarStateMonoTime <= stamp and
stamp - axis.sourceCarStateMonoTime <= AXIS_MAX_AGE_NS)
if native is None and latched and current and continuity and baseline:
native = _newer_combined_intent_native(sm, cp, cs, axis, now_ns)
lateral_native = (self._native_long_withdrawal_lateral_current(sm, cp, cs, axis, now_ns,
latched=latched, producer=intent_producer_session)
if native is None and current and continuity and baseline else None)
first_ford_grant = (self._first_ford_gas_lateral_grant(sm, cp, cs, axis, now_ns,
latched=latched, producer=intent_producer_session)
if native is None and lateral_native is None and current and continuity and baseline else None)
if first_ford_grant is not None:
lateral_native = first_ford_grant
self.availability_producer = str(axis.intentProducerSessionId)
self.availability_epoch = int(axis.intentIntegrityEpoch)
self.lateral_inventory = (lateral_native.pandaSerial, tuple(slot.hardwareSerial for slot in lateral_native.pandaInventory))
self.ever_lateral_active = True
if lateral_native is not None:
from openpilot.starpilot.car.hyundai.aol import qualified_ccnc_long_aol
if not cs.cruiseState.available and qualified_ccnc_long_aol(cp, marked_only=True):
self.ccnc_main_off_source_ns = now_ns
self.lateral_baseline_ns = stamp
self.lateral_source_ns = int(axis.sourceCarStateMonoTime)
self.lateral_native_ns = int(lateral_native.observedMonoTime)
self.sequence, self.signature = int(axis.sequence), signature
return False
transport_healthy = native is not None
cancel_native = (self._longitudinal_cancel_current(sm, cp, cs, axis, now_ns, latched=latched,
cancel_source_ns=cancel_source_ns)
if current and continuity and baseline and not transport_healthy else None)
if self._event_first_retention(sm, cp, axis, stamp, now_ns, latched=latched,
signature=signature, native=native):
return False
current = bool(current and (transport_healthy or cancel_native is not None))
if current and baseline and not latched:
# A healthy idle baseline ends the previous cold MAIN recovery. Do not
# reject the next request using a wait owned by the cleared intent.
self.cold_main_wait_ns = 0
self.cold_main_sparse_waiting = False
self.cold_park_waiting = False
self.temporary_eps_event_ns = 0
self.session = ''
self.pending_event = 0
self.failed = False
self.longitudinal_cancel_ns = 0
continuity = True
if self.failed:
self.longitudinal_cancel_ns = 0
return True
if cancel_native is not None:
if not self.longitudinal_cancel_ns:
self.longitudinal_cancel_ns = int(cancel_source_ns)
self.last_cancel_source_ns = int(cancel_source_ns)
self.lateral_baseline_ns = now_ns
self.lateral_source_ns = int(axis.sourceCarStateMonoTime)
self.lateral_native_ns = int(cancel_native.observedMonoTime)
self.sequence = int(axis.sequence)
self.signature = signature
return False
if transport_healthy:
if not latched or native is not None and not native.requestedLongitudinal:
self.gm_withdrawal_ns = 0
if native is not None and not native.requestedLongitudinal:
self.honda_brake_ns = 0
if (not latched or native is not None and not native.requestedLongitudinal or
self.longitudinal_cancel_ns and now_ns - self.longitudinal_cancel_ns > SAFETY_MAX_AGE_NS):
self.longitudinal_cancel_ns = 0
if not current or not continuity or reason not in ('none', 'transportPause'):
self.longitudinal_cancel_ns = 0
hard = (self.paused or bool(self.pending_event) or reason == 'critical' or
bool(self.session and (latched or not continuity)))
self.paused = False
self.pending_event = 0
self.failed = hard
self.lateral_only_baseline = bool(self.lateral_only_baseline and not hard)
return hard
known = bool(self.session)
if reason == 'none':
if not baseline:
hard = self.paused or bool(self.pending_event) or bool(self.session and latched)
self.paused = False
self.pending_event = 0
self.failed = hard
self.lateral_only_baseline = bool(self.lateral_only_baseline and not hard)
return hard
event_ns = int(sm.logMonoTime['onroadEvents'])
faults = [e for e in sm['onroadEvents'] if e.immediateDisable or e.softDisable]
isolated = bool(len(faults) == 1 and faults[0].name == log.OnroadEvent.EventName.controlsMismatch and
faults[0].immediateDisable)
if known and isolated and sm.valid['onroadEvents'] and 0 < axis.faultEventMonoTime < event_ns <= now_ns:
if not self.pending_event:
self.pending_event = event_ns
if event_ns != self.pending_event or now_ns - self.pending_event > AXIS_MAX_AGE_NS:
self.pending_event = 0
self.paused = False
self.failed = True
self.lateral_only_baseline = False
return True
self.awaiting = True
return False
if self.pending_event:
self.pending_event = 0
self.paused = False
self.failed = True
self.lateral_only_baseline = False
return True
cancel_pending = self._longitudinal_cancel_current(sm, cp, cs, axis, now_ns, latched=latched,
cancel_source_ns=cancel_source_ns, withdrawal_required=False)
if cancel_pending is not None:
self.longitudinal_cancel_ns = int(cancel_source_ns)
self.last_cancel_source_ns = int(cancel_source_ns)
self.source_retention_started_ns = 0
self.healthy_feedback_ns = now_ns
self.healthy_native_ns = int(native.observedMonoTime) if native is not None else 0
self.healthy_inventory = ((native.pandaSerial, tuple(p.hardwareSerial for p in native.pandaInventory))
if native is not None else None)
self.session = str(axis.sessionId)
lateral_baseline = bool(axis.desiredLateral and axis.lateralActive and native is not None and
native.pandaInventory and native.requestedLateral and native.lateralAllowed)
self.lateral_baseline_ns = now_ns if lateral_baseline else 0
self.lateral_source_ns = int(axis.sourceCarStateMonoTime) if lateral_baseline else 0
self.availability_producer = (str(getattr(axis, 'intentProducerSessionId', '')) if lateral_baseline and
intent_producer_session and getattr(axis, 'intentProducerSessionId', '') == intent_producer_session else '')
self.availability_epoch = int(getattr(axis, 'intentIntegrityEpoch', 0)) if self.availability_producer else None
self.lateral_only_baseline = bool(lateral_baseline and self.availability_producer and
not axis.desiredLongitudinal and not axis.longitudinalActive and not native.requestedLongitudinal)
if lateral_baseline and native is not None:
self.ordinary_warning_retained = False
self.ever_lateral_active = True
self.lag_withdrawal_ns = 0
self.cold_main_wait_ns = 0
self.cold_main_sparse_waiting = False
self.cold_park_waiting = False
self.temporary_eps_event_ns = 0
self.lateral_native_ns = int(native.observedMonoTime)
self.lateral_inventory = (native.pandaSerial, tuple(p.hardwareSerial for p in native.pandaInventory))
else:
self.lateral_native_ns = 0
self.lateral_inventory = None
self.paused = False
else:
provenance = bool(known and not axis.lateralActive and not axis.longitudinalActive and
not axis.desiredLongitudinal and 0 < axis.faultEventMonoTime <= stamp)
pending = bool(provenance and axis.faultEventMonoTime > sm.logMonoTime['onroadEvents'])
if pending and not self.pending_event:
self.pending_event = int(axis.faultEventMonoTime)
self.qualified = bool(provenance and
axis.faultEventMonoTime == sm.logMonoTime['onroadEvents'] and
sm.valid['onroadEvents'] and axis.faultEventMonoTime <= now_ns)
if self.pending_event and (axis.faultEventMonoTime != self.pending_event or
now_ns - self.pending_event > AXIS_MAX_AGE_NS):
self.pending_event = 0
self.paused = False
self.failed = True
self.lateral_only_baseline = False
return True
if not self.qualified and not pending:
self.failed = True
self.lateral_only_baseline = False
return True
if self.qualified:
self.pending_event = 0
self.paused = True
self.sequence = int(axis.sequence)
self.signature = signature
return False
except (AttributeError, KeyError, IndexError, TypeError, ValueError):
self.longitudinal_cancel_ns = 0
hard = self.paused or bool(self.pending_event) or bool(self.session and latched)
self.paused = False
self.pending_event = 0
self.failed = hard
self.lateral_only_baseline = bool(self.lateral_only_baseline and not hard)
return hard