parked-controlsd: tester-present heartbeat; cruise-set keeps full stack; dashcam idle on park

Three independent changes for the parked-controlsd architecture.

controlsd_parked: send the Hyundai HDA2 tester-present heartbeat
("\x02\x3E\x80\x00\x00\x00\x00\x00") at 1 Hz to 0x730 on E-CAN while we're
the active controlsd variant. The full carcontroller normally sends this
to keep the ADAS ECU held in its disabled diagnostic session — when full
controlsd hands off to parked-controlsd, the heartbeat used to stop, the
ECU would time out (~5 s default-session timeout) and snap back to stock,
lighting up the LKAS / blind-spot warning icons on the cluster. Continuing
the heartbeat from the parked variant keeps the ECU disabled across the
swap. The panda safety filter only allows tester-present on 0x730 so this
is the only "graceful release" mechanism available to us.

thermald: cruise-set override on the parked check. If carState.cruiseState
.speed > 0 (engaged OR paused-with-speed-set), stay in not_parked even if
gear is in P. The user can shift to park at a stop, glance at the cluster
to verify cruise is still set, and roll forward without waiting for full
controlsd to spin up. PARKED_HYSTERESIS_S still applies for the
gear-in-park-no-cruise → parked transition.

dashcamd: close the trip immediately on gear shift to PARK (was: 10-min
idle timer before close). User wants the dashcam idle in park and a fresh
trip on every drive engagement; brief drive-thru / fuel-stop across-trip
continuity isn't valued.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-26 14:41:44 -05:00
parent ab9158bfb7
commit 74e7c9e627
3 changed files with 46 additions and 14 deletions
+10 -3
View File
@@ -263,11 +263,18 @@ def thermald_thread(end_event, hw_queue) -> None:
# during low-speed parking don't kick the heavy stack off. Going OUT of
# parked is instant so the full stack starts spinning up the moment the
# driver shifts to D/R/N.
#
# Cruise override: if cruise control has any speed set (engaged OR
# paused-with-speed-set), keep the full stack running even in park. This
# means the user can shift to park at a stop, glance at the cluster to
# verify cruise is still set, and roll forward without waiting for full
# controlsd to spin back up.
if sm.updated['carState']:
gear = sm['carState'].gearShifter
gear_is_park = gear == car.CarState.GearShifter.park
cs = sm['carState']
gear_is_park = cs.gearShifter == car.CarState.GearShifter.park
cruise_set = cs.cruiseState.speed > 0
now_mono = time.monotonic()
if gear_is_park:
if gear_is_park and not cruise_set:
if parked_since is None:
parked_since = now_mono
if (not is_parked) and (now_mono - parked_since) >= PARKED_HYSTERESIS_S: