UI Build

LKAS engage/disengage sound

It will now make the same sound as op engage/disengage

Wheel Control fix 2

build

Feature: Model Name on Developer Sidebar

Model Name port and correct DEVELOPER_SIDEBAR_METRICS slot numbering

Wheel Controls button fixes

Mode/Star buttons were not showing on desk
LKAS option was showing even when car was using it for AOL, not it hides it if being used for AOL

MapGears Sync Accel/Decel on UI

MapGears will sync with "Longitudinal Tuning" UI to show chosen accel/decel profile to match with chosen drive mode.

Drive mode -> accel/decel profile mapping.
Eco → Eco
Normal → Standard
Sport → Sport+/Sport

Writes on gear state change, gated on MapAcceleration/MapDeceleration toggles independently

ECU Disable and Auto long/exp check

ECU Disable and Auto long/exp check

compile

Star and Mode buttons to wheel control options

cereal/custom.capnp — Added modePressed @16 and customPressed @17 fields to StarPilotCarState

opendbc_repo/opendbc/car/hyundai/carstate.py — Added STEERING_WHEEL_MEDIA_BUTTONS (50Hz) to the CANFD CAN parser, initialized mode_button/custom_button state, and set fp_ret.modePressed/fp_ret.customPressed in update_canfd()

common/params_keys.h — Added 6 new params: ModeButtonControl, LongModeButtonControl, VeryLongModeButtonControl, StarButtonControl, LongStarButtonControl, VeryLongStarButtonControl

starpilot/common/starpilot_variables.py — Added full short/long/very-long toggle processing for both Mode and Star buttons (gated on HyundaiFlags.CANFD), with has_canfd_media_buttons flag propagated to toggles

starpilot/controls/starpilot_card.py — Added Mode and Star button press counters and short/long/very-long press event handling, mirroring the existing distance button logic

selfdrive/ui/layouts/settings/starpilot/wheel.py — Added 6 new tiles for Mode/Star buttons (short, long, very long each), visible only when cs.isHKGCanFd is true

MapGears for HKG

Add HKG "Drive Modes" button ability to map to eco/normal/sport accel profiles.

Dashboard speed limit reading for CANFD

Add FR_CMR_02_100ms to CAN parsers in get_can_parsers_canfd: on ECAN (freq=10) for LKA_STEERING cars, on CAM (freq=0, optional) for all others
calculate_canfd_speed_limit and fp_ret.dashboardSpeedLimit assignment were already present
CAM bus uses freq=0 to avoid breaking canValid on non-LKA cars that don't have this message

CANFD steering limits

Raises STEER_MAX to 409
Speed-dependent deltas (DELTA_UP=10/DOWN=8 below 15 m/s, UP=2/DOWN=3 above),
Update panda safety ceiling and tests to match.
Removes TacoTuneHacks toggle dependency.

Ioniq 6 toml values update Updated toml values closer to learned values

DBC Update HKG Signals

Added 5 new messages to hyundai_canfd.dbc and hyundai_canfd_generated.dbc:

DRIVE_MODE_EV (0x205):
EV drive mode state with Normal/Eco/Sport (button) values. Can be used to change
acceleration profiles in openpilot based on drive mode.

CAM_0x361 (0x361):
Camera sign recognition with SIGN_TYPE and SIGN_TYPE_2 signals.
Dashboard Speed Limit. Can be used as source for SLC.

ADAS_0x380 (0x380):
ADAS stop sign detection bit. Dashboard stop sign alert.
Triggers 80-90ft before stop sign typically and can be used to help stopping for stop signs.

DOOR_LOCK (0x414):
Not actual command to lock/unlock, but may be used to detect lock state changes.

STEERING_WHEEL_MEDIA_BUTTONS (0x448):
Steering wheel button inputs (voice, phone, mode, next/prev, menu, scroll, custom)
Can be used to assign custom functions to steering wheel buttons in openpilot.

Targets Ioniq 6 but may apply to other Hyundai CAN FD vehicles.
This commit is contained in:
whoisdomi
2026-04-20 15:09:46 -05:00
committed by firestar5683
parent dff758f71b
commit 39afadb95f
30 changed files with 548 additions and 62 deletions
+2
View File
@@ -8,6 +8,8 @@
**StarPilot** is a custom fork of [comma.ai's openpilot](https://comma.ai/openpilot),
an open source driver assistance system.
whoisdomi
Openpilot provides
* Automated Lane Centering
* Adaptive Cruise Control
+5
View File
@@ -82,6 +82,9 @@ struct StarPilotCarState @0xf35cc4560bbf6ec2 {
sportGear @13 :Bool;
trafficModeEnabled @14 :Bool;
gasStack @15 :Bool; # Compatibility with older StarPilot payloads
modePressed @16 :Bool;
customPressed @17 :Bool;
alwaysOnLateralAllowed @18 :Bool;
}
struct StarPilotDeviceState @0xda96579883444c35 {
@@ -147,6 +150,8 @@ struct StarPilotOnroadEvent @0xa5cd762cd951a455 {
youveGotMail @28;
switchbackModeActive @29;
switchbackModeInactive @30;
lkasEnable @31;
lkasDisable @32;
}
}
+7
View File
@@ -38,6 +38,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"DoShutdown", {CLEAR_ON_MANAGER_START, BOOL}},
{"DoUninstall", {CLEAR_ON_MANAGER_START, BOOL}},
{"DriverTooDistracted", {CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON, BOOL}},
{"EcuDisableFailed", {CLEAR_ON_MANAGER_START, BOOL}},
{"AlphaLongitudinalEnabled", {PERSISTENT, BOOL}},
{"ExperimentalLongitudinalEnabled", {PERSISTENT, BOOL}},
{"ExperimentalMode", {PERSISTENT, BOOL}},
@@ -329,6 +330,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"LockDoors", {PERSISTENT, BOOL, "1", "0", 0}},
{"LockDoorsTimer", {PERSISTENT, INT, "0", "0", 0}},
{"LongDistanceButtonControl", {PERSISTENT, INT, "5", "0", 2}},
{"LongModeButtonControl", {PERSISTENT, INT, "0", "0", 2}},
{"LongStarButtonControl", {PERSISTENT, INT, "0", "0", 2}},
{"LongitudinalActuatorDelay", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"LongitudinalActuatorDelayStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"LateralManeuverStatus", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON, "{}", "{}"}},
@@ -358,6 +361,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"MaxDesiredAcceleration", {PERSISTENT, FLOAT, "4.0", "2.0", 2}},
{"MinimumBackupSize", {PERSISTENT, INT, "0", "0"}},
{"MinimumLaneChangeSpeed", {PERSISTENT, FLOAT, "20.0", "20.0", 2}},
{"ModeButtonControl", {PERSISTENT, INT, "0", "0", 2}},
{"ModelDownloadProgress", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"ModelDrivesAndScores", {PERSISTENT, JSON, "{}", "{}"}},
{"ModelReleasedDates", {PERSISTENT, STRING, "", "", 1}},
@@ -517,6 +521,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"StopDistance", {PERSISTENT, FLOAT, "6.0", "6.0", 2}},
{"StoppingDecelRate", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"StoppingDecelRateStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"StarButtonControl", {PERSISTENT, INT, "0", "0", 2}},
{"SwitchbackModeCooldown", {PERSISTENT, INT, "5", "0", 2}},
{"SwitchbackModeEnabled", {CLEAR_ON_OFFROAD_TRANSITION, BOOL, "0", "0"}},
{"SubaruSNG", {PERSISTENT, BOOL, "1", "0", 2}},
@@ -555,6 +560,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"VEgoStopping", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"VEgoStoppingStock", {PERSISTENT, FLOAT, "0.0", "0.0", 3}},
{"VeryLongDistanceButtonControl", {PERSISTENT, INT, "6", "0", 2}},
{"VeryLongModeButtonControl", {PERSISTENT, INT, "0", "0", 2}},
{"VeryLongStarButtonControl", {PERSISTENT, INT, "0", "0", 2}},
{"VoltSNG", {PERSISTENT, BOOL, "0", "0", 2}},
{"WarningImmediateVolume", {PERSISTENT, INT, "101", "101", 2}},
{"WarningSoftVolume", {PERSISTENT, INT, "101", "101", 2}},
+65 -11
View File
@@ -1,10 +1,24 @@
import time
import datetime
from opendbc.car.carlog import carlog
from opendbc.car.isotp_parallel_query import IsoTpParallelQuery
EXT_DIAG_REQUEST = b'\x10\x03'
EXT_DIAG_RESPONSE = b'\x50\x03'
COM_CONT_RESPONSE = b''
# File-based logging for debugging
ECU_LOG_FILE = "/data/ecu_disable.log"
def ecu_log(msg):
"""Write to both carlog and a dedicated log file for debugging."""
timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
log_line = f"[{timestamp}] {msg}"
carlog.warning(msg)
try:
with open(ECU_LOG_FILE, "a") as f:
f.write(log_line + "\n")
except Exception:
pass
def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_req=b'\x28\x83\x01', timeout=0.1, retry=10):
@@ -13,24 +27,64 @@ def disable_ecu(can_recv, can_send, bus=0, addr=0x7d0, sub_addr=None, com_cont_r
This is used to disable the radar in some cars. Openpilot will emulate the radar.
WARNING: THIS DISABLES AEB!"""
carlog.warning(f"ecu disable {hex(addr), sub_addr} ...")
ecu_log(f"=== ECU DISABLE START === addr={hex(addr)}, bus={bus}")
# Try multiple times with different approaches
for i in range(retry):
try:
# Enter extended diagnostic session
ecu_log(f"attempt {i+1}/{retry}: diag session...")
query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [EXT_DIAG_REQUEST], [EXT_DIAG_RESPONSE])
for _, _ in query.get_data(timeout).items():
carlog.warning("communication control disable tx/rx ...")
ecu_log("diag session OK")
query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [com_cont_req], [COM_CONT_RESPONSE])
query.get_data(0)
# Small delay to let ECU fully enter diagnostic mode
time.sleep(0.05)
carlog.warning("ecu disabled")
return True
# Send CC command and log the response
ecu_log("sending CC...")
cc_query = IsoTpParallelQuery(can_send, can_recv, bus, [(addr, sub_addr)], [com_cont_req], [b''])
cc_response = cc_query.get_data(timeout)
except Exception:
carlog.exception("ecu disable exception")
# Log what we got back
cc_success = False
cc_rejected = False
for (rx_addr, _), data in cc_response.items():
ecu_log(f"CC response: {data.hex() if data else 'empty'}")
# Check for positive response (0x68 = 0x28 + 0x40)
if len(data) >= 1 and data[0] == 0x68:
ecu_log("=== ECU DISABLE CONFIRMED ===")
cc_success = True
# Check for negative response
elif len(data) >= 3 and data[0] == 0x7F:
nrc = data[2]
nrc_meanings = {
0x12: "subFunctionNotSupported",
0x13: "incorrectMessageLengthOrInvalidFormat",
0x22: "conditionsNotCorrect (car must be in IGN-ON, not READY)",
0x31: "requestOutOfRange",
0x33: "securityAccessDenied",
}
nrc_name = nrc_meanings.get(nrc, "unknown")
ecu_log(f"CC rejected: NRC 0x{nrc:02x} = {nrc_name}")
cc_rejected = True
carlog.error(f"ecu disable retry ({i + 1}) ...")
carlog.error("ecu disable failed")
if cc_success:
return True
elif cc_rejected:
# ECU explicitly rejected - don't retry, it won't work
ecu_log("=== ECU DISABLE REJECTED ===")
return False
else:
# No response - consider it sent (ECU might have stopped responding)
ecu_log("=== ECU DISABLE SENT (no response) ===")
return True
except Exception as e:
ecu_log(f"attempt {i+1} exception: {e}")
time.sleep(0.1)
ecu_log("=== ECU DISABLE FAILED ===")
return False
@@ -8,6 +8,7 @@ from opendbc.car.hyundai.hyundaicanfd import CanBus
from opendbc.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CAR
from opendbc.car.interfaces import CarControllerBase
from opendbc.car.vehicle_model import VehicleModel
from openpilot.common.params import Params
VisualAlert = structs.CarControl.HUDControl.VisualAlert
LongCtrlState = structs.CarControl.Actuators.LongControlState
@@ -57,11 +58,16 @@ class CarController(CarControllerBase):
self.apply_angle_last = 0.0
self.car_fingerprint = CP.carFingerprint
self.last_button_frame = 0
self.ecu_disable_failed = False
self._ecu_disable_checked = False
self._params = Params()
self.long_active_ecu = self.CP.openpilotLongitudinalControl
def update(self, CC, CS, now_nanos, starpilot_toggles):
actuators = CC.actuators
hud_control = CC.hudControl
self.params = CarControllerParams(self.CP, CS.out.vEgoRaw)
apply_angle = CS.out.steeringAngleDeg
if self.CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
@@ -107,10 +113,19 @@ class CarController(CarControllerBase):
can_sends = []
# Check EcuDisableFailed once after init() has run
if not self._ecu_disable_checked and self.frame > 0:
self.ecu_disable_failed = self._params.get_bool("EcuDisableFailed")
self._ecu_disable_checked = True
# When ECU disable was skipped (car started in READY mode), don't send any
# longitudinal messages - stock ECU is still active and these would conflict
self.long_active_ecu = self.CP.openpilotLongitudinalControl and not self.ecu_disable_failed
# *** common hyundai stuff ***
# tester present - w/ no response (keeps relevant ECU disabled)
if self.frame % 100 == 0 and not (self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC) and self.CP.openpilotLongitudinalControl:
if self.frame % 100 == 0 and not (self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC) and self.long_active_ecu:
# for longitudinal control, either radar or ADAS driving ECU
addr, bus = 0x7d0, self.CAN.ECAN if self.CP.flags & HyundaiFlags.CANFD else 0
if self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING.value:
@@ -155,7 +170,7 @@ class CarController(CarControllerBase):
left_lane_warning, right_lane_warning))
# Button messages
if not self.CP.openpilotLongitudinalControl:
if not self.long_active_ecu:
if CC.cruiseControl.cancel:
can_sends.append(hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.CANCEL, self.CP))
elif CC.cruiseControl.resume:
@@ -166,7 +181,7 @@ class CarController(CarControllerBase):
if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15:
self.last_button_frame = self.frame
if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl:
if self.frame % 2 == 0 and self.long_active_ecu:
# TODO: unclear if this is needed
jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
@@ -179,11 +194,11 @@ class CarController(CarControllerBase):
can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled))
# 5 Hz ACC options
if self.frame % 20 == 0 and self.CP.openpilotLongitudinalControl:
if self.frame % 20 == 0 and self.long_active_ecu:
can_sends.extend(hyundaican.create_acc_opt(self.packer, self.CP))
# 2 Hz front radar options
if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl:
if self.frame % 50 == 0 and self.long_active_ecu:
can_sends.append(hyundaican.create_frt_radar_opt(self.packer))
return can_sends
@@ -192,7 +207,7 @@ class CarController(CarControllerBase):
can_sends = []
lka_steering = self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING
lka_steering_long = lka_steering and self.CP.openpilotLongitudinalControl
lka_steering_long = lka_steering and self.long_active_ecu
# steering control
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled,
@@ -211,7 +226,7 @@ class CarController(CarControllerBase):
if lka_steering and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.CAN, CC.leftBlinker, CC.rightBlinker))
if self.CP.openpilotLongitudinalControl:
if self.long_active_ecu:
if lka_steering:
can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame))
else:
+22 -2
View File
@@ -42,6 +42,8 @@ class CarState(CarStateBase):
self.cruise_buttons: deque = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
self.main_buttons: deque = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
self.lda_button = 0
self.mode_button = 0
self.custom_button = 0
self.gear_msg_canfd = "ACCELERATOR" if CP.flags & HyundaiFlags.EV else \
"GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else \
@@ -287,7 +289,7 @@ class CarState(CarStateBase):
# cruise state
# CAN FD cars enable on main button press, set available if no TCS faults preventing engagement
ret.cruiseState.available = cp.vl["TCS"]["ACCEnable"] == 0
if self.CP.openpilotLongitudinalControl:
if self.CP.openpilotLongitudinalControl and not self.CP.pcmCruise:
# These are not used for engage/disengage since openpilot keeps track of state using the buttons
ret.cruiseState.enabled = cp.vl["TCS"]["ACC_REQ"] == 1
ret.cruiseState.standstill = False
@@ -328,19 +330,37 @@ class CarState(CarStateBase):
fp_ret = custom.StarPilotCarState.new_message()
fp_ret.dashboardSpeedLimit = calculate_canfd_speed_limit(self.CP, self.FPCP, cp, cp_cam, speed_factor)
if self.CP.flags & HyundaiFlags.EV:
drive_mode = cp.vl["DRIVE_MODE_EV"]["DRIVE_MODE"]
fp_ret.ecoGear = (drive_mode == 4)
fp_ret.sportGear = (drive_mode == 5)
self.mode_button = cp.vl["STEERING_WHEEL_MEDIA_BUTTONS"]["MODE_BUTTON"]
self.custom_button = cp.vl["STEERING_WHEEL_MEDIA_BUTTONS"]["CUSTOM_BUTTON"]
fp_ret.modePressed = bool(self.mode_button)
fp_ret.customPressed = bool(self.custom_button)
return ret, fp_ret
def get_can_parsers_canfd(self, CP):
msgs = []
cam_msgs = []
if not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS):
# TODO: this can be removed once we add dynamic support to vl_all
msgs += [
# this message is 50Hz but the ECU frequently stops transmitting for ~0.5s
("CRUISE_BUTTONS", 1)
]
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
msgs.append(("FR_CMR_02_100ms", 10))
else:
cam_msgs.append(("FR_CMR_02_100ms", 0)) # optional: not all non-LKA CANFD cars have this on CAM bus
if CP.flags & HyundaiFlags.EV:
msgs.append(("DRIVE_MODE_EV", 10))
msgs.append(("STEERING_WHEEL_MEDIA_BUTTONS", 50))
return {
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], msgs, CanBus(CP).ECAN),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).CAM),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], cam_msgs, CanBus(CP).CAM),
}
def get_can_parsers(self, CP):
+85 -9
View File
@@ -1,11 +1,13 @@
import time
from opendbc.car import Bus, get_safety_config, structs, uds
from opendbc.car.hyundai.hyundaicanfd import CanBus
from opendbc.car.hyundai.values import HyundaiFlags, CAR, DBC, \
CANFD_UNSUPPORTED_LONGITUDINAL_CAR, \
CANFD_SECURITYACCESS_CAR, \
UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags
from opendbc.car.hyundai.radar_interface import RADAR_START_ADDR
from opendbc.car.interfaces import CarInterfaceBase
from opendbc.car.disable_ecu import disable_ecu
from opendbc.car.disable_ecu import disable_ecu, ecu_log
from opendbc.car.hyundai.carcontroller import CarController
from opendbc.car.hyundai.carstate import CarState
from opendbc.car.hyundai.radar_interface import RadarInterface
@@ -16,6 +18,9 @@ Ecu = structs.CarParams.Ecu
# Cancel button can sometimes be ACC pause/resume button, main button can also enable on some cars
ENABLE_BUTTONS = (ButtonType.accelCruise, ButtonType.decelCruise, ButtonType.cancel, ButtonType.mainCruise)
# Track when ECU disable happened - used to permanently suppress CAN errors from disabled ECU
ECU_DISABLE_TIMESTAMP = 0.0
class CarInterface(CarInterfaceBase):
CarState = CarState
@@ -37,8 +42,9 @@ class CarInterface(CarInterfaceBase):
if ret.flags & HyundaiFlags.CANFD:
# Shared configuration for CAN-FD cars
ret.alphaLongitudinalAvailable = candidate not in CANFD_UNSUPPORTED_LONGITUDINAL_CAR
if lka_steering and Ecu.adas not in [fw.ecu for fw in car_fw]:
if lka_steering and Ecu.adas not in [fw.ecu for fw in car_fw] and candidate not in CANFD_SECURITYACCESS_CAR:
# this needs to be figured out for cars without an ADAS ECU
# Cars in CANFD_SECURITYACCESS_CAR are known to have ADAS ECUs that work with SecurityAccess
ret.alphaLongitudinalAvailable = False
ret.enableBsm = 0x1ba in fingerprint[CAN.ECAN]
@@ -59,10 +65,6 @@ class CarInterface(CarInterfaceBase):
if not ret.flags & HyundaiFlags.RADAR_SCC:
ret.flags |= HyundaiFlags.CANFD_CAMERA_SCC.value
# Ioniq 6 HDA2 uses the camera SCC path for stock ACC, even on LKA steering variants.
if candidate == CAR.HYUNDAI_IONIQ_6:
ret.flags |= HyundaiFlags.CANFD_CAMERA_SCC.value
# Some LKA steering cars have alternative messages for gear checks
# ICE cars do not have 0x130; GEARS message on 0x40 or 0x70 instead
if 0x130 not in fingerprint[CAN.ECAN]:
@@ -143,6 +145,10 @@ class CarInterface(CarInterfaceBase):
if ret.flags & HyundaiFlags.NON_SCC:
ret.alphaLongitudinalAvailable = False
ret.openpilotLongitudinalControl = alpha_long and ret.alphaLongitudinalAvailable
# When longitudinal is enabled, we disable the ADAS ECU which stops radar messages
# Force radarUnavailable to prevent CAN Error from missing radar messages
if ret.openpilotLongitudinalControl:
ret.radarUnavailable = True
ret.pcmCruise = not ret.openpilotLongitudinalControl
ret.startingState = True
ret.vEgoStarting = 0.1
@@ -172,15 +178,50 @@ class CarInterface(CarInterfaceBase):
@staticmethod
def init(CP, can_recv, can_send, communication_control=None):
# 0x80 silences response
global ECU_DISABLE_TIMESTAMP
from openpilot.common.params import Params
params = Params()
if communication_control is None:
communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, 0x80 | uds.CONTROL_TYPE.DISABLE_RX_DISABLE_TX, uds.MESSAGE_TYPE.NORMAL])
if CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
# Don't use 0x80 suppress bit so we can read the ECU response.
# Use ENABLE_RX_DISABLE_TX (0x01) so the ECU can still receive from rear radars for BSM
# while blocking SCC TX.
communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, uds.CONTROL_TYPE.ENABLE_RX_DISABLE_TX, uds.MESSAGE_TYPE.NORMAL])
else:
# 0x80 silences response for other cars (original behavior)
communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, 0x80 | uds.CONTROL_TYPE.DISABLE_RX_DISABLE_TX, uds.MESSAGE_TYPE.NORMAL])
ecu_log(f"=== init() called: opLong={CP.openpilotLongitudinalControl}, flags=0x{CP.flags:x}, safetyParam={CP.safetyConfigs[-1].safetyParam} ===")
if CP.openpilotLongitudinalControl and not (CP.flags & (HyundaiFlags.CANFD_CAMERA_SCC | HyundaiFlags.CAMERA_SCC)):
addr, bus = 0x7d0, CanBus(CP).ECAN if CP.flags & HyundaiFlags.CANFD else 0
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING.value:
addr, bus = 0x730, CanBus(CP).ECAN
disable_ecu(can_recv, can_send, bus=bus, addr=addr, com_cont_req=communication_control)
# Try ECU disable. If it succeeds (IGN-ON mode), enable longitudinal.
# If it fails (READY mode returns NRC 0x22, or timeout), strip LONG safety flag
# so panda forwards stock SCC messages normally (lateral-only mode).
ecu_log(f"=== ECU DISABLE attempt: addr=0x{addr:x}, bus={bus} ===")
ecu_disabled = disable_ecu(can_recv, can_send, bus=bus, addr=addr, com_cont_req=communication_control)
if CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
# Ioniq 6: track success/failure to auto-switch between openpilot long and stock ACC
if ecu_disabled:
ECU_DISABLE_TIMESTAMP = time.monotonic()
params.put_bool("EcuDisableFailed", False)
params.put_bool("ExperimentalMode", True)
ecu_log("=== ECU DISABLE SUCCESS - Longitudinal + Experimental ENABLED ===")
else:
params.put_bool("EcuDisableFailed", True)
CP.safetyConfigs[-1].safetyParam &= ~HyundaiSafetyFlags.LONG.value
ecu_log(f"=== ECU DISABLE FAILED - safetyParam stripped to {CP.safetyConfigs[-1].safetyParam}, lateral-only mode ===")
else:
# Other cars: just log, don't change safety params or params store
if ecu_disabled:
ecu_log("=== ECU DISABLE SUCCESS ===")
else:
ecu_log("=== ECU DISABLE FAILED ===")
# for blinkers
if CP.flags & HyundaiFlags.ENABLE_BLINKERS:
@@ -190,3 +231,38 @@ class CarInterface(CarInterfaceBase):
def deinit(CP, can_recv, can_send):
communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, 0x80 | uds.CONTROL_TYPE.ENABLE_RX_ENABLE_TX, uds.MESSAGE_TYPE.NORMAL])
CarInterface.init(CP, can_recv, can_send, communication_control)
def update(self, can_packets, starpilot_toggles):
ret, fp_ret = super().update(can_packets, starpilot_toggles)
# When ECU disable was skipped (READY mode boot) or failed, suppress CAN timeout errors.
# Keep checking param until it's True (init() sets it AFTER first update() call),
# then cache to avoid per-frame param reads.
if not getattr(self, '_ecu_disable_failed_cached', False):
from openpilot.common.params import Params
self._ecu_disable_failed_cached = Params().get_bool("EcuDisableFailed")
if self._ecu_disable_failed_cached and not ret.canValid:
ret.canValid = True
global ECU_DISABLE_TIMESTAMP
if ECU_DISABLE_TIMESTAMP > 0 and not ret.canValid:
# Check if any parser has counter/checksum errors (real CAN issues)
has_counter_errors = False
for cp in self.can_parsers.values():
if cp is not None:
for state in cp.message_states.values():
if state.counter_fail >= 5: # MAX_BAD_COUNTER from parser.py
has_counter_errors = True
ecu_log(f"REAL CAN ERROR: {state.name} counter_fail={state.counter_fail}")
break
if has_counter_errors:
break
if has_counter_errors:
# Real CAN error - don't suppress, let it through
ecu_log("ECU_DISABLE: NOT suppressing canValid - counter errors detected")
else:
# Only timeout errors (expected after ECU disable) - suppress silently
ret.canValid = True
return ret, fp_ret
+14 -8
View File
@@ -28,7 +28,7 @@ class CarControllerParams:
ANGLE_MIN_TORQUE_REDUCTION_GAIN = 0.1
ANGLE_ACTIVE_TORQUE_REDUCTION_GAIN = 0.6
def __init__(self, CP):
def __init__(self, CP, vEgoRaw=100.):
self.STEER_DELTA_UP = 3
self.STEER_DELTA_DOWN = 7
self.STEER_DRIVER_ALLOWANCE = 50
@@ -38,12 +38,16 @@ class CarControllerParams:
self.STEER_STEP = 1 # 100 Hz
if CP.flags & HyundaiFlags.CANFD:
self.STEER_MAX = 270
self.STEER_DRIVER_ALLOWANCE = 250
self.STEER_MAX = 409
self.STEER_DRIVER_ALLOWANCE = 100
self.STEER_DRIVER_MULTIPLIER = 2
self.STEER_THRESHOLD = 250
self.STEER_DELTA_UP = 2
self.STEER_DELTA_DOWN = 3
self.STEER_THRESHOLD = 100
if vEgoRaw < 15.0: # below ~34 mph - more aggressive for tight turns
self.STEER_DELTA_UP = 10
self.STEER_DELTA_DOWN = 8
else:
self.STEER_DELTA_UP = 2
self.STEER_DELTA_DOWN = 3
if CP.flags & HyundaiFlags.CANFD_ANGLE_STEERING:
self.STEER_THRESHOLD = 175
@@ -377,7 +381,7 @@ class CAR(Platforms):
HYUNDAI_IONIQ_6 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Ioniq 6 (with HDA II) 2023-24", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))],
HYUNDAI_IONIQ_5.specs,
flags=HyundaiFlags.EV,
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_LKA_STEERING | HyundaiFlags.CANFD_LKA_STEERING_ALT | HyundaiFlags.CANFD_NO_RADAR_DISABLE,
)
HYUNDAI_TUCSON_4TH_GEN = HyundaiCanFDPlatformConfig(
[
@@ -817,7 +821,9 @@ CAN_GEARS = {
CANFD_CAR = CAR.with_flags(HyundaiFlags.CANFD)
CANFD_RADAR_SCC_CAR = CAR.with_flags(HyundaiFlags.RADAR_SCC) # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
CANFD_UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.CANFD_NO_RADAR_DISABLE) # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
# Cars with CANFD_NO_RADAR_DISABLE that now work with SecurityAccess handshake
CANFD_SECURITYACCESS_CAR = {CAR.HYUNDAI_IONIQ_6, CAR.HYUNDAI_KONA_EV_2ND_GEN}
CANFD_UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.CANFD_NO_RADAR_DISABLE) - CANFD_SECURITYACCESS_CAR # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
CAMERA_SCC_CAR = CAR.with_flags(HyundaiFlags.CAMERA_SCC)
@@ -78,7 +78,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"GMC_ACADIA" = [1.6, 1.6, 0.2]
"LEXUS_IS_TSS2" = [2.0, 2.0, 0.1]
"HYUNDAI_KONA_EV_2ND_GEN" = [2.5, 2.5, 0.1]
"HYUNDAI_IONIQ_6" = [2.5, 2.5, 0.005]
"HYUNDAI_IONIQ_6" = [3.0, 3.0, 0.09]
"HYUNDAI_AZERA_6TH_GEN" = [1.8, 1.8, 0.1]
"HYUNDAI_AZERA_HEV_6TH_GEN" = [1.8, 1.8, 0.1]
"KIA_K8_HEV_1ST_GEN" = [2.5, 2.5, 0.1]
@@ -514,6 +514,11 @@ BO_ 512 ADRV_0x200: 8 ADRV
SG_ SET_ME_E1 : 24|8@1+ (1,0) [0|255] "" XXX
SG_ SET_ME_3A : 32|8@1+ (1,0) [0|255] "" XXX
BO_ 517 DRIVE_MODE_EV: 8 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ DRIVE_MODE : 24|8@1+ (1,0) [0|255] "" XXX
BO_ 593 RADAR_0x251: 16 FRONT_RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
@@ -574,6 +579,10 @@ BO_ 837 ADRV_0x345: 8 ADRV
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ SET_ME_15 : 24|8@1+ (1,0) [0|255] "" XXX
BO_ 865 CAM_0x361: 32 CAMERA
SG_ SIGN_TYPE : 208|8@1+ (1,0) [0|255] "" XXX
SG_ SIGN_TYPE_2 : 240|8@1+ (1,0) [0|255] "" XXX
BO_ 866 CAM_0x362: 32 CAMERA
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
@@ -614,6 +623,9 @@ BO_ 874 BLINDSPOTS_FRONT_CORNER_2: 16 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
BO_ 896 ADAS_0x380: 24 XXX
SG_ STOP_SIGN : 83|1@1+ (1,0) [0|1] "" XXX
BO_ 961 BLINKER_STALKS: 8 XXX
SG_ CHECKSUM_MAYBE : 7|8@0+ (1,0) [0|255] "" XXX
SG_ COUNTER_ALT : 15|4@0+ (1,0) [0|15] "" XXX
@@ -643,6 +655,23 @@ BO_ 1043 BLINKERS: 8 XXX
SG_ RIGHT_LAMP_ALT : 61|1@0+ (1,0) [0|1] "" XXX
SG_ USE_ALT_LAMP : 62|1@0+ (1,0) [0|1] "" XXX
BO_ 1044 DOOR_LOCK: 8 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ DOOR_LOCK_STATE : 37|1@0+ (1,0) [0|1] "" XXX
SG_ DOOR_LOCK_ACTION : 40|1@1+ (1,0) [0|1] "" XXX
BO_ 1096 STEERING_WHEEL_MEDIA_BUTTONS: 8 XXX
SG_ VOICE_BUTTON : 16|1@0+ (1,0) [0|1] "" XXX
SG_ PHONE_BUTTON : 18|1@0+ (1,0) [0|1] "" XXX
SG_ MODE_BUTTON : 22|1@0+ (1,0) [0|1] "" XXX
SG_ RIGHT_SCROLL_PRESS : 24|1@0+ (1,0) [0|1] "" XXX
SG_ NEXT_BUTTON : 26|1@0+ (1,0) [0|1] "" XXX
SG_ PREVIOUS_BUTTON : 28|1@0+ (1,0) [0|1] "" XXX
SG_ MENU_BUTTON : 34|1@0+ (1,0) [0|1] "" XXX
SG_ LEFT_SCROLL_PRESS : 38|1@0+ (1,0) [0|1] "" XXX
SG_ CUSTOM_BUTTON : 44|1@0+ (1,0) [0|1] "" XXX
BO_ 1144 DRIVE_MODE: 8 XXX
SG_ DRIVE_MODE : 0|16@1+ (1,-61611) [0|61611] "" XXX
SG_ DRIVE_MODE2 : 28|3@1+ (1,0) [1|3] "" XXX
@@ -940,6 +969,7 @@ VAL_ 506 ISLA_AutoUsmSta 0 "None Auto Function (Delete Menu)" 1 "Auto Off" 2 "Au
VAL_ 506 ISLA_Cntry 0 "Europe/Russia/Australia" 1 "Domestic" 2 "China" 3 "USA" 4 "Canada" 5 "Australia" 6 "Reserved" 7 "Reserved" 8 "Reserved" 9 "Reserved" 10 "Reserved" 11 "Reserved" 12 "Reserved" 13 "Reserved" 14 "Reserved" 15 "Initial Value (default)";
VAL_ 506 ISLA_AddtnlSign 0 "No Recognition (default)" 1 "School Crossing" 16 "Do Not Pass" 17 "Reserved" 18 "Reserved" 19 "Reserved" 20 "Reserved" 21 "Reserved" 22 "Reserved" 23 "Reserved" 24 "Exit" 25 "Roundabout" 26 "Right Curve" 27 "Left Curve" 28 "Winding Road" 29 "Reserved" 30 "Reserved" 31 "Reserved" 2 "Pedestrian Crossing" 3 "Bicycle Crossing" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Reserved" 8 "Stop" 9 "Yield" 10 "Stop Ahead" 11 "Yield Ahead" 12 "Road Construction Ahead" 13 "Lane Reduction" 14 "Reserved" 15 "Reserved";
VAL_ 506 ISLA_SchoolZone 0 "No School Zone" 1 "School Zone" 2 "Reserved" 3 "Reserved";
VAL_ 517 DRIVE_MODE 2 "Normal" 4 "Eco" 5 "Sport";
VAL_ 687 HOD_Dir_Status 0 "HANDS OFF" 1 "HAND TOUCH (SOFT)" 2 "HAND TOUCH (STRONG)" 3 "HAND GRIP (SOFT)" 4 "HAND GRIP (STRONG)" 5 "RESERVED" 6 "RESERVED";
VAL_ 698 IFSref_FR_CMR_Sta 0 "None Option (Default)" 1 "Normal" 2 "Blockage Status" 3 "Error Indicator";
VAL_ 698 IFSref_VehNumVal 0 "No vehicle" 1 "Number of vehicles" 2 "Number of vehicles" 3 "Number of vehicles" 4 "Number of vehicles" 5 "Number of vehicles" 6 "Number of vehicles" 7 "Number of vehicles" 8 "Number of vehicles" 9 "Number of vehicles" 10 "Number of vehicles" 11 "Over than 10 vehicles" 12 "Reserved" 13 "Reserved" 14 "Default" 15 "Error indicator";
@@ -751,6 +751,11 @@ BO_ 512 ADRV_0x200: 8 ADRV
SG_ SET_ME_E1 : 24|8@1+ (1,0) [0|255] "" XXX
SG_ SET_ME_3A : 32|8@1+ (1,0) [0|255] "" XXX
BO_ 517 DRIVE_MODE_EV: 8 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ DRIVE_MODE : 24|8@1+ (1,0) [0|255] "" XXX
BO_ 593 RADAR_0x251: 16 FRONT_RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
@@ -811,6 +816,10 @@ BO_ 837 ADRV_0x345: 8 ADRV
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ SET_ME_15 : 24|8@1+ (1,0) [0|255] "" XXX
BO_ 865 CAM_0x361: 32 CAMERA
SG_ SIGN_TYPE : 208|8@1+ (1,0) [0|255] "" XXX
SG_ SIGN_TYPE_2 : 240|8@1+ (1,0) [0|255] "" XXX
BO_ 866 CAM_0x362: 32 CAMERA
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
@@ -851,6 +860,9 @@ BO_ 874 BLINDSPOTS_FRONT_CORNER_2: 16 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
BO_ 896 ADAS_0x380: 24 XXX
SG_ STOP_SIGN : 83|1@1+ (1,0) [0|1] "" XXX
BO_ 961 BLINKER_STALKS: 8 XXX
SG_ CHECKSUM_MAYBE : 7|8@0+ (1,0) [0|255] "" XXX
SG_ COUNTER_ALT : 15|4@0+ (1,0) [0|15] "" XXX
@@ -880,6 +892,23 @@ BO_ 1043 BLINKERS: 8 XXX
SG_ RIGHT_LAMP_ALT : 61|1@0+ (1,0) [0|1] "" XXX
SG_ USE_ALT_LAMP : 62|1@0+ (1,0) [0|1] "" XXX
BO_ 1044 DOOR_LOCK: 8 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ DOOR_LOCK_STATE : 37|1@0+ (1,0) [0|1] "" XXX
SG_ DOOR_LOCK_ACTION : 40|1@1+ (1,0) [0|1] "" XXX
BO_ 1096 STEERING_WHEEL_MEDIA_BUTTONS: 8 XXX
SG_ VOICE_BUTTON : 16|1@0+ (1,0) [0|1] "" XXX
SG_ PHONE_BUTTON : 18|1@0+ (1,0) [0|1] "" XXX
SG_ MODE_BUTTON : 22|1@0+ (1,0) [0|1] "" XXX
SG_ RIGHT_SCROLL_PRESS : 24|1@0+ (1,0) [0|1] "" XXX
SG_ NEXT_BUTTON : 26|1@0+ (1,0) [0|1] "" XXX
SG_ PREVIOUS_BUTTON : 28|1@0+ (1,0) [0|1] "" XXX
SG_ MENU_BUTTON : 34|1@0+ (1,0) [0|1] "" XXX
SG_ LEFT_SCROLL_PRESS : 38|1@0+ (1,0) [0|1] "" XXX
SG_ CUSTOM_BUTTON : 44|1@0+ (1,0) [0|1] "" XXX
BO_ 1144 DRIVE_MODE: 8 XXX
SG_ DRIVE_MODE : 0|16@1+ (1,-61611) [0|61611] "" XXX
SG_ DRIVE_MODE2 : 28|3@1+ (1,0) [1|3] "" XXX
@@ -1177,6 +1206,7 @@ VAL_ 506 ISLA_AutoUsmSta 0 "None Auto Function (Delete Menu)" 1 "Auto Off" 2 "Au
VAL_ 506 ISLA_Cntry 0 "Europe/Russia/Australia" 1 "Domestic" 2 "China" 3 "USA" 4 "Canada" 5 "Australia" 6 "Reserved" 7 "Reserved" 8 "Reserved" 9 "Reserved" 10 "Reserved" 11 "Reserved" 12 "Reserved" 13 "Reserved" 14 "Reserved" 15 "Initial Value (default)";
VAL_ 506 ISLA_AddtnlSign 0 "No Recognition (default)" 1 "School Crossing" 16 "Do Not Pass" 17 "Reserved" 18 "Reserved" 19 "Reserved" 20 "Reserved" 21 "Reserved" 22 "Reserved" 23 "Reserved" 24 "Exit" 25 "Roundabout" 26 "Right Curve" 27 "Left Curve" 28 "Winding Road" 29 "Reserved" 30 "Reserved" 31 "Reserved" 2 "Pedestrian Crossing" 3 "Bicycle Crossing" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Reserved" 8 "Stop" 9 "Yield" 10 "Stop Ahead" 11 "Yield Ahead" 12 "Road Construction Ahead" 13 "Lane Reduction" 14 "Reserved" 15 "Reserved";
VAL_ 506 ISLA_SchoolZone 0 "No School Zone" 1 "School Zone" 2 "Reserved" 3 "Reserved";
VAL_ 517 DRIVE_MODE 2 "Normal" 4 "Eco" 5 "Sport";
VAL_ 687 HOD_Dir_Status 0 "HANDS OFF" 1 "HAND TOUCH (SOFT)" 2 "HAND TOUCH (STRONG)" 3 "HAND GRIP (SOFT)" 4 "HAND GRIP (STRONG)" 5 "RESERVED" 6 "RESERVED";
VAL_ 698 IFSref_FR_CMR_Sta 0 "None Option (Default)" 1 "Normal" 2 "Blockage Status" 3 "Error Indicator";
VAL_ 698 IFSref_VehNumVal 0 "No vehicle" 1 "Number of vehicles" 2 "Number of vehicles" 3 "Number of vehicles" 4 "Number of vehicles" 5 "Number of vehicles" 6 "Number of vehicles" 7 "Number of vehicles" 8 "Number of vehicles" 9 "Number of vehicles" 10 "Number of vehicles" 11 "Over than 10 vehicles" 12 "Reserved" 13 "Reserved" 14 "Default" 15 "Error indicator";
@@ -146,10 +146,10 @@ static void hyundai_canfd_rx_hook(const CANPacket_t *msg) {
static bool hyundai_canfd_tx_hook(const CANPacket_t *msg) {
const TorqueSteeringLimits HYUNDAI_CANFD_STEERING_LIMITS = {
.max_torque = 270,
.max_rt_delta = 112,
.max_rate_up = 2,
.max_rate_down = 3,
.max_torque = 409,
.max_rt_delta = 375,
.max_rate_up = 10,
.max_rate_down = 10,
.driver_torque_allowance = 250,
.driver_torque_multiplier = 2,
.type = TorqueDriverLimited,
@@ -49,11 +49,11 @@ class TestHyundaiCanfdBase(HyundaiButtonBase, common.CarSafetyTest, common.Drive
STANDSTILL_THRESHOLD = 12 # 0.375 kph
FWD_BLACKLISTED_ADDRS = {2: [0x50, 0x2a4]}
MAX_RATE_UP = 2
MAX_RATE_DOWN = 3
MAX_TORQUE_LOOKUP = [0], [270]
MAX_RATE_UP = 10
MAX_RATE_DOWN = 10
MAX_TORQUE_LOOKUP = [0], [409]
MAX_RT_DELTA = 112
MAX_RT_DELTA = 375
DRIVER_TORQUE_ALLOWANCE = 250
DRIVER_TORQUE_FACTOR = 2
+13
View File
@@ -291,6 +291,19 @@ class Car:
# Initialize CarInterface, once controls are ready
# TODO: this can make us miss at least a few cycles when doing an ECU knockout
self.CI.init(self.CP, *self.can_callbacks)
# If ECU disable was skipped/failed, strip LONG safety flag from BOTH CarParams
# and StarPilotCarParams (pandad ORs both safetyParams together)
if self.CP.openpilotLongitudinalControl and self.params.get_bool("EcuDisableFailed"):
# ECU disable failed/rejected - switch to lateral-only mode with stock ACC
LONG_FLAG = 4 # HyundaiSafetyFlags.LONG
for cfg in self.CP.safetyConfigs:
cfg.safetyParam &= ~LONG_FLAG
for cfg in self.FPCP.safetyConfigs:
cfg.safetyParam &= ~LONG_FLAG
# Let stock ACC manage cruise (prevents "controls mismatch" error)
self.CP.pcmCruise = True
self.params.put("CarParams", self.CP.to_bytes())
self.params.put("StarPilotCarParams", self.FPCP.to_bytes())
# signal pandad to switch to car safety mode
self.params.put_bool_nonblocking("ControlsReady", True)
+4 -1
View File
@@ -136,7 +136,10 @@ class Controls:
CS.steerFaultTemporary, CS.steerFaultPermanent,
standstill, self.CP.steerAtStandstill,
self.sm['starpilotPlan'].lateralCheck)
CC.longActive = CC.enabled and not any(e.overrideLongitudinal for e in self.sm['onroadEvents']) and not self.sm['starpilotCarState'].pauseLongitudinal and self.CP.openpilotLongitudinalControl
# EcuDisableFailed is set when car started in READY mode (ECU disable was rejected)
# Disable longitudinal so stock ACC works instead
ecu_disable_failed = self.params.get_bool("EcuDisableFailed")
CC.longActive = CC.enabled and not any(e.overrideLongitudinal for e in self.sm['onroadEvents']) and not self.sm['starpilotCarState'].pauseLongitudinal and self.CP.openpilotLongitudinalControl and not ecu_disable_failed
actuators = CC.actuators
actuators.longControlState = self.LoC.long_control_state
+8
View File
@@ -1232,6 +1232,14 @@ STARPILOT_EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
Priority.LOW, VisualAlert.none, AudibleAlert.prompt, 3.),
},
StarPilotEventName.lkasEnable: {
ET.WARNING: EngagementAlert(AudibleAlert.engage),
},
StarPilotEventName.lkasDisable: {
ET.PERMANENT: EngagementAlert(AudibleAlert.disengage),
},
StarPilotEventName.turningLeft: {
ET.WARNING: Alert(
"Turning Left",
@@ -119,7 +119,7 @@ class StarPilotAlwaysOnLateralLayout(StarPilotPanel):
super().__init__()
self.CATEGORIES = [
{"title": tr_noop("Always On Lateral"), "type": "toggle", "get_state": lambda: self._params.get_bool("AlwaysOnLateral"), "set_state": lambda x: self._on_reboot_toggle("AlwaysOnLateral", x), "icon": "toggle_icons/icon_always_on_lateral.png", "color": "#597497"},
{"title": tr_noop("Enable With LKAS"), "type": "toggle", "get_state": lambda: self._params.get_bool("AlwaysOnLateralLKAS"), "set_state": lambda x: self._params.put_bool("AlwaysOnLateralLKAS", x), "icon": "toggle_icons/icon_always_on_lateral.png", "color": "#597497", "visible": lambda: self._params.get_bool("AlwaysOnLateral")},
{"title": tr_noop("Enable With LKAS"), "type": "toggle", "get_state": lambda: self._params.get_bool("AlwaysOnLateralLKAS"), "set_state": lambda x: self._params.put_bool("AlwaysOnLateralLKAS", x), "icon": "toggle_icons/icon_always_on_lateral.png", "color": "#597497", "visible": lambda: self._params.get_bool("AlwaysOnLateral") and starpilot_state.car_state.lkasAllowedForAOL},
{"title": tr_noop("Pause Below"), "type": "value", "get_value": lambda: f"{self._params.get_int('PauseAOLOnBrake')} mph", "on_click": lambda: self._show_speed_selector("PauseAOLOnBrake"), "icon": "toggle_icons/icon_always_on_lateral.png", "color": "#597497", "visible": lambda: self._params.get_bool("AlwaysOnLateral")},
]
self._rebuild_grid()
@@ -62,6 +62,54 @@ class StarPilotWheelLayout(StarPilotPanel):
"key": "LKASButtonControl",
"color": "#64748B",
},
{
"title": tr_noop("Mode Button"),
"type": "value",
"get_value": lambda: self._get_action_name("ModeButtonControl"),
"on_click": lambda: self._show_action_picker("ModeButtonControl"),
"key": "ModeButtonControl",
"color": "#64748B",
},
{
"title": tr_noop("Mode (Long Press)"),
"type": "value",
"get_value": lambda: self._get_action_name("LongModeButtonControl"),
"on_click": lambda: self._show_action_picker("LongModeButtonControl"),
"key": "LongModeButtonControl",
"color": "#64748B",
},
{
"title": tr_noop("Mode (Very Long)"),
"type": "value",
"get_value": lambda: self._get_action_name("VeryLongModeButtonControl"),
"on_click": lambda: self._show_action_picker("VeryLongModeButtonControl"),
"key": "VeryLongModeButtonControl",
"color": "#64748B",
},
{
"title": tr_noop("Star Button"),
"type": "value",
"get_value": lambda: self._get_action_name("StarButtonControl"),
"on_click": lambda: self._show_action_picker("StarButtonControl"),
"key": "StarButtonControl",
"color": "#64748B",
},
{
"title": tr_noop("Star (Long Press)"),
"type": "value",
"get_value": lambda: self._get_action_name("LongStarButtonControl"),
"on_click": lambda: self._show_action_picker("LongStarButtonControl"),
"key": "LongStarButtonControl",
"color": "#64748B",
},
{
"title": tr_noop("Star (Very Long)"),
"type": "value",
"get_value": lambda: self._get_action_name("VeryLongStarButtonControl"),
"on_click": lambda: self._show_action_picker("VeryLongStarButtonControl"),
"key": "VeryLongStarButtonControl",
"color": "#64748B",
},
]
self._rebuild_grid()
@@ -131,6 +179,10 @@ class StarPilotWheelLayout(StarPilotPanel):
visible = True
if key == "LKASButtonControl":
visible &= not cs.isSubaru
visible &= not (cs.lkasAllowedForAOL and self._params.get_bool("AlwaysOnLateral") and self._params.get_bool("AlwaysOnLateralLKAS"))
if key in ("ModeButtonControl", "LongModeButtonControl", "VeryLongModeButtonControl",
"StarButtonControl", "LongStarButtonControl", "VeryLongStarButtonControl"):
visible &= cs.hasModeStarButtons
if not visible:
continue
tile_type = cat.get("type", "hub")
+6 -1
View File
@@ -7,6 +7,7 @@ from openpilot.system.hardware import HARDWARE, PC
from openpilot.selfdrive.ui.ui_state import ui_state
from cereal import car, log, custom, messaging
from opendbc.car.gm.values import GMFlags
from opendbc.car.hyundai.values import HyundaiFlags
@dataclass
class StarPilotCarState:
@@ -39,6 +40,7 @@ class StarPilotCarState:
# ========== Device/Car State ==========
isFrogsGoMoo: bool = False
hasPCMCruise: bool = False
hasModeStarButtons: bool = False
lkasAllowedForAOL: bool = False
openpilotLongitudinalControlDisabled: bool = False
hasAlphaLongitudinal: bool = False
@@ -82,6 +84,7 @@ class StarPilotState:
if not fallback_model:
fallback_model = "CHEVROLET_BOLT_ACC_2022_2023"
self.car_state.hasModeStarButtons = self.car_state.isHKGCanFd
self.car_state.hasPedal = starpilot_toggles.get("has_pedal", True)
self.car_state.hasSASCM = starpilot_toggles.get("has_sascm", False)
self.car_state.hasSDSU = starpilot_toggles.get("has_sdsu", False)
@@ -157,7 +160,9 @@ class StarPilotState:
self.car_state.isTSK = bool(self._safe_get(CP, "secOcRequired", False))
self.car_state.isVolt = car_fingerprint.startswith("CHEVROLET_VOLT")
self.car_state.lkasAllowedForAOL = starpilot_toggles.get("lkas_allowed_for_aol", False)
cp_flags = self._safe_get(CP, "flags", 0)
self.car_state.hasModeStarButtons = car_make == "hyundai" and bool(cp_flags & HyundaiFlags.CANFD)
self.car_state.lkasAllowedForAOL = car_make == "hyundai" and bool(cp_flags & (HyundaiFlags.CANFD | HyundaiFlags.HAS_LDA_BUTTON))
self.car_state.longitudinalActuatorDelay = float(self._safe_get(CP, "longitudinalActuatorDelay", self.car_state.longitudinalActuatorDelay))
self.car_state.startAccel = float(self._safe_get(CP, "startAccel", self.car_state.startAccel))
self.car_state.steerActuatorDelay = float(self._safe_get(CP, "steerActuatorDelay", self.car_state.steerActuatorDelay))
@@ -215,6 +215,7 @@ DeveloperPanel::DeveloperPanel(SettingsWindow *parent) : QFrame(parent) {
{14, tr("Longitudinal MPC Jerk: Acceleration")},
{15, tr("Longitudinal MPC Jerk: Danger Zone")},
{16, tr("Longitudinal MPC Jerk: Speed Control")},
{17, tr("Model Name")},
};
ButtonControl *metricToggle = new ButtonControl(title, tr("SELECT"), desc);
+67 -3
View File
@@ -142,9 +142,11 @@ DEVELOPER_SIDEBAR_METRICS = {
"LATERAL_STEERING_ANGLE": 10,
"LATERAL_TORQUE_USED": 11,
"LONGITUDINAL_ACTUATOR_ACCELERATION": 12,
"LONGITUDINAL_MPC_JERK_ACCELERATION": 13,
"LONGITUDINAL_MPC_JERK_DANGER_ZONE": 14,
"LONGITUDINAL_MPC_JERK_SPEED_CONTROL": 15,
"LONGITUDINAL_MPC_DANGER_FACTOR": 13,
"LONGITUDINAL_MPC_JERK_ACCELERATION": 14,
"LONGITUDINAL_MPC_JERK_DANGER_ZONE": 15,
"LONGITUDINAL_MPC_JERK_SPEED_CONTROL": 16,
"MODEL_NAME": 17,
}
DEVICE_SHUTDOWN_TIMES = {
@@ -823,6 +825,68 @@ class StarPilotVariables:
toggle.switchback_mode_via_lkas = lkas_button_control == BUTTON_FUNCTIONS["SWITCHBACK_MODE"]
toggle.traffic_mode_via_lkas = toggle.openpilot_longitudinal and lkas_button_control == BUTTON_FUNCTIONS["TRAFFIC_MODE"]
has_canfd_media_buttons = toggle.car_make == "hyundai" and bool(CP.flags & HyundaiFlags.CANFD)
mode_button_control = self.get_value("ModeButtonControl", cast=float, condition=has_canfd_media_buttons)
toggle.experimental_mode_via_mode = toggle.openpilot_longitudinal and mode_button_control == BUTTON_FUNCTIONS["EXPERIMENTAL_MODE"]
toggle.experimental_mode_via_press |= toggle.experimental_mode_via_mode
toggle.force_coast_via_mode = toggle.openpilot_longitudinal and mode_button_control == BUTTON_FUNCTIONS["FORCE_COAST"]
toggle.pause_lateral_via_mode = mode_button_control == BUTTON_FUNCTIONS["PAUSE_LATERAL"]
toggle.pause_longitudinal_via_mode = toggle.openpilot_longitudinal and mode_button_control == BUTTON_FUNCTIONS["PAUSE_LONGITUDINAL"]
toggle.personality_profile_via_mode = toggle.openpilot_longitudinal and mode_button_control == BUTTON_FUNCTIONS["PERSONALITY_PROFILE"]
toggle.switchback_mode_via_mode = mode_button_control == BUTTON_FUNCTIONS["SWITCHBACK_MODE"]
toggle.traffic_mode_via_mode = toggle.openpilot_longitudinal and mode_button_control == BUTTON_FUNCTIONS["TRAFFIC_MODE"]
mode_button_control_long = self.get_value("LongModeButtonControl", cast=float, condition=has_canfd_media_buttons)
toggle.experimental_mode_via_mode_long = toggle.openpilot_longitudinal and mode_button_control_long == BUTTON_FUNCTIONS["EXPERIMENTAL_MODE"]
toggle.experimental_mode_via_press |= toggle.experimental_mode_via_mode_long
toggle.force_coast_via_mode_long = toggle.openpilot_longitudinal and mode_button_control_long == BUTTON_FUNCTIONS["FORCE_COAST"]
toggle.pause_lateral_via_mode_long = mode_button_control_long == BUTTON_FUNCTIONS["PAUSE_LATERAL"]
toggle.pause_longitudinal_via_mode_long = toggle.openpilot_longitudinal and mode_button_control_long == BUTTON_FUNCTIONS["PAUSE_LONGITUDINAL"]
toggle.personality_profile_via_mode_long = toggle.openpilot_longitudinal and mode_button_control_long == BUTTON_FUNCTIONS["PERSONALITY_PROFILE"]
toggle.switchback_mode_via_mode_long = mode_button_control_long == BUTTON_FUNCTIONS["SWITCHBACK_MODE"]
toggle.traffic_mode_via_mode_long = toggle.openpilot_longitudinal and mode_button_control_long == BUTTON_FUNCTIONS["TRAFFIC_MODE"]
mode_button_control_very_long = self.get_value("VeryLongModeButtonControl", cast=float, condition=has_canfd_media_buttons)
toggle.experimental_mode_via_mode_very_long = toggle.openpilot_longitudinal and mode_button_control_very_long == BUTTON_FUNCTIONS["EXPERIMENTAL_MODE"]
toggle.experimental_mode_via_press |= toggle.experimental_mode_via_mode_very_long
toggle.force_coast_via_mode_very_long = toggle.openpilot_longitudinal and mode_button_control_very_long == BUTTON_FUNCTIONS["FORCE_COAST"]
toggle.pause_lateral_via_mode_very_long = mode_button_control_very_long == BUTTON_FUNCTIONS["PAUSE_LATERAL"]
toggle.pause_longitudinal_via_mode_very_long = toggle.openpilot_longitudinal and mode_button_control_very_long == BUTTON_FUNCTIONS["PAUSE_LONGITUDINAL"]
toggle.personality_profile_via_mode_very_long = toggle.openpilot_longitudinal and mode_button_control_very_long == BUTTON_FUNCTIONS["PERSONALITY_PROFILE"]
toggle.switchback_mode_via_mode_very_long = mode_button_control_very_long == BUTTON_FUNCTIONS["SWITCHBACK_MODE"]
toggle.traffic_mode_via_mode_very_long = toggle.openpilot_longitudinal and mode_button_control_very_long == BUTTON_FUNCTIONS["TRAFFIC_MODE"]
star_button_control = self.get_value("StarButtonControl", cast=float, condition=has_canfd_media_buttons)
toggle.experimental_mode_via_star = toggle.openpilot_longitudinal and star_button_control == BUTTON_FUNCTIONS["EXPERIMENTAL_MODE"]
toggle.experimental_mode_via_press |= toggle.experimental_mode_via_star
toggle.force_coast_via_star = toggle.openpilot_longitudinal and star_button_control == BUTTON_FUNCTIONS["FORCE_COAST"]
toggle.pause_lateral_via_star = star_button_control == BUTTON_FUNCTIONS["PAUSE_LATERAL"]
toggle.pause_longitudinal_via_star = toggle.openpilot_longitudinal and star_button_control == BUTTON_FUNCTIONS["PAUSE_LONGITUDINAL"]
toggle.personality_profile_via_star = toggle.openpilot_longitudinal and star_button_control == BUTTON_FUNCTIONS["PERSONALITY_PROFILE"]
toggle.switchback_mode_via_star = star_button_control == BUTTON_FUNCTIONS["SWITCHBACK_MODE"]
toggle.traffic_mode_via_star = toggle.openpilot_longitudinal and star_button_control == BUTTON_FUNCTIONS["TRAFFIC_MODE"]
star_button_control_long = self.get_value("LongStarButtonControl", cast=float, condition=has_canfd_media_buttons)
toggle.experimental_mode_via_star_long = toggle.openpilot_longitudinal and star_button_control_long == BUTTON_FUNCTIONS["EXPERIMENTAL_MODE"]
toggle.experimental_mode_via_press |= toggle.experimental_mode_via_star_long
toggle.force_coast_via_star_long = toggle.openpilot_longitudinal and star_button_control_long == BUTTON_FUNCTIONS["FORCE_COAST"]
toggle.pause_lateral_via_star_long = star_button_control_long == BUTTON_FUNCTIONS["PAUSE_LATERAL"]
toggle.pause_longitudinal_via_star_long = toggle.openpilot_longitudinal and star_button_control_long == BUTTON_FUNCTIONS["PAUSE_LONGITUDINAL"]
toggle.personality_profile_via_star_long = toggle.openpilot_longitudinal and star_button_control_long == BUTTON_FUNCTIONS["PERSONALITY_PROFILE"]
toggle.switchback_mode_via_star_long = star_button_control_long == BUTTON_FUNCTIONS["SWITCHBACK_MODE"]
toggle.traffic_mode_via_star_long = toggle.openpilot_longitudinal and star_button_control_long == BUTTON_FUNCTIONS["TRAFFIC_MODE"]
star_button_control_very_long = self.get_value("VeryLongStarButtonControl", cast=float, condition=has_canfd_media_buttons)
toggle.experimental_mode_via_star_very_long = toggle.openpilot_longitudinal and star_button_control_very_long == BUTTON_FUNCTIONS["EXPERIMENTAL_MODE"]
toggle.experimental_mode_via_press |= toggle.experimental_mode_via_star_very_long
toggle.force_coast_via_star_very_long = toggle.openpilot_longitudinal and star_button_control_very_long == BUTTON_FUNCTIONS["FORCE_COAST"]
toggle.pause_lateral_via_star_very_long = star_button_control_very_long == BUTTON_FUNCTIONS["PAUSE_LATERAL"]
toggle.pause_longitudinal_via_star_very_long = toggle.openpilot_longitudinal and star_button_control_very_long == BUTTON_FUNCTIONS["PAUSE_LONGITUDINAL"]
toggle.personality_profile_via_star_very_long = toggle.openpilot_longitudinal and star_button_control_very_long == BUTTON_FUNCTIONS["PERSONALITY_PROFILE"]
toggle.switchback_mode_via_star_very_long = star_button_control_very_long == BUTTON_FUNCTIONS["SWITCHBACK_MODE"]
toggle.traffic_mode_via_star_very_long = toggle.openpilot_longitudinal and star_button_control_very_long == BUTTON_FUNCTIONS["TRAFFIC_MODE"]
toggle.has_canfd_media_buttons = has_canfd_media_buttons
toggle.lock_doors_timer = self.get_value("LockDoorsTimer", cast=float, condition=(toggle.car_make == "toyota"))
longitudinal_tuning = toggle.openpilot_longitudinal and self.get_value("LongitudinalTune")
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import numpy as np
from openpilot.common.params import Params
from openpilot.selfdrive.controls.lib.longitudinal_planner import A_CRUISE_MIN, get_max_accel
from openpilot.starpilot.common.accel_profile import (
@@ -80,10 +81,13 @@ def get_max_allowed_accel(v_ego, ev_tuning=True, truck_tuning=False):
class StarPilotAcceleration:
def __init__(self, StarPilotPlanner):
self.starpilot_planner = StarPilotPlanner
self.params = Params()
self.max_accel = 0
self.min_accel = 0
self.last_gear_state = "init"
def update(self, v_ego, sm, starpilot_toggles):
eco_gear = sm["starpilotCarState"].ecoGear
sport_gear = sm["starpilotCarState"].sportGear
@@ -100,10 +104,7 @@ class StarPilotAcceleration:
if eco_gear:
self.max_accel = get_max_accel_eco(v_ego, ev_tuning, truck_tuning)
else:
if starpilot_toggles.acceleration_profile == ACCELERATION_PROFILES["SPORT"]:
self.max_accel = get_max_accel_sport(v_ego, ev_tuning, truck_tuning)
else:
self.max_accel = get_max_allowed_accel(v_ego, ev_tuning, truck_tuning)
self.max_accel = get_max_allowed_accel(v_ego, ev_tuning, truck_tuning)
else:
if starpilot_toggles.acceleration_profile == ACCELERATION_PROFILES["ECO"]:
self.max_accel = get_max_accel_eco(v_ego, ev_tuning, truck_tuning)
@@ -135,3 +136,24 @@ class StarPilotAcceleration:
self.min_accel = A_CRUISE_MIN_SPORT
else:
self.min_accel = A_CRUISE_MIN
# Sync AccelerationProfile and DecelerationProfile params so the UI reflects the active drive mode
# Eco → Eco, Normal → Standard, Sport → Sport+
gear_state = "eco" if eco_gear else ("sport" if sport_gear else "normal")
if gear_state != self.last_gear_state:
self.last_gear_state = gear_state
if gear_state == "eco":
if starpilot_toggles.map_acceleration:
self.params.put_nonblocking("AccelerationProfile", ACCELERATION_PROFILES["ECO"])
if starpilot_toggles.map_deceleration:
self.params.put_nonblocking("DecelerationProfile", DECELERATION_PROFILES["ECO"])
elif gear_state == "sport":
if starpilot_toggles.map_acceleration:
self.params.put_nonblocking("AccelerationProfile", ACCELERATION_PROFILES["SPORT_PLUS"])
if starpilot_toggles.map_deceleration:
self.params.put_nonblocking("DecelerationProfile", DECELERATION_PROFILES["SPORT"])
else:
if starpilot_toggles.map_acceleration:
self.params.put_nonblocking("AccelerationProfile", ACCELERATION_PROFILES["STANDARD"])
if starpilot_toggles.map_deceleration:
self.params.put_nonblocking("DecelerationProfile", DECELERATION_PROFILES["STANDARD"])
+9 -3
View File
@@ -22,7 +22,7 @@ class StarPilotEvents:
self.events = Events(starpilot=True)
self.always_on_lateral_enabled_previously = False
self.always_on_lateral_allowed_previously = False
self.previous_traffic_mode = False
self.previous_switchback_mode = False
self.random_event_playing = False
@@ -57,6 +57,12 @@ class StarPilotEvents:
else:
self.max_acceleration = 0
if sm["starpilotCarState"].alwaysOnLateralAllowed != self.always_on_lateral_allowed_previously:
if sm["starpilotCarState"].alwaysOnLateralAllowed:
self.events.add(StarPilotEventName.lkasEnable)
else:
self.events.add(StarPilotEventName.lkasDisable)
if self.starpilot_planner.starpilot_vcruise.forcing_stop:
self.events.add(StarPilotEventName.forcingStop)
@@ -173,11 +179,10 @@ class StarPilotEvents:
elif event_choice == "yourFrogTriedToKillMe":
self.events.add(StarPilotEventName.yourFrogTriedToKillMe)
if "youveGotMail" not in self.played_events and sm["starpilotCarState"].alwaysOnLateralEnabled and not self.always_on_lateral_enabled_previously:
if "youveGotMail" not in self.played_events and sm["starpilotCarState"].alwaysOnLateralAllowed and not self.always_on_lateral_allowed_previously:
if random.random() < RANDOM_EVENTS_CHANCE / DT_MDL:
self.events.add(StarPilotEventName.youveGotMail)
self.always_on_lateral_enabled_previously = sm["starpilotCarState"].alwaysOnLateralEnabled
self.random_event_playing |= bool({event for event in self.events.names if RANDOM_EVENT_START <= event <= RANDOM_EVENT_END})
if self.error_log.is_file():
@@ -212,4 +217,5 @@ class StarPilotEvents:
elif sm["starpilotModelV2"].turnDirection == TurnDirection.turnRight:
self.events.add(StarPilotEventName.turningRight)
self.always_on_lateral_allowed_previously = sm["starpilotCarState"].alwaysOnLateralAllowed
self.played_events.update(STARPILOT_EVENT_NAME[event] for event in self.events.names)
+34
View File
@@ -25,6 +25,10 @@ class StarPilotCard:
self.decel_pressed = False
self.distancePressed_previously = False
self.force_coast = False
self.modePressed_previously = False
self.mode_counter = 0
self.customPressed_previously = False
self.custom_counter = 0
self.pause_lateral = False
self.pause_longitudinal = False
self.switchback_mode_enabled = self.params_memory.get_bool("SwitchbackModeEnabled")
@@ -120,9 +124,39 @@ class StarPilotCard:
if any(be.pressed and be.type == ButtonType.lkas for be in carState.buttonEvents):
self.handle_button_event("lkas", sm, starpilot_toggles)
if getattr(starpilot_toggles, "has_canfd_media_buttons", False):
if starpilotCarState.modePressed:
self.mode_counter += 1
elif not self.modePressed_previously:
self.mode_counter = 0
self.modePressed_previously = starpilotCarState.modePressed
if not starpilotCarState.modePressed and 1 <= self.mode_counter < self.long_press_threshold:
self.handle_button_event("mode", sm, starpilot_toggles)
elif self.mode_counter == self.long_press_threshold:
self.handle_button_event("mode_long", sm, starpilot_toggles)
elif self.mode_counter == self.very_long_press_threshold:
self.handle_button_event("mode_long", sm, starpilot_toggles)
self.handle_button_event("mode_very_long", sm, starpilot_toggles)
if starpilotCarState.customPressed:
self.custom_counter += 1
elif not self.customPressed_previously:
self.custom_counter = 0
self.customPressed_previously = starpilotCarState.customPressed
if not starpilotCarState.customPressed and 1 <= self.custom_counter < self.long_press_threshold:
self.handle_button_event("star", sm, starpilot_toggles)
elif self.custom_counter == self.long_press_threshold:
self.handle_button_event("star_long", sm, starpilot_toggles)
elif self.custom_counter == self.very_long_press_threshold:
self.handle_button_event("star_long", sm, starpilot_toggles)
self.handle_button_event("star_very_long", sm, starpilot_toggles)
self.force_coast &= not (carState.brakePressed or carState.gasPressed)
starpilotCarState.accelPressed = self.accel_pressed
starpilotCarState.alwaysOnLateralAllowed = self.always_on_lateral_allowed
starpilotCarState.alwaysOnLateralEnabled = self.always_on_lateral_enabled
starpilotCarState.decelPressed = self.decel_pressed
starpilotCarState.distanceLongPressed = self.very_long_press_threshold > self.gap_counter >= self.long_press_threshold
@@ -996,7 +996,7 @@ void StarPilotLongitudinalPanel::updateToggles() {
}
else if (key == "MapGears") {
setVisible &= parent->isToyota;
setVisible &= parent->isToyota || parent->isHKG;
setVisible &= !parent->isTSK;
}
@@ -335,11 +335,13 @@ void StarPilotSettingsWindow::updateVariables() {
std::string fallbackFingerprint = fallbackModel.toStdString();
hasPedal = starpilot_toggles.value("has_pedal").toBool(true);
hasModeStarButtons = starpilot_toggles.contains("has_canfd_media_buttons") && starpilot_toggles.value("has_canfd_media_buttons").toBool();
hasSDSU = starpilot_toggles.value("has_sdsu").toBool();
hasZSS = starpilot_toggles.value("has_zss").toBool();
isBolt = fallbackFingerprint.rfind("CHEVROLET_BOLT", 0) == 0;
isGM = carMake == "gm";
isHKG = carMake == "hyundai";
isHKGCanFd = isHKG && hasModeStarButtons;
isSubaru = carMake == "subaru";
isToyota = carMake == "toyota";
isVolt = fallbackFingerprint.rfind("CHEVROLET_VOLT", 0) == 0;
@@ -382,6 +384,7 @@ void StarPilotSettingsWindow::updateVariables() {
isTSK = CP.getSecOcRequired();
isVolt = carFingerprint.rfind("CHEVROLET_VOLT", 0) == 0;
latAccelFactor = CP.getLateralTuning().getTorque().getLatAccelFactor();
hasModeStarButtons = starpilot_toggles.contains("has_canfd_media_buttons") ? starpilot_toggles.value("has_canfd_media_buttons").toBool() : isHKGCanFd;
lkasAllowedForAOL = starpilot_toggles.value("lkas_allowed_for_aol").toBool();
longitudinalActuatorDelay = CP.getLongitudinalActuatorDelay();
startAccel = CP.getStartAccel();
@@ -31,6 +31,7 @@ public:
bool hasRadar = true;
bool hasSDSU = false;
bool hasSNG = false;
bool hasModeStarButtons = false;
bool hasZSS = false;
bool isAngleCar = false;
bool isBolt = false;
+17 -1
View File
@@ -56,7 +56,13 @@ StarPilotWheelPanel::StarPilotWheelPanel(StarPilotSettingsWindow *parent, bool f
{"DistanceButtonControl", tr("Distance Button"), tr("<b>Action performed when the \"Distance\" button is pressed.</b>"), "../../starpilot/assets/toggle_icons/icon_mute.png"},
{"LongDistanceButtonControl", tr("Distance Button (Long Press)"), tr("<b>Action performed when the \"Distance\" button is pressed for more than 0.5 seconds.</b>"), "../../starpilot/assets/toggle_icons/icon_mute.png"},
{"VeryLongDistanceButtonControl", tr("Distance Button (Very Long Press)"), tr("<b>Action performed when the \"Distance\" button is pressed for more than 2.5 seconds.</b>"), "../../starpilot/assets/toggle_icons/icon_mute.png"},
{"LKASButtonControl", tr("LKAS Button"), tr("<b>Action performed when the \"LKAS\" button is pressed.</b>"), "../../starpilot/assets/toggle_icons/icon_mute.png"}
{"LKASButtonControl", tr("LKAS Button"), tr("<b>Action performed when the \"LKAS\" button is pressed.</b>"), "../../starpilot/assets/toggle_icons/icon_mute.png"},
{"ModeButtonControl", tr("Mode Button"), tr("<b>Action performed when the \"Mode\" button is pressed.</b>"), "../../starpilot/assets/toggle_icons/icon_mute.png"},
{"LongModeButtonControl", tr("Mode Button (Long Press)"), tr("<b>Action performed when the \"Mode\" button is pressed for more than 0.5 seconds.</b>"), "../../starpilot/assets/toggle_icons/icon_mute.png"},
{"VeryLongModeButtonControl", tr("Mode Button (Very Long Press)"), tr("<b>Action performed when the \"Mode\" button is pressed for more than 2.5 seconds.</b>"), "../../starpilot/assets/toggle_icons/icon_mute.png"},
{"StarButtonControl", tr("Star Button"), tr("<b>Action performed when the \"Star\" button is pressed.</b>"), "../../starpilot/assets/toggle_icons/icon_mute.png"},
{"LongStarButtonControl", tr("Star Button (Long Press)"), tr("<b>Action performed when the \"Star\" button is pressed for more than 0.5 seconds.</b>"), "../../starpilot/assets/toggle_icons/icon_mute.png"},
{"VeryLongStarButtonControl", tr("Star Button (Very Long Press)"), tr("<b>Action performed when the \"Star\" button is pressed for more than 2.5 seconds.</b>"), "../../starpilot/assets/toggle_icons/icon_mute.png"}
};
for (const auto &[param, title, desc, icon] : wheelToggles) {
@@ -121,6 +127,16 @@ void StarPilotWheelPanel::updateToggles() {
setVisible &= !parent->lkasAllowedForAOL || !(params.getBool("AlwaysOnLateral") && params.getBool("AlwaysOnLateralLKAS"));
}
if (!showAllToggles && (
key == "ModeButtonControl" ||
key == "LongModeButtonControl" ||
key == "VeryLongModeButtonControl" ||
key == "StarButtonControl" ||
key == "LongStarButtonControl" ||
key == "VeryLongStarButtonControl")) {
setVisible &= parent->hasModeStarButtons;
}
if (ButtonControl *wheelToggle = qobject_cast<ButtonControl*>(toggle)) {
if (key == "LKASButtonControl") {
const bool lkasLocked = lockLkasButtonIfNeeded(params);
+13 -1
View File
@@ -1,5 +1,7 @@
#include "starpilot/ui/qt/widgets/developer_sidebar.h"
#include <QRegularExpression>
void DeveloperSidebar::drawMetric(QPainter &p, const QPair<QString, QString> &label, QColor c, int y) {
const QRect rect = {12, y, 275, 126};
@@ -17,7 +19,11 @@ void DeveloperSidebar::drawMetric(QPainter &p, const QPair<QString, QString> &la
p.setPen(QColor(0xff, 0xff, 0xff));
p.setFont(InterFont(35, QFont::DemiBold));
p.drawText(rect.adjusted(0, 0, -22, 0), Qt::AlignCenter, label.first + "\n" + label.second);
if (label.second.isEmpty()) {
p.drawText(rect.adjusted(8, 8, -22, -8), Qt::AlignCenter | Qt::TextWordWrap, label.first);
} else {
p.drawText(rect.adjusted(8, 8, -22, -8), Qt::AlignCenter, label.first + "\n" + label.second);
}
}
DeveloperSidebar::DeveloperSidebar(QWidget *parent) : QFrame(parent) {
@@ -144,6 +150,11 @@ void DeveloperSidebar::updateState(const UIState &s, const StarPilotUIState &fs)
stiffnessFactorStatus = ItemStatus(QPair<QString, QString>(tr("STEER STIFF"), QString::number(liveParameters.getStiffnessFactor(), 'f', 5)), metricColor);
torqueStatus = ItemStatus(QPair<QString, QString>(tr("TORQUE %"), torqueLabel), metricColor);
QString modelName = starpilot_scene.starpilot_toggles.value("model_name").toString();
modelName.remove(QRegularExpression("\\(.*\\)"));
modelName.remove(QRegularExpression("[^a-zA-Z0-9 \\-\\.:]"));
modelNameStatus = ItemStatus(QPair<QString, QString>(modelName.trimmed(), ""), metricColor);
update();
}
@@ -171,6 +182,7 @@ void DeveloperSidebar::paintEvent(QPaintEvent *event) {
metricMap.insert(14, &accelerationJerkStatus);
metricMap.insert(15, &dangerJerkStatus);
metricMap.insert(16, &speedJerkStatus);
metricMap.insert(17, &modelNameStatus);
int count = 0;
for (size_t i = 0; i < metricAssignments.size(); ++i) {
@@ -37,6 +37,7 @@ private:
ItemStatus lateralEngagementStatus;
ItemStatus longitudinalEngagementStatus;
ItemStatus maxAccelerationStatus;
ItemStatus modelNameStatus;
ItemStatus speedJerkStatus;
ItemStatus steerAngleStatus;
ItemStatus steerRatioStatus;