"""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