RIP iPedal

This commit is contained in:
firestar5683
2026-05-11 19:09:47 -05:00
parent 21589861fd
commit a67c8f98b7
16 changed files with 7 additions and 883 deletions
-1
View File
@@ -159,7 +159,6 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"AlertVolumeControl", {PERSISTENT, BOOL, "0", "0", 2}},
{"AlwaysOnLateral", {PERSISTENT, BOOL, "1", "0", 0}},
{"AlwaysOnLateralLKAS", {PERSISTENT, BOOL, "1", "0", 2}},
{"AlwaysIPedal", {PERSISTENT, BOOL, "0", "0", 2}},
{"ApiCache_DriveStats", {PERSISTENT, JSON, "{}", "{}"}},
{"AutomaticallyDownloadModels", {PERSISTENT, BOOL, "1", "0", 1}},
{"AutomaticUpdates", {PERSISTENT, BOOL, "1", "1", 0}},
@@ -57,17 +57,6 @@ IONIQ_6_STOP_RELEASE_JERK_BP = [0.0, 0.15, 0.5]
IONIQ_6_STOP_RELEASE_JERK_V = [3.6 * IONIQ_6_RESPONSE_MULTIPLIER,
4.2 * IONIQ_6_RESPONSE_MULTIPLIER,
4.8 * IONIQ_6_RESPONSE_MULTIPLIER]
IONIQ_6_IPEDAL_PRESS_SEND_COUNT = 6
IONIQ_6_IPEDAL_LATCH_PRESS_SEND_COUNT = 6
IONIQ_6_IPEDAL_PADDLE_BURST_COUNT = 3
IONIQ_6_MAX_REGEN_STATE = 0x3C
IONIQ_6_MAX_REGEN_STATE_2 = 0x01
IONIQ_6_IPEDAL_REGEN_STATE = 0x50
IONIQ_6_IPEDAL_REGEN_STATE_2_PENDING = 0x01
IONIQ_6_IPEDAL_PROGRESS_RETRY_WAIT_FRAMES = 10
IONIQ_6_IPEDAL_RETRY_WAIT_FRAMES = 30
def get_canfd_lead_distance_setting(lead_distance: float | None, default_setting: int) -> int:
default = int(np.clip(default_setting, 0, 3))
if lead_distance is None or lead_distance <= CANFD_LEAD_MIN_DISTANCE:
@@ -253,17 +242,6 @@ class CarController(CarControllerBase):
self._ioniq_6_lane_change_ui_side = None
self._ioniq_6_lane_change_ui_trigger_frames = 0
self._ioniq_6_long_tuning = Ioniq6LongitudinalTuningState()
self._ioniq_6_always_ipedal_pending = False
self._ioniq_6_always_ipedal_press_remaining = 0
self._ioniq_6_always_ipedal_retry_frame = 0
self._ioniq_6_always_ipedal_startup_park_done = False
self._ioniq_6_last_ipedal_regen_state = 0
self._ioniq_6_last_ipedal_regen_state_2 = 0
self._ioniq_6_last_buttons_counter = 0
self._ioniq_6_last_regen_control_counter = -1
self._ioniq_6_regen_request_sent = False
self._ioniq_6_ipedal_latch_counter = -1
self._ioniq_6_last_gear = structs.CarState.GearShifter.unknown
self._genesis_g90_long_tuning = GenesisG90LongitudinalTuningState()
self._dash_lat_disengage_blink_frame = 0
self._dash_lat_disengage_init = False
@@ -306,126 +284,6 @@ class CarController(CarControllerBase):
return False, 0.0, 0.0, default_distance_setting
def _reset_ioniq_6_always_ipedal(self) -> None:
self._ioniq_6_always_ipedal_pending = False
self._ioniq_6_always_ipedal_press_remaining = 0
self._ioniq_6_always_ipedal_retry_frame = 0
self._ioniq_6_regen_request_sent = False
self._ioniq_6_ipedal_latch_counter = -1
def _arm_ioniq_6_always_ipedal(self) -> None:
self._ioniq_6_always_ipedal_pending = True
self._ioniq_6_always_ipedal_press_remaining = 0
self._ioniq_6_always_ipedal_retry_frame = self.frame
self._ioniq_6_regen_request_sent = False
self._ioniq_6_ipedal_latch_counter = -1
def _update_ioniq_6_always_ipedal(self, CC, CS, starpilot_toggles):
can_sends = []
if self.CP.carFingerprint != CAR.HYUNDAI_IONIQ_6 or not getattr(starpilot_toggles, "always_ipedal", False):
self._reset_ioniq_6_always_ipedal()
self._ioniq_6_always_ipedal_startup_park_done = False
self._ioniq_6_last_ipedal_regen_state = int(getattr(CS, "ipedal_regen_state", 0))
self._ioniq_6_last_ipedal_regen_state_2 = int(getattr(CS, "ipedal_regen_state_2", 0))
self._ioniq_6_last_buttons_counter = int(getattr(CS, "buttons_counter", 0))
self._ioniq_6_last_regen_control_counter = int(getattr(CS, "ioniq_6_regen_control_msg", {}).get("COUNTER", -1))
self._ioniq_6_last_gear = CS.out.gearShifter
return can_sends
gear = CS.out.gearShifter
regen_state = int(getattr(CS, "ipedal_regen_state", 0))
regen_state_2 = int(getattr(CS, "ipedal_regen_state_2", 0))
buttons_counter = int(getattr(CS, "buttons_counter", 0))
regen_control_msg = getattr(CS, "ioniq_6_regen_control_msg", {})
regen_control_counter = int(regen_control_msg.get("COUNTER", -1))
has_regen_control_msg = bool(regen_control_msg) and getattr(CS, "ioniq_6_regen_control_ts", 0) > 0
regen_state_changed = regen_state != self._ioniq_6_last_ipedal_regen_state or regen_state_2 != self._ioniq_6_last_ipedal_regen_state_2
buttons_counter_changed = buttons_counter != self._ioniq_6_last_buttons_counter
regen_control_counter_changed = regen_control_counter != self._ioniq_6_last_regen_control_counter
max_regen_state = regen_state == IONIQ_6_MAX_REGEN_STATE and regen_state_2 == IONIQ_6_MAX_REGEN_STATE_2
ipedal_latch_pending = regen_state == IONIQ_6_IPEDAL_REGEN_STATE and regen_state_2 == IONIQ_6_IPEDAL_REGEN_STATE_2_PENDING
was_max_regen_state = self._ioniq_6_last_ipedal_regen_state == IONIQ_6_MAX_REGEN_STATE and \
self._ioniq_6_last_ipedal_regen_state_2 == IONIQ_6_MAX_REGEN_STATE_2
was_ipedal_latch_pending = self._ioniq_6_last_ipedal_regen_state == IONIQ_6_IPEDAL_REGEN_STATE and \
self._ioniq_6_last_ipedal_regen_state_2 == IONIQ_6_IPEDAL_REGEN_STATE_2_PENDING
entered_latch_stage = (max_regen_state and not was_max_regen_state) or \
(ipedal_latch_pending and not was_ipedal_latch_pending)
drive = gear == structs.CarState.GearShifter.drive
park = gear == structs.CarState.GearShifter.park
drive_edge = drive and self._ioniq_6_last_gear != structs.CarState.GearShifter.drive
startup_park = park and not self._ioniq_6_always_ipedal_startup_park_done
startup_park_edge = startup_park and self._ioniq_6_last_gear != structs.CarState.GearShifter.park
target_gear = drive or startup_park
if gear == structs.CarState.GearShifter.unknown:
self._ioniq_6_always_ipedal_startup_park_done = False
elif not park and not self._ioniq_6_always_ipedal_startup_park_done:
self._ioniq_6_always_ipedal_startup_park_done = True
if (startup_park_edge or drive_edge) and not CS.ipedal_active:
self._arm_ioniq_6_always_ipedal()
elif not target_gear or CS.ipedal_active:
self._reset_ioniq_6_always_ipedal()
elif CC.enabled:
self._ioniq_6_always_ipedal_pending = False
self._ioniq_6_always_ipedal_press_remaining = 0
if entered_latch_stage:
self._ioniq_6_always_ipedal_press_remaining = 0
self._ioniq_6_always_ipedal_retry_frame = self.frame
self._ioniq_6_regen_request_sent = False
self._ioniq_6_ipedal_latch_counter = -1
if target_gear and self._ioniq_6_always_ipedal_pending and not CS.ipedal_active and not CC.enabled:
if self._ioniq_6_always_ipedal_press_remaining == 0 and self.frame >= self._ioniq_6_always_ipedal_retry_frame:
self._ioniq_6_always_ipedal_press_remaining = IONIQ_6_IPEDAL_LATCH_PRESS_SEND_COUNT if (max_regen_state or ipedal_latch_pending) \
else IONIQ_6_IPEDAL_PRESS_SEND_COUNT
self._ioniq_6_regen_request_sent = False
if max_regen_state or ipedal_latch_pending:
self._ioniq_6_ipedal_latch_counter = buttons_counter if 0 <= buttons_counter < hyundaicanfd.IONIQ_6_CRUISE_BUTTONS_COUNTER_MAX else -1
else:
self._ioniq_6_ipedal_latch_counter = -1
if self._ioniq_6_always_ipedal_press_remaining > 0:
if max_regen_state or ipedal_latch_pending:
if self._ioniq_6_ipedal_latch_counter < 0 and 0 <= buttons_counter < hyundaicanfd.IONIQ_6_CRUISE_BUTTONS_COUNTER_MAX:
self._ioniq_6_ipedal_latch_counter = buttons_counter
if 0 <= self._ioniq_6_ipedal_latch_counter < hyundaicanfd.IONIQ_6_CRUISE_BUTTONS_COUNTER_MAX:
# A real successful i-Pedal pull is a short held press followed by release, not a continuous hold.
# Mirror that with a stock-like six-counter sequence, then stop transmitting to give the car a release window.
paddle_msg = hyundaicanfd.create_ioniq_6_paddle_buttons(self.packer, self.CP, self.CAN,
self._ioniq_6_ipedal_latch_counter, left_paddle=True)
can_sends.append(paddle_msg)
self._ioniq_6_ipedal_latch_counter = hyundaicanfd.get_ioniq_6_cruise_buttons_next_counter(self._ioniq_6_ipedal_latch_counter)
self._ioniq_6_always_ipedal_press_remaining -= 1
elif buttons_counter_changed and 0 <= buttons_counter < hyundaicanfd.IONIQ_6_CRUISE_BUTTONS_COUNTER_MAX:
paddle_msg = hyundaicanfd.create_ioniq_6_paddle_buttons(self.packer, self.CP, self.CAN,
buttons_counter, left_paddle=True)
can_sends.extend([paddle_msg] * IONIQ_6_IPEDAL_PADDLE_BURST_COUNT)
self._ioniq_6_always_ipedal_press_remaining -= 1
if self._ioniq_6_always_ipedal_press_remaining == 0:
retry_wait_frames = IONIQ_6_IPEDAL_PROGRESS_RETRY_WAIT_FRAMES if regen_state_changed else IONIQ_6_IPEDAL_RETRY_WAIT_FRAMES
self._ioniq_6_always_ipedal_retry_frame = self.frame + retry_wait_frames
self._ioniq_6_ipedal_latch_counter = -1
# The drivetrain latch uses a second HKG CAN-FD request path in addition to the left paddle bit.
# Mirror the next stock 0x25A frame once per retry burst instead of spamming it continuously.
if max_regen_state and has_regen_control_msg and regen_control_counter_changed and not self._ioniq_6_regen_request_sent:
request_tail = hyundaicanfd.get_ioniq_6_regen_control_request_tail(regen_control_msg)
if request_tail is not None:
can_sends.append(hyundaicanfd.create_ioniq_6_regen_control(self.packer, self.CP, self.CAN, regen_control_msg))
self._ioniq_6_regen_request_sent = True
self._ioniq_6_last_ipedal_regen_state = regen_state
self._ioniq_6_last_ipedal_regen_state_2 = regen_state_2
self._ioniq_6_last_buttons_counter = buttons_counter
self._ioniq_6_last_regen_control_counter = regen_control_counter
self._ioniq_6_last_gear = gear
return can_sends
def update(self, CC, CS, now_nanos, starpilot_toggles):
actuators = CC.actuators
hud_control = CC.hudControl
@@ -678,8 +536,6 @@ class CarController(CarControllerBase):
if self._ioniq_6_lane_change_ui_trigger_frames > 0:
self._ioniq_6_lane_change_ui_trigger_frames -= 1
can_sends.extend(self._update_ioniq_6_always_ipedal(CC, CS, starpilot_toggles))
if self.long_active_ecu:
if lka_steering:
can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame))
@@ -24,12 +24,6 @@ BUTTONS_DICT = {Buttons.RES_ACCEL: ButtonType.accelCruise, Buttons.SET_DECEL: Bu
IONIQ_6_BLINDSPOT_RIGHT_MASK = 0x08
IONIQ_6_BLINDSPOT_LEFT_MASK = 0x10
IONIQ_6_MAX_REGEN_STATE = 0x3C
IONIQ_6_MAX_REGEN_STATE_2 = 0x01
IONIQ_6_IPEDAL_INTERMEDIATE_REGEN_STATE = 0x50
IONIQ_6_IPEDAL_INTERMEDIATE_REGEN_STATE_2 = 0x01
IONIQ_6_IPEDAL_REGEN_STATE = 0x50
IONIQ_6_IPEDAL_REGEN_STATE_2 = 0x03
CANFD_CAMERA_LEAD_MIN_DISTANCE = 0.1
@@ -50,18 +44,6 @@ def decode_ioniq_6_blindspot_radar_state(state: int) -> tuple[bool, bool]:
return bool(state_int & IONIQ_6_BLINDSPOT_LEFT_MASK), bool(state_int & IONIQ_6_BLINDSPOT_RIGHT_MASK)
def decode_ioniq_6_ipedal_state(regen_state: int, regen_state_2: int) -> bool:
return int(regen_state) == IONIQ_6_IPEDAL_REGEN_STATE and int(regen_state_2) == IONIQ_6_IPEDAL_REGEN_STATE_2
def decode_ioniq_6_max_regen_state(regen_state: int, regen_state_2: int) -> bool:
return int(regen_state) == IONIQ_6_MAX_REGEN_STATE and int(regen_state_2) == IONIQ_6_MAX_REGEN_STATE_2
def decode_ioniq_6_ipedal_intermediate_state(regen_state: int, regen_state_2: int) -> bool:
return int(regen_state) == IONIQ_6_IPEDAL_INTERMEDIATE_REGEN_STATE and int(regen_state_2) == IONIQ_6_IPEDAL_INTERMEDIATE_REGEN_STATE_2
def decode_canfd_camera_lead(distance: float, rel_speed: float) -> tuple[bool, float, float]:
lead_distance = float(distance)
lead_visible = lead_distance > CANFD_CAMERA_LEAD_MIN_DISTANCE
@@ -89,11 +71,6 @@ class CarState(CarStateBase):
self.custom_button = 0
self.cancel_button_enable_in_progress = False
self.cruise_buttons_msg = {}
self.ipedal_active = False
self.ipedal_regen_state = 0
self.ipedal_regen_state_2 = 0
self.ioniq_6_regen_control_msg = {}
self.ioniq_6_regen_control_ts = 0
self.gear_msg_canfd = "ACCELERATOR" if CP.flags & HyundaiFlags.EV else \
"GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else \
@@ -346,7 +323,6 @@ class CarState(CarStateBase):
self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1
speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
self.ipedal_active = False
if self.CP.flags & (HyundaiFlags.EV | HyundaiFlags.HYBRID):
ret.gasPressed = cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL"] > 1e-5
@@ -424,15 +400,6 @@ class CarState(CarStateBase):
# TODO: find this message on ICE & HYBRID cars + cruise control signals (if exists)
if self.CP.flags & HyundaiFlags.EV:
ret.cruiseState.nonAdaptive = cp.vl["MANUAL_SPEED_LIMIT_ASSIST"]["MSLA_ENABLED"] == 1
if self.CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
msla = cp.vl["MANUAL_SPEED_LIMIT_ASSIST"]
self.ipedal_regen_state = int(msla.get("EV_REGEN_STATE", 0))
self.ipedal_regen_state_2 = int(msla.get("EV_REGEN_STATE_2", 0))
self.ipedal_active = decode_ioniq_6_ipedal_state(self.ipedal_regen_state, self.ipedal_regen_state_2)
if cp.ts_nanos["IONIQ_6_REGEN_CONTROL"]["CHECKSUM"] > 0:
self.ioniq_6_regen_control_msg = copy.copy(cp.vl["IONIQ_6_REGEN_CONTROL"])
self.ioniq_6_regen_control_ts = cp.ts_nanos["IONIQ_6_REGEN_CONTROL"]["CHECKSUM"]
prev_cruise_buttons = self.cruise_buttons[-1]
prev_main_buttons = self.main_buttons[-1]
prev_lda_button = self.lda_button
@@ -517,8 +484,6 @@ class CarState(CarStateBase):
if CP.flags & HyundaiFlags.EV:
msgs.append(("DRIVE_MODE_EV", 0)) # optional: not all CAN-FD EV variants publish drive mode
msgs.append(("MANUAL_SPEED_LIMIT_ASSIST", 0)) # optional: used for non-adaptive cruise state and Ioniq 6 i-Pedal latch detection
if CP.carFingerprint == CAR.HYUNDAI_IONIQ_6:
msgs.append(("IONIQ_6_REGEN_CONTROL", 0))
msgs.append(("STEERING_WHEEL_MEDIA_BUTTONS", 0)) # optional: absent or slower on some CAN-FD variants
cam_msgs.append(("ADAS_0x380", 0)) # optional: dashboard stop-sign signal, only on ADAS-equipped HKG CANFD
return {
@@ -162,77 +162,6 @@ def create_suppress_lfa(packer, CAN, lfa_block_msg, lka_steering_alt):
return packer.make_can_msg(suppress_msg, CAN.ACAN, values)
IONIQ_6_CRUISE_BUTTONS_COUNTER_MAX = 15
IONIQ_6_CRUISE_BUTTONS_BASE_CHECKSUMS = (
0x56, 0xEF, 0x39, 0x80, 0x88,
0x31, 0xE7, 0x5E, 0xF7, 0x4E,
0x98, 0x21, 0x29, 0x90, 0x46,
)
IONIQ_6_CRUISE_BUTTONS_LEFT_PADDLE_CHECKSUM_XOR = 0x77
IONIQ_6_CRUISE_BUTTONS_RIGHT_PADDLE_CHECKSUM_XOR = 0xD4
IONIQ_6_REGEN_CONTROL_REQUEST_TAILS = {
(0xA8, 0x0C, 0x12, 0x0E): (0xC0, 0x0C, 0x12, 0x00),
(0xA8, 0x0E, 0x07, 0x0E): (0x85, 0x0E, 0x07, 0x0C),
(0x18, 0x10, 0x07, 0x02): (0xB5, 0x10, 0x07, 0x00),
(0xA8, 0x10, 0x07, 0x0E): (0xB5, 0x10, 0x07, 0x00),
}
def get_ioniq_6_cruise_buttons_next_counter(counter: int) -> int:
return (int(counter) + 1) % IONIQ_6_CRUISE_BUTTONS_COUNTER_MAX
def create_ioniq_6_paddle_buttons(packer, CP, CAN, cnt, left_paddle=False, right_paddle=False):
if left_paddle and right_paddle:
raise ValueError("Ioniq 6 paddle spoof only supports one paddle at a time")
if cnt < 0 or cnt >= IONIQ_6_CRUISE_BUTTONS_COUNTER_MAX:
raise ValueError(f"Invalid Ioniq 6 cruise buttons counter: {cnt}")
values = {
"COUNTER": cnt,
"SET_ME_1": 1,
"CRUISE_BUTTONS": 0,
"ADAPTIVE_CRUISE_MAIN_BTN": 0,
"NORMAL_CRUISE_MAIN_BTN": 0,
"LDA_BTN": 0,
"LEFT_PADDLE": int(left_paddle),
"RIGHT_PADDLE": int(right_paddle),
}
address = packer.dbc.name_to_msg["CRUISE_BUTTONS"].address
dat = packer.pack(address, values)
checksum = IONIQ_6_CRUISE_BUTTONS_BASE_CHECKSUMS[cnt]
if left_paddle:
checksum ^= IONIQ_6_CRUISE_BUTTONS_LEFT_PADDLE_CHECKSUM_XOR
if right_paddle:
checksum ^= IONIQ_6_CRUISE_BUTTONS_RIGHT_PADDLE_CHECKSUM_XOR
dat[0] = checksum
bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_LKA_STEERING else CAN.CAM
return address, bytes(dat), bus
def get_ioniq_6_regen_control_request_tail(base_values):
base_tail = tuple(int(base_values.get(f"BYTE{i}", 0)) for i in range(24, 28))
return IONIQ_6_REGEN_CONTROL_REQUEST_TAILS.get(base_tail)
def create_ioniq_6_regen_control(packer, CP, CAN, base_values):
request_tail = get_ioniq_6_regen_control_request_tail(base_values)
if request_tail is None:
raise ValueError(f"Unsupported Ioniq 6 regen control tail: {tuple(int(base_values.get(f'BYTE{i}', 0)) for i in range(24, 28))}")
values = {k: v for k, v in base_values.items() if k != "CHECKSUM"}
address = packer.dbc.name_to_msg["IONIQ_6_REGEN_CONTROL"].address
dat = bytearray(packer.pack(address, values))
dat[24:28] = bytes(request_tail)
checksum = hkg_can_fd_checksum(address, None, dat)
dat[0] = checksum & 0xFF
dat[1] = (checksum >> 8) & 0xFF
return address, bytes(dat), CAN.ECAN
def create_buttons(packer, CP, CAN, cnt, btn=0, base_values=None, left_paddle=False, right_paddle=False):
values = {k: v for k, v in base_values.items() if k not in ("_CHECKSUM", "COUNTER")} if base_values else {}
values.update({
@@ -9,11 +9,9 @@ from opendbc.car.structs import CarControl, CarParams
from opendbc.car.fw_versions import build_fw_dict, match_fw_to_car
from opendbc.car.hyundai.carcontroller import CarController, Ioniq6LongitudinalTuningState, GenesisG90LongitudinalTuningState, \
get_canfd_lead_distance_setting, \
IONIQ_6_IPEDAL_PADDLE_BURST_COUNT, \
update_ioniq_6_longitudinal_tuning, \
update_genesis_g90_longitudinal_tuning
from opendbc.car.hyundai.carstate import CarState, decode_canfd_camera_lead, decode_ioniq_6_blindspot_radar_state, decode_ioniq_6_ipedal_intermediate_state, \
decode_ioniq_6_ipedal_state, decode_ioniq_6_max_regen_state
from opendbc.car.hyundai.carstate import CarState, decode_canfd_camera_lead, decode_ioniq_6_blindspot_radar_state
from opendbc.car.hyundai.interface import CarInterface
from opendbc.car.hyundai import hyundaican, hyundaicanfd
from opendbc.car.hyundai.hyundaicanfd import CanBus
@@ -57,7 +55,7 @@ CANFD_EXPECTED_ECUS = {Ecu.fwdCamera, Ecu.fwdRadar}
def get_test_toggles() -> SimpleNamespace:
return SimpleNamespace(always_ipedal=False, always_on_lateral_lkas=False, force_torque_controller=False, nnff=False, nnff_lite=False)
return SimpleNamespace(always_on_lateral_lkas=False, force_torque_controller=False, nnff=False, nnff_lite=False)
class TestHyundaiFingerprint:
@@ -316,258 +314,6 @@ class TestHyundaiFingerprint:
ret = update(0, 3)
assert any(be.type == ButtonType.altButton2 and not be.pressed for be in ret.buttonEvents)
def test_ioniq_6_ipedal_state_decode(self):
assert decode_ioniq_6_max_regen_state(0x3C, 0x01)
assert not decode_ioniq_6_ipedal_state(0x3C, 0x01)
assert not decode_ioniq_6_ipedal_state(0x50, 0x01)
assert decode_ioniq_6_ipedal_intermediate_state(0x50, 0x01)
assert decode_ioniq_6_ipedal_state(0x50, 0x03)
def test_ioniq_6_msla_regen_signals_decode(self):
CP = CarParams.new_message()
CP.carFingerprint = CAR.HYUNDAI_IONIQ_6
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CANFD_LKA_STEERING)
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
can_bus = CanBus(CP)
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("MANUAL_SPEED_LIMIT_ASSIST", 0)], can_bus.ECAN)
msg = packer.make_can_msg("MANUAL_SPEED_LIMIT_ASSIST", can_bus.ECAN, {
"MSLA_STATUS": 0,
"MSLA_ENABLED": 0,
"MAX_SPEED": 0,
"MAX_SPEED_COPY": 0,
"EV_REGEN_STATE": 0x50,
"EV_REGEN_STATE_2": 0x03,
})
parser.update([(1, [msg])])
assert parser.can_valid
assert parser.vl["MANUAL_SPEED_LIMIT_ASSIST"]["EV_REGEN_STATE"] == 0x50
assert parser.vl["MANUAL_SPEED_LIMIT_ASSIST"]["EV_REGEN_STATE_2"] == 0x03
@pytest.mark.parametrize(("counter", "expected_hex"), [
(0, "2100002800000000"),
(7, "2970002800000000"),
(14, "31e0002800000000"),
])
def test_ioniq_6_left_paddle_message_matches_stock(self, counter, expected_hex):
CP = CarParams.new_message()
CP.carFingerprint = CAR.HYUNDAI_IONIQ_6
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CANFD_LKA_STEERING)
msg = hyundaicanfd.create_ioniq_6_paddle_buttons(CANPacker(DBC[CP.carFingerprint][Bus.pt]), CP, CanBus(CP),
counter, left_paddle=True)
assert msg[1].hex() == expected_hex
def test_ioniq_6_buttons_counter_wraps_like_stock(self):
assert hyundaicanfd.get_ioniq_6_cruise_buttons_next_counter(13) == 14
assert hyundaicanfd.get_ioniq_6_cruise_buttons_next_counter(14) == 0
@pytest.mark.parametrize(("stock_hex", "expected_tail"), [
("45421440801f000000000000a865170000a000000080c071a80c120e00000000", bytes.fromhex("c00c1200")),
("47745840801f0000000005006e5e0e0000a000000080c071a80e070e00000000", bytes.fromhex("850e070c")),
("7aea8140801f000000000000b965140000a000000080c0711810070200000000", bytes.fromhex("b5100700")),
("32438340801f000000000000b965140000a000000080c071a810070e00000000", bytes.fromhex("b5100700")),
])
def test_ioniq_6_regen_control_message_preserves_stock_frame_and_flips_only_ipedal_request_bytes(self, stock_hex, expected_tail):
CP = CarParams.new_message()
CP.carFingerprint = CAR.HYUNDAI_IONIQ_6
CP.flags = int(HyundaiFlags.CANFD | HyundaiFlags.CANFD_LKA_STEERING)
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
can_bus = CanBus(CP)
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("IONIQ_6_REGEN_CONTROL", 0)], can_bus.ECAN)
stock_dat = bytes.fromhex(stock_hex)
parser.update([(1, [(0x25A, stock_dat, can_bus.ECAN)])])
msg = hyundaicanfd.create_ioniq_6_regen_control(packer, CP, can_bus, parser.vl["IONIQ_6_REGEN_CONTROL"])
assert msg[1][2:24] == stock_dat[2:24]
assert msg[1][24:28] == expected_tail
assert msg[1][28:] == stock_dat[28:]
checksum = hyundaicanfd.hkg_can_fd_checksum(msg[0], None, bytearray(msg[1]))
assert msg[1][0] | (msg[1][1] << 8) == checksum
def test_ioniq_6_always_ipedal_spoofs_left_paddle_in_startup_park_and_drive_until_latched(self):
toggles = get_test_toggles()
toggles.always_ipedal = True
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, gen_empty_fingerprint(), [], True, False, False, toggles)
controller = CarController(DBC[CP.carFingerprint], CP)
can_bus = CanBus(CP)
parser_bus = can_bus.ECAN if CP.flags & HyundaiFlags.CANFD_LKA_STEERING else can_bus.CAM
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [("CRUISE_BUTTONS", 0)], parser_bus)
cs = SimpleNamespace(
out=SimpleNamespace(gearShifter=structs.CarState.GearShifter.park),
ipedal_active=False,
buttons_counter=5,
cruise_buttons_msg={
"_CHECKSUM": 0,
"COUNTER": 5,
"CRUISE_BUTTONS": 0,
"ADAPTIVE_CRUISE_MAIN_BTN": 0,
"NORMAL_CRUISE_MAIN_BTN": 0,
"LDA_BTN": 0,
"RIGHT_PADDLE": 0,
"LEFT_PADDLE": 0,
"SET_ME_1": 1,
},
ioniq_6_regen_control_msg={},
ioniq_6_regen_control_ts=0,
)
cc = SimpleNamespace(enabled=False)
sends = controller._update_ioniq_6_always_ipedal(cc, cs, toggles)
parser.update([(1, sends)])
assert sends
assert len([msg for msg in sends if msg[0] == 0x1CF]) == IONIQ_6_IPEDAL_PADDLE_BURST_COUNT
assert sends[0][1].hex() == "4650002800000000"
assert parser.vl["CRUISE_BUTTONS"]["LEFT_PADDLE"] == 1
assert parser.vl["CRUISE_BUTTONS"]["COUNTER"] == 5
assert controller._ioniq_6_always_ipedal_pending
assert not controller._ioniq_6_always_ipedal_startup_park_done
controller.frame = 1
sends = controller._update_ioniq_6_always_ipedal(cc, cs, toggles)
assert sends == []
controller.frame = 2
cs.out.gearShifter = structs.CarState.GearShifter.drive
cs.buttons_counter = 6
sends = controller._update_ioniq_6_always_ipedal(cc, cs, toggles)
assert sends
assert len([msg for msg in sends if msg[0] == 0x1CF]) == IONIQ_6_IPEDAL_PADDLE_BURST_COUNT
assert sends[0][1].hex() == "9060002800000000"
assert controller._ioniq_6_always_ipedal_pending
assert controller._ioniq_6_always_ipedal_startup_park_done
controller.frame = 4
cs.ipedal_active = True
sends = controller._update_ioniq_6_always_ipedal(cc, cs, toggles)
assert sends == []
assert not controller._ioniq_6_always_ipedal_pending
assert controller._ioniq_6_always_ipedal_press_remaining == 0
def test_ioniq_6_always_ipedal_uses_stronger_followup_pull_for_intermediate_latch_state(self):
toggles = get_test_toggles()
toggles.always_ipedal = True
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, gen_empty_fingerprint(), [], True, False, False, toggles)
controller = CarController(DBC[CP.carFingerprint], CP)
cs = SimpleNamespace(
out=SimpleNamespace(gearShifter=structs.CarState.GearShifter.drive),
ipedal_active=False,
ipedal_regen_state=0x50,
ipedal_regen_state_2=0x01,
buttons_counter=5,
cruise_buttons_msg={
"_CHECKSUM": 0,
"COUNTER": 5,
"CRUISE_BUTTONS": 0,
"ADAPTIVE_CRUISE_MAIN_BTN": 0,
"NORMAL_CRUISE_MAIN_BTN": 0,
"LDA_BTN": 0,
"RIGHT_PADDLE": 0,
"LEFT_PADDLE": 0,
"SET_ME_1": 1,
},
ioniq_6_regen_control_msg={},
ioniq_6_regen_control_ts=0,
)
cc = SimpleNamespace(enabled=False)
controller._ioniq_6_last_gear = structs.CarState.GearShifter.reverse
sends = controller._update_ioniq_6_always_ipedal(cc, cs, toggles)
assert sends
assert [msg[1].hex() for msg in sends if msg[0] == 0x1CF] == ["4650002800000000"]
assert controller._ioniq_6_always_ipedal_press_remaining == 5
def test_ioniq_6_always_ipedal_sends_regen_control_companion_once_max_regen_is_shown(self):
toggles = get_test_toggles()
toggles.always_ipedal = True
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, gen_empty_fingerprint(), [], True, False, False, toggles)
controller = CarController(DBC[CP.carFingerprint], CP)
cs = SimpleNamespace(
out=SimpleNamespace(gearShifter=structs.CarState.GearShifter.drive),
ipedal_active=False,
ipedal_regen_state=0x3C,
ipedal_regen_state_2=0x01,
buttons_counter=5,
cruise_buttons_msg={
"_CHECKSUM": 0,
"COUNTER": 5,
"CRUISE_BUTTONS": 0,
"ADAPTIVE_CRUISE_MAIN_BTN": 0,
"NORMAL_CRUISE_MAIN_BTN": 0,
"LDA_BTN": 0,
"RIGHT_PADDLE": 0,
"LEFT_PADDLE": 0,
"SET_ME_1": 1,
},
ioniq_6_regen_control_msg={
"COUNTER": 0x14,
"BYTE3": 0x40,
"BYTE4": 0x80,
"BYTE5": 0x1F,
"BYTE6": 0x00,
"BYTE7": 0x00,
"BYTE8": 0x00,
"BYTE9": 0x00,
"BYTE10": 0x00,
"BYTE11": 0x00,
"BYTE12": 0xA8,
"BYTE13": 0x65,
"BYTE14": 0x17,
"BYTE15": 0x00,
"BYTE16": 0x00,
"BYTE17": 0xA0,
"BYTE18": 0x00,
"BYTE19": 0x00,
"BYTE20": 0x00,
"BYTE21": 0x80,
"BYTE22": 0xC0,
"BYTE23": 0x71,
"BYTE24": 0xA8,
"BYTE25": 0x0C,
"BYTE26": 0x12,
"BYTE27": 0x0E,
"BYTE28": 0x00,
"BYTE29": 0x00,
"BYTE30": 0x00,
"BYTE31": 0x00,
},
ioniq_6_regen_control_ts=1,
)
cc = SimpleNamespace(enabled=False)
controller._ioniq_6_last_gear = structs.CarState.GearShifter.reverse
controller._ioniq_6_last_regen_control_counter = 0x13
sends = controller._update_ioniq_6_always_ipedal(cc, cs, toggles)
paddle_msgs = [msg for msg in sends if msg[0] == 0x1CF]
assert [msg[1].hex() for msg in paddle_msgs] == ["4650002800000000"]
regen_cmd = next(msg for msg in sends if msg[0] == 0x25A)
assert regen_cmd[1][24:28] == bytes.fromhex("c00c1200")
checksum = hyundaicanfd.hkg_can_fd_checksum(regen_cmd[0], None, bytearray(regen_cmd[1]))
assert regen_cmd[1][0] | (regen_cmd[1][1] << 8) == checksum
assert controller._ioniq_6_always_ipedal_press_remaining == 5
controller.frame = 1
cs.buttons_counter = 6
cs.ioniq_6_regen_control_msg = dict(cs.ioniq_6_regen_control_msg, COUNTER=0x15)
sends = controller._update_ioniq_6_always_ipedal(cc, cs, toggles)
paddle_msgs = [msg for msg in sends if msg[0] == 0x1CF]
assert [msg[1].hex() for msg in paddle_msgs] == ["9060002800000000"]
assert not any(msg[0] == 0x25A for msg in sends)
def test_ioniq_6_longitudinal_params_match_canfd_tune(self):
toggles = get_test_toggles()
CP = CarInterface.get_params(CAR.HYUNDAI_IONIQ_6, gen_empty_fingerprint(), [], True, False, False, toggles)
@@ -125,7 +125,6 @@ class HyundaiSafetyFlags(IntFlag):
class HyundaiStarPilotSafetyFlags(IntFlag):
HAS_LDA_BUTTON = 1024
AOL_LKAS_ON_ENGAGE = 2048
ALLOW_IPEDAL_PADDLE = 32768
class HyundaiStarPilotFlags(IntFlag):
-3
View File
@@ -232,9 +232,6 @@ class CarInterfaceBase(ABC):
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.HAS_LDA_BUTTON.value
if starpilot_toggles.always_on_lateral_lkas:
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value
if candidate == HYUNDAI.HYUNDAI_IONIQ_6 and getattr(starpilot_toggles, "always_ipedal", False):
fp_ret.safetyConfigs[-1].safetyParam |= HyundaiStarPilotSafetyFlags.ALLOW_IPEDAL_PADDLE.value
elif platform in TOYOTA:
fp_ret.canUsePedal = not CP.autoResumeSng
fp_ret.canUseSDSU = candidate not in UNSUPPORTED_DSU_CAR and candidate not in TSS2_CAR
@@ -64,7 +64,6 @@ class DummyCarInterface(CarInterfaceBase):
def get_test_starpilot_toggles() -> SimpleNamespace:
return SimpleNamespace(
always_ipedal=False,
always_on_lateral_lkas=False,
car_model="",
cluster_offset=1.0,
@@ -215,31 +214,6 @@ class TestCarInterfaces:
)
assert fp_car_params.safetyConfigs[-1].safetyParam & HyundaiStarPilotSafetyFlags.AOL_LKAS_ON_ENGAGE.value
def test_hyundai_always_ipedal_flag_is_set_for_ioniq_6(self):
toggles = get_test_starpilot_toggles()
toggles.always_ipedal = True
fingerprint = {bus: {} for bus in range(8)}
fingerprint[2][0x50] = 16
car_params = HyundaiCarInterface.get_params(
HYUNDAI_CAR.HYUNDAI_IONIQ_6,
fingerprint,
[],
alpha_long=False,
is_release=False,
docs=False,
starpilot_toggles=toggles,
)
fp_car_params = HyundaiCarInterface.get_starpilot_params(
HYUNDAI_CAR.HYUNDAI_IONIQ_6,
fingerprint,
[],
car_params,
toggles,
)
assert fp_car_params.safetyConfigs[-1].safetyParam & HyundaiStarPilotSafetyFlags.ALLOW_IPEDAL_PADDLE.value
def test_toyota_disable_openpilot_long_sets_stock_long_safety_flag(self):
CarInterface = interfaces[TOYOTA_CAR.TOYOTA_PRIUS_TSS2]
fingerprint = {bus: {} for bus in range(8)}
@@ -537,39 +537,6 @@ 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
BO_ 602 IONIQ_6_REGEN_CONTROL: 32 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE3 : 24|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE4 : 32|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE5 : 40|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE6 : 48|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE7 : 56|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE8 : 64|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE9 : 72|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE10 : 80|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE11 : 88|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE12 : 96|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE13 : 104|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE14 : 112|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE15 : 120|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE16 : 128|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE17 : 136|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE18 : 144|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE19 : 152|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE20 : 160|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE21 : 168|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE22 : 176|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE23 : 184|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE24 : 192|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE25 : 200|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE26 : 208|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE27 : 216|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE28 : 224|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE29 : 232|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE30 : 240|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE31 : 248|8@1+ (1,0) [0|255] "" XXX
BO_ 687 HOD_FD_01_100ms: 8 XXX
SG_ HOD_Dir_Status : 18|3@0+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_2 : 32|8@1+ (1,0) [0|255] "" XXX
@@ -620,8 +587,6 @@ BO_ 736 MANUAL_SPEED_LIMIT_ASSIST: 32 XXX
SG_ MSLA_ENABLED : 38|1@1+ (1,0) [0|1] "" XXX
SG_ MAX_SPEED : 55|8@0+ (1,0) [0|255] "" XXX
SG_ MAX_SPEED_COPY : 144|8@1+ (1,0) [0|255] "" XXX
SG_ EV_REGEN_STATE : 104|8@1+ (1,0) [0|255] "" XXX
SG_ EV_REGEN_STATE_2 : 184|8@1+ (1,0) [0|255] "" XXX
BO_ 837 ADRV_0x345: 8 ADRV
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
@@ -774,39 +774,6 @@ 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
BO_ 602 IONIQ_6_REGEN_CONTROL: 32 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE3 : 24|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE4 : 32|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE5 : 40|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE6 : 48|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE7 : 56|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE8 : 64|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE9 : 72|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE10 : 80|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE11 : 88|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE12 : 96|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE13 : 104|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE14 : 112|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE15 : 120|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE16 : 128|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE17 : 136|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE18 : 144|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE19 : 152|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE20 : 160|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE21 : 168|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE22 : 176|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE23 : 184|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE24 : 192|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE25 : 200|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE26 : 208|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE27 : 216|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE28 : 224|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE29 : 232|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE30 : 240|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE31 : 248|8@1+ (1,0) [0|255] "" XXX
BO_ 687 HOD_FD_01_100ms: 8 XXX
SG_ HOD_Dir_Status : 18|3@0+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_2 : 32|8@1+ (1,0) [0|255] "" XXX
@@ -857,8 +824,6 @@ BO_ 736 MANUAL_SPEED_LIMIT_ASSIST: 32 XXX
SG_ MSLA_ENABLED : 38|1@1+ (1,0) [0|1] "" XXX
SG_ MAX_SPEED : 55|8@0+ (1,0) [0|255] "" XXX
SG_ MAX_SPEED_COPY : 144|8@1+ (1,0) [0|255] "" XXX
SG_ EV_REGEN_STATE : 104|8@1+ (1,0) [0|255] "" XXX
SG_ EV_REGEN_STATE_2 : 184|8@1+ (1,0) [0|255] "" XXX
BO_ 837 ADRV_0x345: 8 ADRV
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
@@ -6,9 +6,6 @@
#define HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(bus) \
{0x1CF, bus, 8, .check_relay = false}, /* CRUISE_BUTTON */ \
#define HYUNDAI_CANFD_IPEDAL_REGEN_TX_MSGS(bus) \
{0x25A, bus, 32, .check_relay = false}, /* IONIQ_6_REGEN_CONTROL */ \
#define HYUNDAI_CANFD_LKA_STEERING_COMMON_TX_MSGS(a_can, e_can) \
HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(e_can) \
{0x50, a_can, 16, .check_relay = (a_can) == 0}, /* LKAS */ \
@@ -59,9 +56,6 @@
static bool hyundai_canfd_alt_buttons = false;
static bool hyundai_canfd_lka_steering_alt = false;
static bool hyundai_canfd_angle_steering = false;
static bool hyundai_canfd_allow_ipedal_paddle = false;
static bool hyundai_canfd_last_regen_control_seen = false;
static uint8_t hyundai_canfd_last_regen_control[32] = {0U};
static unsigned int hyundai_canfd_get_lka_addr(void) {
return hyundai_canfd_lka_steering_alt ? 0x110U : 0x50U;
@@ -82,44 +76,8 @@ static uint32_t hyundai_canfd_get_checksum(const CANPacket_t *msg) {
return chksum;
}
static bool hyundai_canfd_ioniq_6_regen_tail_allowed(const CANPacket_t *msg) {
const uint8_t stock24 = hyundai_canfd_last_regen_control[24];
const uint8_t stock25 = hyundai_canfd_last_regen_control[25];
const uint8_t stock26 = hyundai_canfd_last_regen_control[26];
const uint8_t stock27 = hyundai_canfd_last_regen_control[27];
if ((stock24 == 0xA8U) && (stock25 == 0x0CU) && (stock26 == 0x12U) && (stock27 == 0x0EU)) {
return (msg->data[24] == 0xC0U) && (msg->data[25] == 0x0CU) &&
(msg->data[26] == 0x12U) && (msg->data[27] == 0x00U);
}
if ((stock24 == 0xA8U) && (stock25 == 0x0EU) && (stock26 == 0x07U) && (stock27 == 0x0EU)) {
return (msg->data[24] == 0x85U) && (msg->data[25] == 0x0EU) &&
(msg->data[26] == 0x07U) && (msg->data[27] == 0x0CU);
}
if ((stock24 == 0x18U) && (stock25 == 0x10U) && (stock26 == 0x07U) && (stock27 == 0x02U)) {
return (msg->data[24] == 0xB5U) && (msg->data[25] == 0x10U) &&
(msg->data[26] == 0x07U) && (msg->data[27] == 0x00U);
}
if ((stock24 == 0xA8U) && (stock25 == 0x10U) && (stock26 == 0x07U) && (stock27 == 0x0EU)) {
return (msg->data[24] == 0xB5U) && (msg->data[25] == 0x10U) &&
(msg->data[26] == 0x07U) && (msg->data[27] == 0x00U);
}
return false;
}
static void hyundai_canfd_rx_all_hook(const CANPacket_t *msg) {
const unsigned pt_bus = hyundai_canfd_lka_steering ? 1U : 0U;
if (hyundai_canfd_allow_ipedal_paddle && (msg->bus == pt_bus) && (msg->addr == 0x25AU) && (GET_LEN(msg) == 32U)) {
for (int i = 0; i < 32; i++) {
hyundai_canfd_last_regen_control[i] = msg->data[i];
}
hyundai_canfd_last_regen_control_seen = true;
}
UNUSED(msg);
}
static void hyundai_canfd_rx_hook(const CANPacket_t *msg) {
@@ -274,47 +232,10 @@ static bool hyundai_canfd_tx_hook(const CANPacket_t *msg) {
// cruise buttons check
if (msg->addr == 0x1cfU) {
int button = msg->data[2] & 0x7U;
bool main_button = GET_BIT(msg, 19U) || GET_BIT(msg, 21U);
bool lkas_button = GET_BIT(msg, 23U);
bool right_paddle = GET_BIT(msg, 25U);
bool left_paddle = GET_BIT(msg, 27U);
bool is_cancel = (button == HYUNDAI_BTN_CANCEL);
bool is_resume = (button == HYUNDAI_BTN_RESUME);
bool is_left_paddle_only = hyundai_canfd_allow_ipedal_paddle &&
!controls_allowed &&
(button == HYUNDAI_BTN_NONE) &&
!main_button &&
!lkas_button &&
!right_paddle &&
left_paddle;
bool allowed = (is_cancel && cruise_engaged_prev) || (is_resume && controls_allowed) || is_left_paddle_only;
if (!allowed) {
tx = false;
}
}
if (msg->addr == 0x25AU) {
const unsigned pt_bus = hyundai_canfd_lka_steering ? 1U : 0U;
bool allowed = hyundai_canfd_allow_ipedal_paddle &&
!controls_allowed &&
(msg->bus == pt_bus) &&
(GET_LEN(msg) == 32U) &&
hyundai_canfd_last_regen_control_seen &&
(hyundai_canfd_get_checksum(msg) == hyundai_common_canfd_compute_checksum(msg)) &&
hyundai_canfd_ioniq_6_regen_tail_allowed(msg);
if (allowed) {
for (int i = 2; i < 32; i++) {
if ((i < 24) || (i > 27)) {
if (msg->data[i] != hyundai_canfd_last_regen_control[i]) {
allowed = false;
break;
}
}
}
}
bool allowed = (is_cancel && cruise_engaged_prev) || (is_resume && controls_allowed);
if (!allowed) {
tx = false;
}
@@ -361,26 +282,15 @@ static safety_config hyundai_canfd_init(uint16_t param) {
const uint16_t HYUNDAI_PARAM_CANFD_LKA_STEERING_ALT = 128;
const uint16_t HYUNDAI_PARAM_CANFD_ALT_BUTTONS = 32;
const uint16_t HYUNDAI_PARAM_CANFD_ANGLE_STEERING = 1024;
const uint16_t HYUNDAI_PARAM_ALLOW_IPEDAL_PADDLE = 32768;
static const CanMsg HYUNDAI_CANFD_LKA_STEERING_TX_MSGS[] = {
HYUNDAI_CANFD_LKA_STEERING_COMMON_TX_MSGS(0, 1)
};
static const CanMsg HYUNDAI_CANFD_LKA_STEERING_IPEDAL_TX_MSGS[] = {
HYUNDAI_CANFD_LKA_STEERING_COMMON_TX_MSGS(0, 1)
HYUNDAI_CANFD_IPEDAL_REGEN_TX_MSGS(1)
};
static const CanMsg HYUNDAI_CANFD_LKA_STEERING_ALT_TX_MSGS[] = {
HYUNDAI_CANFD_LKA_STEERING_ALT_COMMON_TX_MSGS(0, 1)
};
static const CanMsg HYUNDAI_CANFD_LKA_STEERING_ALT_IPEDAL_TX_MSGS[] = {
HYUNDAI_CANFD_LKA_STEERING_ALT_COMMON_TX_MSGS(0, 1)
HYUNDAI_CANFD_IPEDAL_REGEN_TX_MSGS(1)
};
static const CanMsg HYUNDAI_CANFD_LKA_STEERING_LONG_TX_MSGS[] = {
HYUNDAI_CANFD_LKA_STEERING_COMMON_TX_MSGS(0, 1)
HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(1)
@@ -395,21 +305,6 @@ static safety_config hyundai_canfd_init(uint16_t param) {
{0x1DA, 1, 32, .check_relay = false}, // ADRV_0x1da
};
static const CanMsg HYUNDAI_CANFD_LKA_STEERING_LONG_IPEDAL_TX_MSGS[] = {
HYUNDAI_CANFD_LKA_STEERING_COMMON_TX_MSGS(0, 1)
HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(1)
HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(1, true)
HYUNDAI_CANFD_BLINDSPOT_DASH_TX_MSGS(1)
HYUNDAI_CANFD_IPEDAL_REGEN_TX_MSGS(1)
{0x51, 0, 32, .check_relay = false}, // ADRV_0x51
{0x730, 1, 8, .check_relay = false}, // tester present for ADAS ECU disable
{0x160, 1, 16, .check_relay = false}, // ADRV_0x160
{0x1EA, 1, 32, .check_relay = false}, // ADRV_0x1ea
{0x200, 1, 8, .check_relay = false}, // ADRV_0x200
{0x345, 1, 8, .check_relay = false}, // ADRV_0x345
{0x1DA, 1, 32, .check_relay = false}, // ADRV_0x1da
};
static const CanMsg HYUNDAI_CANFD_LFA_STEERING_TX_MSGS[] = {
HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(2)
HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(0)
@@ -439,8 +334,6 @@ static safety_config hyundai_canfd_init(uint16_t param) {
hyundai_canfd_alt_buttons = GET_FLAG(param, HYUNDAI_PARAM_CANFD_ALT_BUTTONS);
hyundai_canfd_lka_steering_alt = GET_FLAG(param, HYUNDAI_PARAM_CANFD_LKA_STEERING_ALT);
hyundai_canfd_angle_steering = GET_FLAG(param, HYUNDAI_PARAM_CANFD_ANGLE_STEERING);
hyundai_canfd_allow_ipedal_paddle = GET_FLAG(param, HYUNDAI_PARAM_ALLOW_IPEDAL_PADDLE);
hyundai_canfd_last_regen_control_seen = false;
safety_config ret;
if (hyundai_longitudinal) {
@@ -450,11 +343,7 @@ static safety_config hyundai_canfd_init(uint16_t param) {
};
SET_RX_CHECKS(hyundai_canfd_lka_steering_long_rx_checks, ret);
if (hyundai_canfd_allow_ipedal_paddle) {
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_LONG_IPEDAL_TX_MSGS, ret);
} else {
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_LONG_TX_MSGS, ret);
}
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_LONG_TX_MSGS, ret);
} else {
// Longitudinal checks for LFA steering
@@ -496,17 +385,9 @@ static safety_config hyundai_canfd_init(uint16_t param) {
SET_RX_CHECKS(hyundai_canfd_lka_steering_rx_checks, ret);
if (hyundai_canfd_lka_steering_alt) {
if (hyundai_canfd_allow_ipedal_paddle) {
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_ALT_IPEDAL_TX_MSGS, ret);
} else {
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_ALT_TX_MSGS, ret);
}
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_ALT_TX_MSGS, ret);
} else {
if (hyundai_canfd_allow_ipedal_paddle) {
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_IPEDAL_TX_MSGS, ret);
} else {
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_TX_MSGS, ret);
}
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_TX_MSGS, ret);
}
} else if (!hyundai_camera_scc) {
@@ -440,112 +440,12 @@ class TestHyundaiCanfdLKASteeringEV(TestHyundaiCanfdBase):
}
return self.packer.make_can_msg_safety("CRUISE_BUTTONS", bus, values)
def _regen_control_msg(self, byte24=0xA8, byte25=0x0C, byte26=0x12, byte27=0x0E, counter=0x14, bus=None):
if bus is None:
bus = self.PT_BUS
values = {
"COUNTER": counter,
"BYTE3": 0x40,
"BYTE4": 0x80,
"BYTE5": 0x1F,
"BYTE6": 0x00,
"BYTE7": 0x00,
"BYTE8": 0x00,
"BYTE9": 0x00,
"BYTE10": 0x00,
"BYTE11": 0x00,
"BYTE12": 0xA8,
"BYTE13": 0x65,
"BYTE14": 0x17,
"BYTE15": 0x00,
"BYTE16": 0x00,
"BYTE17": 0xA0,
"BYTE18": 0x00,
"BYTE19": 0x00,
"BYTE20": 0x00,
"BYTE21": 0x80,
"BYTE22": 0xC0,
"BYTE23": 0x71,
"BYTE24": byte24,
"BYTE25": byte25,
"BYTE26": byte26,
"BYTE27": byte27,
"BYTE28": 0x00,
"BYTE29": 0x00,
"BYTE30": 0x00,
"BYTE31": 0x00,
}
def fix_checksum(msg):
addr, dat, msg_bus = msg
dat = bytearray(dat)
checksum = hyundaicanfd.hkg_can_fd_checksum(addr, None, dat)
dat[0] = checksum & 0xFF
dat[1] = (checksum >> 8) & 0xFF
return addr, bytes(dat), msg_bus
return self.packer.make_can_msg_safety("IONIQ_6_REGEN_CONTROL", bus, values, fix_checksum=fix_checksum)
def test_left_paddle_send(self):
for controls_allowed in (True, False):
self.safety.set_controls_allowed(controls_allowed)
self.assertFalse(self._tx(self._paddle_msg(left_paddle=1)))
class TestHyundaiCanfdLKASteeringEVAlwaysIPedal(TestHyundaiCanfdLKASteeringEV):
TX_MSGS = TestHyundaiCanfdLKASteeringEV.TX_MSGS + [[0x25A, 1]]
def setUp(self):
self.packer = CANPackerSafety("hyundai_canfd_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd,
HyundaiSafetyFlags.CANFD_LKA_STEERING |
HyundaiSafetyFlags.EV_GAS |
HyundaiStarPilotSafetyFlags.ALLOW_IPEDAL_PADDLE)
self.safety.init_tests()
def test_left_paddle_send(self):
self.safety.set_controls_allowed(False)
self.assertTrue(self._tx(self._paddle_msg(left_paddle=1)))
self.assertFalse(self._tx(self._paddle_msg(right_paddle=1)))
self.assertFalse(self._tx(self._paddle_msg(left_paddle=1, buttons=1)))
self.assertFalse(self._tx(self._paddle_msg(left_paddle=1, main_button=1)))
self.assertFalse(self._tx(self._paddle_msg(left_paddle=1, lka_button=1)))
self.safety.set_controls_allowed(True)
self.assertFalse(self._tx(self._paddle_msg(left_paddle=1)))
def test_regen_control_send(self):
stock_msg = self._regen_control_msg(byte24=0xA8, byte27=0x0E, counter=0x14)
self._rx(stock_msg)
self.safety.set_controls_allowed(False)
self.assertTrue(self._tx(self._regen_control_msg(byte24=0xC0, byte27=0x00, counter=0x14)))
self.assertFalse(self._tx(self._regen_control_msg(byte24=0x85, byte25=0x0E, byte26=0x07, byte27=0x0C, counter=0x14)))
self.assertFalse(self._tx(self._regen_control_msg(byte24=0xA8, byte27=0x00, counter=0x14)))
self.assertFalse(self._tx(self._regen_control_msg(byte24=0xC0, byte27=0x0E, counter=0x14)))
self.assertFalse(self._tx(self._regen_control_msg(byte24=0xC0, byte27=0x00, counter=0x15)))
stock_msg = self._regen_control_msg(byte24=0xA8, byte25=0x0E, byte26=0x07, byte27=0x0E, counter=0x58)
self._rx(stock_msg)
self.assertTrue(self._tx(self._regen_control_msg(byte24=0x85, byte25=0x0E, byte26=0x07, byte27=0x0C, counter=0x58)))
self.assertFalse(self._tx(self._regen_control_msg(byte24=0xC0, byte25=0x0E, byte26=0x07, byte27=0x00, counter=0x58)))
stock_msg = self._regen_control_msg(byte24=0x18, byte25=0x10, byte26=0x07, byte27=0x02, counter=0x81)
self._rx(stock_msg)
self.assertTrue(self._tx(self._regen_control_msg(byte24=0xB5, byte25=0x10, byte26=0x07, byte27=0x00, counter=0x81)))
self.assertFalse(self._tx(self._regen_control_msg(byte24=0xA8, byte25=0x10, byte26=0x07, byte27=0x00, counter=0x81)))
stock_msg = self._regen_control_msg(byte24=0xA8, byte25=0x10, byte26=0x07, byte27=0x0E, counter=0x82)
self._rx(stock_msg)
self.assertTrue(self._tx(self._regen_control_msg(byte24=0xB5, byte25=0x10, byte26=0x07, byte27=0x00, counter=0x82)))
self.assertFalse(self._tx(self._regen_control_msg(byte24=0xA8, byte25=0x02, byte26=0x07, byte27=0x0E, counter=0x82)))
self.safety.set_controls_allowed(True)
self.assertFalse(self._tx(self._regen_control_msg(byte24=0xC0, byte27=0x00, counter=0x14)))
# TODO: Handle ICE and HEV configurations once we see cars that use the new messages
class TestHyundaiCanfdLKASteeringAltEV(TestHyundaiCanfdBase):
@@ -596,26 +496,6 @@ class TestHyundaiCanfdLKASteeringLongEV(HyundaiLongitudinalBase, TestHyundaiCanf
return self.packer.make_can_msg_safety("SCC_CONTROL", 1, values)
class TestHyundaiCanfdLKASteeringLongEVAlwaysIPedal(TestHyundaiCanfdLKASteeringLongEV):
TX_MSGS = TestHyundaiCanfdLKASteeringLongEV.TX_MSGS + [[0x25A, 1]]
def setUp(self):
self.packer = CANPackerSafety("hyundai_canfd_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, HyundaiSafetyFlags.CANFD_LKA_STEERING |
HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.EV_GAS |
HyundaiStarPilotSafetyFlags.ALLOW_IPEDAL_PADDLE)
self.safety.init_tests()
def test_regen_control_send(self):
stock_msg = self._regen_control_msg(byte24=0xA8, byte27=0x0E, counter=0x14)
self._rx(stock_msg)
self.safety.set_controls_allowed(False)
self.assertTrue(self._tx(self._regen_control_msg(byte24=0xC0, byte27=0x00, counter=0x14)))
# Tests longitudinal for ICE, hybrid, EV cars with LFA steering
class TestHyundaiCanfdLFASteeringLongBase(HyundaiLongitudinalBase, TestHyundaiCanfdLFASteeringBase):
@@ -471,11 +471,6 @@ class VehicleSettingsManagerView(Widget):
rows.append({"target_id": "toggle:RemapCancelToDistance", "type": "toggle",
"title": tr("Remap Cancel Button"), "subtitle": tr("Treat the Cancel button as an extra mappable steering-wheel button."),
"get_state": lambda: self._controller._params.get_bool("RemapCancelToDistance")})
if cs.isHKGCanFd:
rows.append({"target_id": "toggle:AlwaysIPedal", "type": "toggle",
"title": tr("Always I-Pedal"),
"subtitle": tr("Spoof the left paddle after shifting into Drive until i-Pedal latches."),
"get_state": lambda: self._controller._params.get_bool("AlwaysIPedal")})
if cs.isHKGCanFd and cs.hasOpenpilotLongitudinal:
rows.append({"target_id": "toggle:NostalgiaMode", "type": "toggle",
"title": tr("Nostalgia Mode"),
-1
View File
@@ -800,7 +800,6 @@ class StarPilotVariables:
toggle.no_uploads = self.get_value("NoUploads", condition=device_management and not self.vetting_branch)
toggle.no_onroad_uploads = self.get_value("DisableOnroadUploads", condition=toggle.no_uploads)
toggle.always_ipedal = self.get_value("AlwaysIPedal", condition=toggle.car_model == HYUNDAI_CAR.HYUNDAI_IONIQ_6)
toggle.nostalgia_mode = self.get_value("NostalgiaMode", condition=toggle.openpilot_longitudinal and toggle.car_model == HYUNDAI_CAR.HYUNDAI_IONIQ_6)
toggle.remap_cancel_to_distance = self.get_value(
"RemapCancelToDistance",
@@ -2323,13 +2323,6 @@
"data_type": "bool",
"ui_type": "toggle"
},
{
"key": "AlwaysIPedal",
"label": "Always I-Pedal",
"description": "Automatically spoof the left paddle when shifting into Drive until i-Pedal latches on supported Hyundai CAN-FD cars.",
"data_type": "bool",
"ui_type": "toggle"
},
{
"key": "NostalgiaMode",
"label": "Nostalgia Mode",
-19
View File
@@ -55,21 +55,6 @@ StarPilotWheelPanel::StarPilotWheelPanel(StarPilotSettingsWindow *parent, bool f
update();
});
ParamControl *alwaysIPedalToggle = new ParamControl(
"AlwaysIPedal",
tr("Always I-Pedal"),
tr("<b>Automatically spoof the left paddle when shifting into Drive</b> until i-Pedal latches on supported Hyundai CAN-FD cars."),
"../../starpilot/assets/toggle_icons/icon_mute.png"
);
toggles["AlwaysIPedal"] = alwaysIPedalToggle;
addItem(alwaysIPedalToggle);
QObject::connect(alwaysIPedalToggle, &AbstractControl::hideDescriptionEvent, [this]() {
update();
});
QObject::connect(alwaysIPedalToggle, &AbstractControl::showDescriptionEvent, [this]() {
update();
});
const std::vector<std::tuple<QString, QString, QString, QString>> wheelToggles {
{"CancelButtonControl", tr("Cancel Button"), tr("<b>Action performed when the remapped \"Cancel\" button is pressed.</b>"), "../../starpilot/assets/toggle_icons/icon_mute.png"},
{"DistanceButtonControl", tr("Distance Button"), tr("<b>Action performed when the \"Distance\" button is pressed.</b>"), "../../starpilot/assets/toggle_icons/icon_mute.png"},
@@ -150,10 +135,6 @@ void StarPilotWheelPanel::updateToggles() {
setVisible &= parent->hasOpenpilotLongitudinal;
}
if (!showAllToggles && key == "AlwaysIPedal") {
setVisible &= parent->isHKGCanFd;
}
if (!showAllToggles && (
key == "ModeButtonControl" ||
key == "LongModeButtonControl" ||