mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-10-28 00:53:45 +08:00
156 lines
6.3 KiB
Python
156 lines
6.3 KiB
Python
"""Retain established LAT intent across a physical Reverse/native withdrawal join."""
|
|
|
|
from opendbc.car import structs
|
|
from openpilot.cereal import log
|
|
from openpilot.starpilot.aol.runtime import AXIS_MAX_AGE_NS, current_native
|
|
from openpilot.starpilot.aol.transport_pause import cp_identity
|
|
|
|
|
|
def retain_reverse_intent(feedback, sm, cp, cs, axis, now_ns, *, latched, producer, qualified_cp,
|
|
extra_user_events=(), informational_events=(), allow_withdrawal_join=False):
|
|
"""Retain only an existing intent under its original fresh LAT-only proof.
|
|
|
|
This never grants output or renews a healthy/source/native/output deadline.
|
|
A subsequent OFF proof must satisfy the unchanged configured-native path.
|
|
"""
|
|
try:
|
|
if (
|
|
not qualified_cp
|
|
or not latched
|
|
or feedback.failed
|
|
or feedback.paused
|
|
or feedback.pending_event
|
|
or feedback.awaiting
|
|
or feedback.retention_started_ns
|
|
or feedback.retention_pending
|
|
or feedback.retention_qualified
|
|
or feedback.source_retention_started_ns
|
|
or feedback.cp != cp_identity(cp)
|
|
or cs.gearShifter != structs.CarState.GearShifter.reverse
|
|
or not cs.canValid
|
|
or cs.canTimeout
|
|
or cs.steerFaultTemporary
|
|
or cs.steerFaultPermanent
|
|
or cs.vehicleSensorsInvalid
|
|
or cs.accFaulted
|
|
or cs.gasPressed
|
|
or cs.steeringDisengage
|
|
or not cs.cruiseState.available
|
|
or cs.buttonEvents
|
|
):
|
|
return False
|
|
previous = feedback.signature
|
|
stamp = int(sm.logMonoTime['aolAxisState'])
|
|
active = bool(str(axis.mode) == 'lateralOnly' and axis.desiredLateral and axis.lateralActive and axis.nativeAcknowledged)
|
|
# Separate producer/native sockets can deliver a fresh OFF receipt before
|
|
# the axis producer acknowledges it. Retain only the original LAT intent.
|
|
withdrawing = bool(allow_withdrawal_join and str(axis.mode) == 'off' and
|
|
not axis.desiredLateral and not axis.lateralActive and not axis.nativeAcknowledged)
|
|
if (
|
|
not feedback.session
|
|
or str(axis.sessionId) != feedback.session
|
|
or axis.faultSessionId != axis.sessionId
|
|
or str(axis.faultReason) != 'none'
|
|
or not (active or withdrawing)
|
|
or not axis.qualified
|
|
or axis.desiredLongitudinal
|
|
or axis.longitudinalActive
|
|
or not sm.seen['aolAxisState']
|
|
or not sm.valid['aolAxisState']
|
|
or not sm.alive['aolAxisState']
|
|
or not 0 < 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
|
|
or not producer
|
|
or producer != feedback.availability_producer
|
|
or str(axis.intentProducerSessionId) != producer
|
|
or int(axis.intentIntegrityEpoch) != feedback.availability_epoch
|
|
or feedback.availability_epoch is None
|
|
or not feedback.lateral_only_baseline
|
|
or not feedback.lateral_inventory
|
|
or previous is None
|
|
or not 0 < feedback.lateral_source_ns <= feedback.lateral_baseline_ns <= now_ns
|
|
or now_ns - feedback.lateral_source_ns > AXIS_MAX_AGE_NS
|
|
or previous[0] != feedback.session
|
|
or previous[7] != feedback.session
|
|
or previous[5] != 'none'
|
|
or not previous[9]
|
|
or not previous[11]
|
|
or not previous[13]
|
|
or previous[10]
|
|
or previous[12]
|
|
or previous[14] != producer
|
|
or previous[15] != feedback.availability_epoch
|
|
or not 0 < previous[8] <= previous[2] <= now_ns <= previous[4]
|
|
or now_ns - previous[8] > AXIS_MAX_AGE_NS
|
|
or axis.sourceCarStateMonoTime < previous[8]
|
|
or stamp < previous[2]
|
|
or not (
|
|
axis.sequence > feedback.sequence
|
|
or axis.sequence == feedback.sequence
|
|
and stamp == previous[2]
|
|
and axis.sourceCarStateMonoTime == previous[8]
|
|
and axis.validUntilMonoTime == previous[4]
|
|
and axis.faultEventMonoTime == previous[6]
|
|
)
|
|
):
|
|
return False
|
|
event_ns = int(sm.logMonoTime['onroadEvents'])
|
|
allowed = (log.OnroadEvent.EventName.pcmDisable, log.OnroadEvent.EventName.wrongGear,
|
|
log.OnroadEvent.EventName.reverseGear, *extra_user_events, *informational_events)
|
|
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.pcmDisable, log.OnroadEvent.EventName.reverseGear, *extra_user_events)
|
|
for event in sm['onroadEvents']
|
|
)
|
|
):
|
|
return False
|
|
native = current_native(sm, cp, now_ns=now_ns, axis_session_id=feedback.session)
|
|
if (
|
|
native is None
|
|
or not native.pandaInventory
|
|
or not native.sourcePandaStatesMonoTime
|
|
or active and not native.requestedLateral
|
|
or withdrawing and (native.requestedLateral or native.observedMonoTime < stamp)
|
|
or native.lateralAllowed
|
|
or native.requestedLongitudinal
|
|
or native.longitudinalAllowed
|
|
or native.observedMonoTime < feedback.lateral_native_ns
|
|
or (native.pandaSerial, tuple(p.hardwareSerial for p in native.pandaInventory)) != feedback.lateral_inventory
|
|
or any(p.controlsAllowed for p in native.pandaInventory)
|
|
):
|
|
return False
|
|
# Same raw latest-Panda veto as configured transport; its BOOTTIME source
|
|
# stamp is not interpreted as a monotonic lease. Native v2 owns that lease.
|
|
pandas = sm['pandaStates']
|
|
if (
|
|
not sm.seen['pandaStates']
|
|
or not sm.valid['pandaStates']
|
|
or not sm.alive['pandaStates']
|
|
or int(sm.logMonoTime['pandaStates']) <= 0
|
|
or len(pandas) != len(cp.safetyConfigs)
|
|
):
|
|
return False
|
|
return all(
|
|
int(p.safetyModel.raw) == int(c.safetyModel.raw)
|
|
and p.safetyParam == c.safetyParam
|
|
and p.alternativeExperience == cp.alternativeExperience
|
|
and not p.controlsAllowed
|
|
and not p.safetyRxChecksInvalid
|
|
and not p.heartbeatLost
|
|
and not p.faults
|
|
for p, c in zip(pandas, cp.safetyConfigs, strict=True)
|
|
)
|
|
except (AttributeError, KeyError, IndexError, TypeError, ValueError, OverflowError):
|
|
return False
|