mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-07-03 04:22:09 +08:00
peedle
This commit is contained in:
@@ -55,6 +55,8 @@ IONIQ_6_STOP_RELEASE_JERK_V = [3.6 * IONIQ_6_RESPONSE_MULTIPLIER,
|
||||
4.8 * IONIQ_6_RESPONSE_MULTIPLIER]
|
||||
IONIQ_6_IPEDAL_PRESS_SEND_COUNT = 6
|
||||
IONIQ_6_IPEDAL_LATCH_PRESS_SEND_COUNT = 10
|
||||
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
|
||||
@@ -248,6 +250,7 @@ class CarController(CarControllerBase):
|
||||
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_last_gear = structs.CarState.GearShifter.unknown
|
||||
self._genesis_g90_long_tuning = GenesisG90LongitudinalTuningState()
|
||||
|
||||
@@ -270,6 +273,7 @@ class CarController(CarControllerBase):
|
||||
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
|
||||
|
||||
@@ -277,8 +281,13 @@ class CarController(CarControllerBase):
|
||||
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
|
||||
drive = gear == structs.CarState.GearShifter.drive
|
||||
park = gear == structs.CarState.GearShifter.park
|
||||
@@ -302,7 +311,7 @@ class CarController(CarControllerBase):
|
||||
|
||||
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 ipedal_latch_pending \
|
||||
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
|
||||
|
||||
# Mirror the current stock counter after seeing the real CRUISE_BUTTONS frame land on the bus.
|
||||
@@ -317,9 +326,16 @@ class CarController(CarControllerBase):
|
||||
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
|
||||
|
||||
# The drivetrain latch uses a second HKG CAN-FD request path in addition to the left paddle bit.
|
||||
# Once the cluster-facing regen state reaches max regen, mirror the live stock frame and only
|
||||
# flip the request bytes that the physical paddle toggles for the final i-Pedal latch step.
|
||||
if max_regen_state and has_regen_control_msg and regen_control_counter_changed:
|
||||
can_sends.append(hyundaicanfd.create_ioniq_6_regen_control(self.packer, self.CP, self.CAN, regen_control_msg))
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ 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
|
||||
@@ -51,6 +53,10 @@ 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
|
||||
|
||||
@@ -77,6 +83,8 @@ class CarState(CarStateBase):
|
||||
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 \
|
||||
@@ -408,6 +416,9 @@ class CarState(CarStateBase):
|
||||
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]
|
||||
@@ -484,6 +495,8 @@ 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 {
|
||||
|
||||
@@ -164,6 +164,8 @@ IONIQ_6_CRUISE_BUTTONS_BASE_CHECKSUMS = (
|
||||
)
|
||||
IONIQ_6_CRUISE_BUTTONS_LEFT_PADDLE_CHECKSUM_XOR = 0x77
|
||||
IONIQ_6_CRUISE_BUTTONS_RIGHT_PADDLE_CHECKSUM_XOR = 0xD4
|
||||
IONIQ_6_REGEN_CONTROL_REQ_BYTE24 = 0xC0
|
||||
IONIQ_6_REGEN_CONTROL_REQ_BYTE27 = 0x00
|
||||
|
||||
|
||||
def get_ioniq_6_cruise_buttons_next_counter(counter: int) -> int:
|
||||
@@ -200,6 +202,21 @@ def create_ioniq_6_paddle_buttons(packer, CP, CAN, cnt, left_paddle=False, right
|
||||
return address, bytes(dat), bus
|
||||
|
||||
|
||||
def create_ioniq_6_regen_control(packer, CP, CAN, base_values,
|
||||
req_byte24=IONIQ_6_REGEN_CONTROL_REQ_BYTE24,
|
||||
req_byte27=IONIQ_6_REGEN_CONTROL_REQ_BYTE27):
|
||||
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] = req_byte24
|
||||
dat[27] = req_byte27
|
||||
|
||||
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({
|
||||
|
||||
@@ -10,7 +10,7 @@ from opendbc.car.fw_versions import build_fw_dict, match_fw_to_car
|
||||
from opendbc.car.hyundai.carcontroller import CarController, Ioniq6LongitudinalTuningState, GenesisG90LongitudinalTuningState, \
|
||||
update_ioniq_6_longitudinal_tuning, update_genesis_g90_longitudinal_tuning
|
||||
from opendbc.car.hyundai.carstate import CarState, decode_ioniq_6_blindspot_radar_state, decode_ioniq_6_ipedal_intermediate_state, \
|
||||
decode_ioniq_6_ipedal_state
|
||||
decode_ioniq_6_ipedal_state, decode_ioniq_6_max_regen_state
|
||||
from opendbc.car.hyundai.interface import CarInterface
|
||||
from opendbc.car.hyundai import hyundaican, hyundaicanfd
|
||||
from opendbc.car.hyundai.hyundaicanfd import CanBus
|
||||
@@ -296,6 +296,7 @@ class TestHyundaiFingerprint:
|
||||
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)
|
||||
@@ -342,6 +343,26 @@ class TestHyundaiFingerprint:
|
||||
assert hyundaicanfd.get_ioniq_6_cruise_buttons_next_counter(13) == 14
|
||||
assert hyundaicanfd.get_ioniq_6_cruise_buttons_next_counter(14) == 0
|
||||
|
||||
def test_ioniq_6_regen_control_message_preserves_stock_frame_and_flips_only_ipedal_request_bytes(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], [("IONIQ_6_REGEN_CONTROL", 0)], can_bus.ECAN)
|
||||
stock_dat = bytes.fromhex("45421440801f000000000000a865170000a000000080c071a80c120e00000000")
|
||||
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] == hyundaicanfd.IONIQ_6_REGEN_CONTROL_REQ_BYTE24
|
||||
assert msg[1][25:27] == stock_dat[25:27]
|
||||
assert msg[1][27] == hyundaicanfd.IONIQ_6_REGEN_CONTROL_REQ_BYTE27
|
||||
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
|
||||
@@ -367,6 +388,8 @@ class TestHyundaiFingerprint:
|
||||
"LEFT_PADDLE": 0,
|
||||
"SET_ME_1": 1,
|
||||
},
|
||||
ioniq_6_regen_control_msg={},
|
||||
ioniq_6_regen_control_ts=0,
|
||||
)
|
||||
cc = SimpleNamespace(enabled=False)
|
||||
|
||||
@@ -426,6 +449,8 @@ class TestHyundaiFingerprint:
|
||||
"LEFT_PADDLE": 0,
|
||||
"SET_ME_1": 1,
|
||||
},
|
||||
ioniq_6_regen_control_msg={},
|
||||
ioniq_6_regen_control_ts=0,
|
||||
)
|
||||
cc = SimpleNamespace(enabled=False)
|
||||
|
||||
@@ -435,6 +460,76 @@ class TestHyundaiFingerprint:
|
||||
assert sends
|
||||
assert controller._ioniq_6_always_ipedal_press_remaining == 9
|
||||
|
||||
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)
|
||||
|
||||
assert any(msg[0] == 0x1CF for msg in sends)
|
||||
regen_cmd = next(msg for msg in sends if msg[0] == 0x25A)
|
||||
assert regen_cmd[1][24] == hyundaicanfd.IONIQ_6_REGEN_CONTROL_REQ_BYTE24
|
||||
assert regen_cmd[1][27] == hyundaicanfd.IONIQ_6_REGEN_CONTROL_REQ_BYTE27
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
@@ -774,6 +774,39 @@ 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
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#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 */ \
|
||||
@@ -57,6 +60,8 @@ 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;
|
||||
@@ -77,6 +82,17 @@ static uint32_t hyundai_canfd_get_checksum(const CANPacket_t *msg) {
|
||||
return chksum;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
static void hyundai_canfd_rx_hook(const CANPacket_t *msg) {
|
||||
|
||||
const unsigned pt_bus = hyundai_canfd_lka_steering ? 1U : 0U;
|
||||
@@ -249,6 +265,31 @@ static bool hyundai_canfd_tx_hook(const CANPacket_t *msg) {
|
||||
}
|
||||
}
|
||||
|
||||
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)) &&
|
||||
(msg->data[24] == 0xC0U) &&
|
||||
(msg->data[27] == 0x00U);
|
||||
|
||||
if (allowed) {
|
||||
for (int i = 2; i < 32; i++) {
|
||||
if ((i != 24) && (i != 27) && (msg->data[i] != hyundai_canfd_last_regen_control[i])) {
|
||||
allowed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!allowed) {
|
||||
tx = false;
|
||||
}
|
||||
}
|
||||
|
||||
// UDS: only tester present ("\x02\x3E\x80\x00\x00\x00\x00\x00") allowed on diagnostics address
|
||||
if (((msg->addr == 0x730U) && hyundai_canfd_lka_steering) || ((msg->addr == 0x7D0U) && !hyundai_camera_scc)) {
|
||||
if ((GET_BYTES(msg, 0, 4) != 0x00803E02U) || (GET_BYTES(msg, 4, 4) != 0x0U)) {
|
||||
@@ -296,10 +337,20 @@ static safety_config hyundai_canfd_init(uint16_t param) {
|
||||
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)
|
||||
@@ -314,6 +365,21 @@ 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)
|
||||
@@ -344,6 +410,7 @@ static safety_config hyundai_canfd_init(uint16_t param) {
|
||||
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) {
|
||||
@@ -352,7 +419,12 @@ static safety_config hyundai_canfd_init(uint16_t param) {
|
||||
HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(1)
|
||||
};
|
||||
|
||||
ret = BUILD_SAFETY_CFG(hyundai_canfd_lka_steering_long_rx_checks, HYUNDAI_CANFD_LKA_STEERING_LONG_TX_MSGS);
|
||||
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);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Longitudinal checks for LFA steering
|
||||
@@ -394,9 +466,17 @@ 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) {
|
||||
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_ALT_TX_MSGS, ret);
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_TX_MSGS, ret);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (!hyundai_camera_scc) {
|
||||
@@ -452,6 +532,7 @@ static safety_config hyundai_canfd_init(uint16_t param) {
|
||||
|
||||
const safety_hooks hyundai_canfd_hooks = {
|
||||
.init = hyundai_canfd_init,
|
||||
.rx_all = hyundai_canfd_rx_all_hook,
|
||||
.rx = hyundai_canfd_rx_hook,
|
||||
.tx = hyundai_canfd_tx_hook,
|
||||
.get_counter = hyundai_canfd_get_counter,
|
||||
|
||||
@@ -440,6 +440,52 @@ class TestHyundaiCanfdLKASteeringEV(TestHyundaiCanfdBase):
|
||||
}
|
||||
return self.packer.make_can_msg_safety("CRUISE_BUTTONS", bus, values)
|
||||
|
||||
def _regen_control_msg(self, byte24=0xA8, 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": 0x0C,
|
||||
"BYTE26": 0x12,
|
||||
"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)
|
||||
@@ -448,6 +494,8 @@ class TestHyundaiCanfdLKASteeringEV(TestHyundaiCanfdBase):
|
||||
|
||||
class TestHyundaiCanfdLKASteeringEVAlwaysIPedal(TestHyundaiCanfdLKASteeringEV):
|
||||
|
||||
TX_MSGS = TestHyundaiCanfdLKASteeringEV.TX_MSGS + [[0x25A, 1]]
|
||||
|
||||
def setUp(self):
|
||||
self.packer = CANPackerSafety("hyundai_canfd_generated")
|
||||
self.safety = libsafety_py.libsafety
|
||||
@@ -468,6 +516,19 @@ class TestHyundaiCanfdLKASteeringEVAlwaysIPedal(TestHyundaiCanfdLKASteeringEV):
|
||||
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=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)))
|
||||
|
||||
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):
|
||||
@@ -519,6 +580,26 @@ 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):
|
||||
|
||||
|
||||
Reference in New Issue
Block a user