mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-20 07:43:48 +08:00
greased lightning
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -238,8 +238,8 @@
|
||||
|Hyundai|Kona Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Hyundai|Nexo 2021|All|[Upstream](#upstream)|
|
||||
|Hyundai|Palisade 2020-22|All|[Upstream](#upstream)|
|
||||
|Hyundai|Palisade 2023-24|HDA2|[Community](#community)|
|
||||
|Hyundai|Palisade (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Hyundai|Palisade 2023-25|HDA2|[Community](#community)|
|
||||
|Hyundai|Palisade (with HDA II) 2023-25|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Hyundai|Palisade (without HDA II) 2023-25|Highway Driving Assist|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Cruz 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Cruz (without HDA II) 2025|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|
||||
@@ -55,7 +55,7 @@ class CAR(Platforms):
|
||||
|
||||
EXTRA_HYUNDAI = ExtraPlatformConfig(
|
||||
[
|
||||
CommunityCarDocs("Hyundai Palisade 2023-24", package="HDA2"),
|
||||
CommunityCarDocs("Hyundai Palisade 2023-25", package="HDA2"),
|
||||
CommunityCarDocs("Kia Telluride 2023-24", package="HDA2"),
|
||||
],
|
||||
)
|
||||
|
||||
@@ -721,15 +721,25 @@ class CarController(CarControllerBase):
|
||||
def create_can_msgs(self, apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel, stopping, hud_control, actuators, CS, CC, lka_icon, lfa_icon):
|
||||
can_sends = []
|
||||
can_canfd_blended = bool(self.CP.flags & HyundaiFlags.CAN_CANFD_BLENDED)
|
||||
blended_hda2 = can_canfd_blended and bool(self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING)
|
||||
|
||||
# HUD messages
|
||||
sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
|
||||
hud_control)
|
||||
|
||||
if can_canfd_blended and self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||
if blended_hda2:
|
||||
can_sends.extend(hyundaicanfd.create_steering_messages(
|
||||
self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_torque, 0.0,
|
||||
))
|
||||
if self.long_active_ecu:
|
||||
can_sends.extend(hyundaican.create_lkas11_can_canfd_blended(
|
||||
self.packer, self.frame, self.CP, apply_torque, apply_steer_req,
|
||||
torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
|
||||
hud_control.leftLaneVisible, hud_control.rightLaneVisible,
|
||||
left_lane_warning, right_lane_warning, CS.msg_364,
|
||||
include_alerts=False,
|
||||
counter_mod=0xF,
|
||||
))
|
||||
if self.frame % 5 == 0:
|
||||
can_sends.append(hyundaicanfd.create_suppress_lfa(
|
||||
self.packer, self.CAN, CS.lfa_block_msg, False,
|
||||
@@ -760,13 +770,22 @@ class CarController(CarControllerBase):
|
||||
can_sends.extend(self._create_can_redneck_button_messages(CS))
|
||||
|
||||
if self.long_active_ecu and can_canfd_blended:
|
||||
can_sends.extend(hyundaican.create_radar_aux_messages(self.packer, self.CAN, self.frame))
|
||||
if blended_hda2:
|
||||
can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame, blended_hda2=True))
|
||||
can_sends.extend(hyundaican.create_radar_aux_messages(self.packer, self.CAN, self.frame, hda2=blended_hda2))
|
||||
|
||||
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
|
||||
if can_canfd_blended:
|
||||
if blended_hda2:
|
||||
stopping = stopping and CS.out.vEgoRaw < 0.1
|
||||
can_sends.extend(hyundaican.create_acc_commands_can_canfd_blended_hda2(
|
||||
self.packer, CC.enabled, accel, self.accel_last, jerk, int(self.frame / 2), hud_control,
|
||||
set_speed_in_units, stopping, CC.cruiseControl.override, use_fca, self.CP,
|
||||
))
|
||||
self.accel_last = accel
|
||||
elif can_canfd_blended:
|
||||
can_sends.extend(hyundaican.create_acc_commands_can_canfd_blended(self.packer, CC.enabled, accel, jerk,
|
||||
int(self.frame / 2), hud_control,
|
||||
set_speed_in_units, stopping,
|
||||
@@ -777,7 +796,7 @@ class CarController(CarControllerBase):
|
||||
CC.cruiseControl.override, use_fca, self.CP))
|
||||
|
||||
# 20 Hz LFA MFA message
|
||||
if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
|
||||
if self.frame % 5 == 0 and (self.CP.flags & HyundaiFlags.SEND_LFA.value or (self.long_active_ecu and blended_hda2)):
|
||||
can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled, self.frame, self.CP, lfa_icon))
|
||||
|
||||
# 5 Hz ACC options
|
||||
|
||||
@@ -667,7 +667,7 @@ class CarState(CarStateBase):
|
||||
("CGW2", 5),
|
||||
("WHL_SPD11", 50),
|
||||
("SAS11", 100),
|
||||
("SCC12", 50),
|
||||
("SCC12", 0 if CP.openpilotLongitudinalControl and CP.flags & HyundaiFlags.CANFD_LKA_STEERING else 50),
|
||||
("EMS12", 100),
|
||||
("EMS16", 100),
|
||||
("LVR12", 100),
|
||||
|
||||
@@ -106,7 +106,8 @@ def create_checksum_can_canfd_blended(packer, bus, addr, values):
|
||||
def create_lkas11_can_canfd_blended(packer, frame, CP, apply_steer, steer_req,
|
||||
torque_fault, lkas11, sys_warning, sys_state, enabled,
|
||||
left_lane, right_lane,
|
||||
left_lane_depart, right_lane_depart, msg_364):
|
||||
left_lane_depart, right_lane_depart, msg_364,
|
||||
include_alerts=True, counter_mod=0x10):
|
||||
bus = CanBus(CP).ECAN
|
||||
values = {
|
||||
"CF_Lkas_LdwsActivemode": int(left_lane) + (int(right_lane) << 1),
|
||||
@@ -116,7 +117,7 @@ def create_lkas11_can_canfd_blended(packer, frame, CP, apply_steer, steer_req,
|
||||
"CR_Lkas_StrToqReq": apply_steer,
|
||||
"CF_Lkas_ActToi": steer_req,
|
||||
"CF_Lkas_ToiFlt": torque_fault,
|
||||
"CF_Lkas_MsgCount": frame % 0x10,
|
||||
"CF_Lkas_MsgCount": frame % counter_mod,
|
||||
"NEW_SIGNAL_1": 0,
|
||||
"NEW_SIGNAL_5": 100,
|
||||
}
|
||||
@@ -130,13 +131,13 @@ def create_lkas11_can_canfd_blended(packer, frame, CP, apply_steer, steer_req,
|
||||
alerts_364.setdefault("BYTE5", 0)
|
||||
alerts_364.setdefault("BYTE6", 0)
|
||||
alerts_364.setdefault("BYTE7", 0)
|
||||
alerts_364["COUNTER"] = frame % 0x10
|
||||
alerts_364["COUNTER"] = frame % counter_mod
|
||||
alerts_364["CHECKSUM"] = create_checksum_can_canfd_blended(packer, bus, "ALERTS_364", alerts_364)
|
||||
|
||||
return [
|
||||
packer.make_can_msg("LKAS11", bus, values),
|
||||
packer.make_can_msg("ALERTS_364", bus, alerts_364),
|
||||
]
|
||||
ret = [packer.make_can_msg("LKAS11", bus, values)]
|
||||
if include_alerts:
|
||||
ret.append(packer.make_can_msg("ALERTS_364", bus, alerts_364))
|
||||
return ret
|
||||
|
||||
|
||||
def create_clu11(packer, frame, clu11, button, CP):
|
||||
@@ -233,6 +234,56 @@ def create_acc_commands_can_canfd_blended(packer, enabled, accel, upper_jerk, id
|
||||
return commands
|
||||
|
||||
|
||||
def create_acc_commands_can_canfd_blended_hda2(packer, enabled, accel, accel_last, upper_jerk, idx,
|
||||
hud_control, set_speed, stopping, long_override, use_fca, CP):
|
||||
commands = []
|
||||
bus = CanBus(CP).ECAN
|
||||
jerk = 5.0
|
||||
|
||||
if not enabled or long_override:
|
||||
accel_raw, accel_value = 0.0, 0.0
|
||||
else:
|
||||
accel_raw = accel
|
||||
accel_value = max(accel_last - jerk / 50.0, min(accel, accel_last + jerk / 50.0))
|
||||
|
||||
message_values = [
|
||||
("SCC11", {
|
||||
"aReqRaw": accel_raw,
|
||||
"aReqValue": accel_value,
|
||||
"JerkUpperLimit": upper_jerk,
|
||||
"JerkLowerLimit": jerk if enabled else 1.0,
|
||||
}),
|
||||
("SCC12", {
|
||||
"MainMode_ACC": 1,
|
||||
"ACCMode_Inactive": 0 if enabled else 1,
|
||||
"TauGapSet": hud_control.leadDistanceBars,
|
||||
"VSetDis": set_speed,
|
||||
"ACC_ObjDist": 1,
|
||||
"ACCMode": 2 if enabled and long_override else 1 if enabled else 0,
|
||||
"StopReq": 1 if stopping else 0,
|
||||
}),
|
||||
("SCC14", {
|
||||
"ACC_ObjRelSpd": 0,
|
||||
"ObjValid": 0,
|
||||
"ObjStatus": 2 if hud_control.leadVisible and enabled else 1 if hud_control.leadVisible else 0,
|
||||
}),
|
||||
]
|
||||
|
||||
if use_fca and not (CP.flags & HyundaiFlags.CAMERA_SCC):
|
||||
# These values reproduce the stock status bytes without requesting AEB/FCA actuation.
|
||||
message_values.append(("FCA11", {
|
||||
"cr_vsm_deccmd": 255,
|
||||
"cf_vsm_deccmdact": 0,
|
||||
}))
|
||||
|
||||
for name, values in message_values:
|
||||
values["COUNTER"] = idx % 0xF
|
||||
values["CHECKSUM"] = create_checksum_can_canfd_blended(packer, bus, name, values)
|
||||
commands.append(packer.make_can_msg(name, bus, values))
|
||||
|
||||
return commands
|
||||
|
||||
|
||||
def create_acc_commands(packer, enabled, accel, upper_jerk, idx, hud_control, set_speed, stopping, long_override, use_fca, CP):
|
||||
commands = []
|
||||
|
||||
@@ -324,17 +375,27 @@ def create_frt_radar_opt(packer):
|
||||
return packer.make_can_msg("FRT_RADAR11", 0, frt_radar11_values)
|
||||
|
||||
|
||||
def create_radar_aux_messages(packer, CAN, frame):
|
||||
def create_radar_aux_messages(packer, CAN, frame, hda2=False):
|
||||
commands = []
|
||||
|
||||
for addr, freq, values in (
|
||||
message_specs = (
|
||||
("RADAR_0x363", 2, {"FCA_ESA": 1}),
|
||||
("RADAR_0x398", 5, {"BYTE4": 0x80, "BYTE5": 0x5D}),
|
||||
("RADAR_0x399", 5, {"BYTE2": 0x02}),
|
||||
("RADAR_0x39a", 5, {"BYTE7": 0xFF}),
|
||||
("RADAR_0x39b", 5, {}),
|
||||
("RADAR_0x39c", 5, {"BYTE5": 0xE0, "BYTE6": 0x79}),
|
||||
("RADAR_0x43a", 20, {"BYTE2": 0x07}),
|
||||
) if hda2 else (
|
||||
("RADAR_0x363", 2, {"FCA_ESA": 1}),
|
||||
("RADAR_0x398", 5, {"BYTE4": 0x80, "BYTE5": 0x10}),
|
||||
):
|
||||
)
|
||||
|
||||
for addr, freq, values in message_specs:
|
||||
if frame % freq != 0:
|
||||
continue
|
||||
|
||||
msg_values = values | {"COUNTER": frame % 0x10}
|
||||
msg_values = values | {"COUNTER": frame % (0xF if hda2 else 0x10)}
|
||||
msg_values["CHECKSUM"] = create_checksum_can_canfd_blended(packer, CAN.ECAN, addr, msg_values)
|
||||
commands.append(packer.make_can_msg(addr, CAN.ECAN, msg_values))
|
||||
|
||||
|
||||
@@ -258,7 +258,7 @@ def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque,
|
||||
ret = []
|
||||
if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||
lkas_msg = "LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT else "LKAS"
|
||||
if CP.openpilotLongitudinalControl or send_lfa_status:
|
||||
if (CP.openpilotLongitudinalControl and not CP.flags & HyundaiFlags.CAN_CANFD_BLENDED) or send_lfa_status:
|
||||
ret.append(packer.make_can_msg("LFA", CAN.ECAN, lfa_values))
|
||||
if lfa_only:
|
||||
return ret
|
||||
@@ -820,7 +820,7 @@ def create_fca_warning_light(packer, CAN, frame):
|
||||
return ret
|
||||
|
||||
|
||||
def create_adrv_messages(packer, CAN, frame):
|
||||
def create_adrv_messages(packer, CAN, frame, blended_hda2=False):
|
||||
# messages needed to car happy after disabling
|
||||
# the ADAS Driving ECU to do longitudinal control
|
||||
|
||||
@@ -830,6 +830,9 @@ def create_adrv_messages(packer, CAN, frame):
|
||||
}
|
||||
ret.append(packer.make_can_msg("ADRV_0x51", CAN.ACAN, values))
|
||||
|
||||
if blended_hda2:
|
||||
return ret
|
||||
|
||||
ret.extend(create_fca_warning_light(packer, CAN, frame))
|
||||
|
||||
if frame % 5 == 0:
|
||||
|
||||
@@ -9,6 +9,7 @@ from opendbc.car.hyundai.values import HyundaiFlags, CAR, CarControllerParams, \
|
||||
RADAR_LIVE_LONGITUDINAL_CAR, \
|
||||
UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags, \
|
||||
LEGACY_LONGITUDINAL_CAR, \
|
||||
CAN_CANFD_BLENDED_HDA2_LONGITUDINAL_CAR, \
|
||||
HyundaiStarPilotSafetyFlags, \
|
||||
hyundai_cancel_button_enables_cruise, \
|
||||
kia_ev6_gt_line_longitudinal_tuning
|
||||
@@ -199,7 +200,8 @@ class CarInterface(CarInterfaceBase):
|
||||
else:
|
||||
# Shared configuration for non CAN-FD cars
|
||||
ret.alphaLongitudinalAvailable = candidate not in UNSUPPORTED_LONGITUDINAL_CAR or candidate in LEGACY_LONGITUDINAL_CAR
|
||||
if ret.flags & HyundaiFlags.CAN_CANFD_BLENDED and ret.flags & HyundaiFlags.CANFD_LKA_STEERING:
|
||||
if ret.flags & HyundaiFlags.CAN_CANFD_BLENDED and ret.flags & HyundaiFlags.CANFD_LKA_STEERING and \
|
||||
candidate not in CAN_CANFD_BLENDED_HDA2_LONGITUDINAL_CAR:
|
||||
ret.alphaLongitudinalAvailable = False
|
||||
ret.enableBsm = 0x58b in fingerprint[CAN.ECAN]
|
||||
|
||||
|
||||
@@ -549,14 +549,17 @@ class TestHyundaiFingerprint:
|
||||
|
||||
assert CP.flags & HyundaiFlags.CAN_CANFD_BLENDED
|
||||
assert CP.flags & HyundaiFlags.CANFD_LKA_STEERING
|
||||
assert not CP.alphaLongitudinalAvailable
|
||||
assert not CP.openpilotLongitudinalControl
|
||||
assert CP.alphaLongitudinalAvailable
|
||||
assert CP.openpilotLongitudinalControl
|
||||
assert CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.CAN_CANFD_BLENDED
|
||||
assert CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.CANFD_LKA_STEERING
|
||||
assert CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.LONG
|
||||
assert can_bus.ACAN == 0
|
||||
assert can_bus.ECAN == 1
|
||||
assert parsers[Bus.pt].bus == 1
|
||||
assert parsers[Bus.cam].bus == 2
|
||||
scc12_state = next(state for state in parsers[Bus.pt].message_states.values() if state.name == "SCC12")
|
||||
assert scc12_state.frequency == 0
|
||||
assert CarControllerParams(CP).STEER_MAX == 384
|
||||
|
||||
def test_palisade_telluride_hda2_sends_lkas_and_camera_suppression(self):
|
||||
@@ -587,6 +590,41 @@ class TestHyundaiFingerprint:
|
||||
assert (0x2A4, 0) in msg_addrs_buses
|
||||
assert not ({0x340, 0x364} & {addr for addr, _, _ in msgs})
|
||||
|
||||
def test_palisade_telluride_hda2_long_sends_complete_support_set(self):
|
||||
fingerprint = gen_empty_fingerprint()
|
||||
fingerprint[2][0x50] = 16
|
||||
fingerprint[1][0x38D] = 8
|
||||
car_fw = [CarParams.CarFw(ecu=Ecu.adas, fwVersion=b"", address=0x730, brand="hyundai")]
|
||||
CP = CarInterface.get_params(CAR.HYUNDAI_PALISADE_2023, fingerprint, car_fw, True, False, False, None)
|
||||
controller = CarController(DBC[CP.carFingerprint], CP)
|
||||
controller.frame = 0
|
||||
|
||||
hud_control = SimpleNamespace(
|
||||
visualAlert=CarControl.HUDControl.VisualAlert.none,
|
||||
leftLaneVisible=True,
|
||||
rightLaneVisible=True,
|
||||
leftLaneDepart=False,
|
||||
rightLaneDepart=False,
|
||||
leadDistanceBars=3,
|
||||
leadVisible=True,
|
||||
)
|
||||
lfa_block_msg = {f"BYTE{i}": 0 for i in range(3, 24) if i != 7}
|
||||
lfa_block_msg["COUNTER"] = 0
|
||||
CS = SimpleNamespace(lfa_block_msg=lfa_block_msg, redneck_send_button=Buttons.NONE, lkas11={}, msg_364={},
|
||||
out=SimpleNamespace(vEgoRaw=5.0))
|
||||
CC = SimpleNamespace(enabled=True, cruiseControl=SimpleNamespace(cancel=False, resume=False, override=False))
|
||||
actuators = SimpleNamespace(longControlState=LongCtrlState.pid)
|
||||
|
||||
msgs = controller.create_can_msgs(True, 0, False, 42.0, 0.0, False, hud_control, actuators, CS, CC, 2, 2)
|
||||
msg_addrs_buses = {(addr, bus) for addr, _, bus in msgs}
|
||||
|
||||
assert {
|
||||
(0x50, 0), (0x2A4, 0), (0x51, 0),
|
||||
(0x340, 1), (0x485, 1), (0x420, 1), (0x421, 1), (0x389, 1), (0x38D, 1),
|
||||
(0x363, 1), (0x398, 1), (0x399, 1), (0x39A, 1), (0x39B, 1), (0x39C, 1), (0x43A, 1),
|
||||
} <= msg_addrs_buses
|
||||
assert (0x364, 1) not in msg_addrs_buses
|
||||
|
||||
def test_g70_aol_uses_active_lkas_icon(self):
|
||||
CP = CarInterface.get_params(CAR.GENESIS_G70_2020, gen_empty_fingerprint(), [], False, False, False, None)
|
||||
controller = CarController(DBC[CP.carFingerprint], CP)
|
||||
@@ -2418,6 +2456,46 @@ class TestHyundaiFingerprint:
|
||||
assert parser.vl["SCC14"]["ObjStatus"] == 1
|
||||
assert parser.vl["RADAR_0x363"]["FCA_ESA"] == 1
|
||||
|
||||
def test_can_canfd_blended_hda2_acc_commands_use_hda2_layout(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.HYUNDAI_PALISADE_2023
|
||||
CP.flags = int(HyundaiFlags.CAN_CANFD_BLENDED | HyundaiFlags.CANFD_LKA_STEERING | HyundaiFlags.USE_FCA)
|
||||
|
||||
packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
|
||||
parser = CANParser(DBC[CP.carFingerprint][Bus.pt], [
|
||||
("SCC11", 0),
|
||||
("SCC12", 0),
|
||||
("SCC14", 0),
|
||||
("FCA11", 0),
|
||||
], 1)
|
||||
|
||||
msgs = hyundaican.create_acc_commands_can_canfd_blended_hda2(
|
||||
packer,
|
||||
enabled=True,
|
||||
accel=-1.0,
|
||||
accel_last=0.0,
|
||||
upper_jerk=2.5,
|
||||
idx=15,
|
||||
hud_control=SimpleNamespace(leadDistanceBars=3, leadVisible=True),
|
||||
set_speed=42,
|
||||
stopping=False,
|
||||
long_override=False,
|
||||
use_fca=True,
|
||||
CP=CP,
|
||||
)
|
||||
parser.update([(1, msgs)])
|
||||
|
||||
assert parser.can_valid
|
||||
assert parser.vl["SCC11"]["aReqRaw"] == pytest.approx(-1.0)
|
||||
assert parser.vl["SCC11"]["aReqValue"] == pytest.approx(-0.1)
|
||||
assert parser.vl["SCC11"]["COUNTER"] == 0
|
||||
assert parser.vl["SCC12"]["VSetDis"] == 42
|
||||
assert parser.vl["SCC14"]["ObjValid"] == 0
|
||||
assert parser.vl["SCC14"]["ObjStatus"] == 2
|
||||
assert parser.vl["FCA11"]["aeb_cmd_act"] == 0
|
||||
assert parser.vl["FCA11"]["fca_cmd_act"] == 0
|
||||
assert next(dat for addr, dat, _ in msgs if addr == 0x38D)[4:7] == b"\xC0\x3F\x7F"
|
||||
|
||||
def test_can_acc_optional_messages_use_enabled_fca_usm(self):
|
||||
CP = CarParams.new_message()
|
||||
CP.carFingerprint = CAR.GENESIS_G90
|
||||
|
||||
@@ -481,7 +481,7 @@ class CAR(Platforms):
|
||||
[
|
||||
HyundaiCarDocs("Hyundai Palisade (without HDA II) 2023-25", "Highway Driving Assist",
|
||||
car_parts=CarParts.common([CarHarness.hyundai_a])),
|
||||
HyundaiCarDocs("Hyundai Palisade (with HDA II) 2023-24", "Highway Driving Assist II",
|
||||
HyundaiCarDocs("Hyundai Palisade (with HDA II) 2023-25", "Highway Driving Assist II",
|
||||
car_parts=CarParts.common([CarHarness.hyundai_r])),
|
||||
HyundaiCarDocs("Kia Telluride (without HDA II) 2023-25", "Highway Driving Assist",
|
||||
car_parts=CarParts.common([CarHarness.hyundai_l])),
|
||||
@@ -968,6 +968,10 @@ CANCEL_BUTTON_ENABLE_CARS = frozenset({
|
||||
CAR.HYUNDAI_PALISADE_2023,
|
||||
})
|
||||
|
||||
CAN_CANFD_BLENDED_HDA2_LONGITUDINAL_CAR = frozenset({
|
||||
CAR.HYUNDAI_PALISADE_2023,
|
||||
})
|
||||
|
||||
KIA_EV6_GT_LINE_LONG_TUNING_VDS_PREFIXES = frozenset({
|
||||
"C4DLC",
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import numpy as np
|
||||
|
||||
from opendbc.can import CANPacker
|
||||
from opendbc.car import Bus, DT_CTRL, make_tester_present_msg, structs
|
||||
from opendbc.car import Bus, DT_CTRL, structs
|
||||
from opendbc.car.common.filter_simple import FirstOrderFilter
|
||||
from opendbc.car.lateral import apply_std_steer_angle_limits
|
||||
from opendbc.car.interfaces import CarControllerBase
|
||||
@@ -55,7 +55,7 @@ class CarController(CarControllerBase):
|
||||
CC.longActive and brake_pressure > 0, brake_mode))
|
||||
|
||||
if self.frame % 100 == 0:
|
||||
can_sends.append(make_tester_present_msg(0x707, 0, suppress_response=True))
|
||||
can_sends.append(nissancan.create_leaf_adas_tester_present())
|
||||
|
||||
### STEER ###
|
||||
steer_hud_alert = 1 if hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw) else 0
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
from opendbc.car import get_safety_config, structs, uds
|
||||
import time
|
||||
|
||||
from opendbc.car import get_safety_config, structs
|
||||
from opendbc.car.disable_ecu import disable_ecu, ecu_log
|
||||
from opendbc.car.interfaces import CarInterfaceBase
|
||||
from opendbc.car.isotp_parallel_query import IsoTpParallelQuery
|
||||
from opendbc.car.nissan.carcontroller import CarController
|
||||
from opendbc.car.nissan.carstate import CarState
|
||||
from opendbc.car.nissan.values import CAR, CarControllerParams, NissanSafetyFlags, \
|
||||
@@ -9,8 +12,22 @@ from opendbc.car.nissan.values import CAR, CarControllerParams, NissanSafetyFlag
|
||||
|
||||
LEAF_ADAS_ECU_ADDR = 0x707
|
||||
LEAF_ADAS_ECU_BUS = 0
|
||||
LEAF_ADAS_COMMAND_BUS = 1
|
||||
LEAF_ADAS_COMMAND_ADDRS = frozenset((0x1C3, 0x2B0))
|
||||
LEAF_2025_SV_PLUS_CAMERA_FW = b'6WK2CDB\x04\x18\x00\x00\x00\x00\x00R=1\x18\x99\x10\x00\x00\x00\x80'
|
||||
|
||||
# This Leaf camera uses KWP2000 rather than UDS for session management.
|
||||
LEAF_KWP_AFTER_SALES_REQUEST = b"\x10\xC0"
|
||||
LEAF_KWP_AFTER_SALES_RESPONSE = b"\x50\xC0"
|
||||
LEAF_KWP_DISABLE_NORMAL_TX = b"\x28\x01"
|
||||
LEAF_KWP_ENABLE_NORMAL_TX = b"\x29\x01"
|
||||
LEAF_KWP_ENABLE_NORMAL_TX_RESPONSE = b"\x69"
|
||||
|
||||
LEAF_KWP_SESSIONS = (
|
||||
(LEAF_KWP_AFTER_SALES_REQUEST, LEAF_KWP_AFTER_SALES_RESPONSE),
|
||||
(NISSAN_DIAGNOSTIC_REQUEST_KWP, NISSAN_DIAGNOSTIC_RESPONSE_KWP),
|
||||
)
|
||||
|
||||
|
||||
def is_leaf_2025_sv_plus_longitudinal(candidate, car_fw):
|
||||
return candidate == CAR.NISSAN_LEAF and any(
|
||||
@@ -19,6 +36,62 @@ def is_leaf_2025_sv_plus_longitudinal(candidate, car_fw):
|
||||
)
|
||||
|
||||
|
||||
def leaf_adas_commands_silent(can_recv, settle_time=0.05, observe_time=0.15):
|
||||
"""Confirm the stock ADAS command sender stopped while bus 1 is still observable."""
|
||||
if can_recv is None:
|
||||
return False
|
||||
|
||||
try:
|
||||
# Let already-published CAN batches age out, then discard everything queued
|
||||
# before the communication-control response.
|
||||
time.sleep(settle_time)
|
||||
can_recv()
|
||||
|
||||
saw_adas_bus_traffic = False
|
||||
deadline = time.monotonic() + observe_time
|
||||
while time.monotonic() < deadline:
|
||||
packets = can_recv(wait_for_one=True)
|
||||
for packet in packets:
|
||||
for msg in packet:
|
||||
if msg.src != LEAF_ADAS_COMMAND_BUS:
|
||||
continue
|
||||
saw_adas_bus_traffic = True
|
||||
if msg.address in LEAF_ADAS_COMMAND_ADDRS:
|
||||
ecu_log(f"Nissan Leaf ADAS TX still active: {hex(msg.address)} on bus {msg.src}")
|
||||
return False
|
||||
except Exception as e:
|
||||
ecu_log(f"Nissan Leaf ADAS TX silence verification exception: {e}")
|
||||
return False
|
||||
|
||||
if not saw_adas_bus_traffic:
|
||||
ecu_log("Nissan Leaf ADAS TX silence could not be verified: no bus 1 traffic observed")
|
||||
return saw_adas_bus_traffic
|
||||
|
||||
|
||||
def restore_leaf_adas_tx(can_recv, can_send):
|
||||
"""Re-enable normal KWP message transmission, trying both safe diagnostic sessions."""
|
||||
if can_recv is None or can_send is None:
|
||||
return False
|
||||
|
||||
for diag_request, diag_response in LEAF_KWP_SESSIONS:
|
||||
try:
|
||||
ecu_log(f"Nissan Leaf ADAS TX restore using KWP session {diag_request.hex()}")
|
||||
query = IsoTpParallelQuery(
|
||||
can_send, can_recv, LEAF_ADAS_ECU_BUS, [LEAF_ADAS_ECU_ADDR],
|
||||
[diag_request, LEAF_KWP_ENABLE_NORMAL_TX],
|
||||
[diag_response, LEAF_KWP_ENABLE_NORMAL_TX_RESPONSE],
|
||||
response_offset=NISSAN_RX_OFFSET,
|
||||
)
|
||||
if query.get_data(0.2):
|
||||
ecu_log("Nissan Leaf ADAS normal TX restored")
|
||||
return True
|
||||
except Exception as e:
|
||||
ecu_log(f"Nissan Leaf ADAS TX restore exception: {e}")
|
||||
|
||||
ecu_log("Nissan Leaf ADAS normal TX restore was not confirmed")
|
||||
return False
|
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
CarState = CarState
|
||||
CarController = CarController
|
||||
@@ -62,39 +135,36 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
@staticmethod
|
||||
def init(CP, can_recv, can_send):
|
||||
if not (CP.openpilotLongitudinalControl and CP.carFingerprint == CAR.NISSAN_LEAF):
|
||||
if not (CP.openpilotLongitudinalControl and CP.alphaLongitudinalAvailable and CP.carFingerprint == CAR.NISSAN_LEAF):
|
||||
return
|
||||
|
||||
from openpilot.common.params import Params
|
||||
params = Params()
|
||||
communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL,
|
||||
uds.CONTROL_TYPE.ENABLE_RX_DISABLE_TX,
|
||||
uds.MESSAGE_TYPE.NORMAL])
|
||||
ecu_disabled = disable_ecu(can_recv, can_send, bus=LEAF_ADAS_ECU_BUS, addr=LEAF_ADAS_ECU_ADDR,
|
||||
com_cont_req=communication_control, require_response=True, response_offset=NISSAN_RX_OFFSET)
|
||||
if not ecu_disabled:
|
||||
# Nissan firmware queries use the KWP-style default session. Try it after
|
||||
# standard UDS extended-session control, but still require a positive 0x68 response.
|
||||
ecu_disabled = False
|
||||
for diag_request, diag_response in LEAF_KWP_SESSIONS:
|
||||
ecu_log(f"Nissan Leaf ADAS takeover using KWP session {diag_request.hex()}")
|
||||
ecu_disabled = disable_ecu(can_recv, can_send, bus=LEAF_ADAS_ECU_BUS, addr=LEAF_ADAS_ECU_ADDR,
|
||||
com_cont_req=communication_control, require_response=True,
|
||||
diag_request=NISSAN_DIAGNOSTIC_REQUEST_KWP, diag_response=NISSAN_DIAGNOSTIC_RESPONSE_KWP,
|
||||
response_offset=NISSAN_RX_OFFSET)
|
||||
params.put_bool("EcuDisableFailed", not ecu_disabled)
|
||||
if ecu_disabled:
|
||||
ecu_log("Nissan Leaf ADAS TX disabled; experimental longitudinal control enabled")
|
||||
com_cont_req=LEAF_KWP_DISABLE_NORMAL_TX, require_response=True, retry=3,
|
||||
diag_request=diag_request, diag_response=diag_response, response_offset=NISSAN_RX_OFFSET)
|
||||
if ecu_disabled:
|
||||
break
|
||||
|
||||
takeover_confirmed = ecu_disabled and leaf_adas_commands_silent(can_recv)
|
||||
params.put_bool("EcuDisableFailed", not takeover_confirmed)
|
||||
if takeover_confirmed:
|
||||
ecu_log("Nissan Leaf ADAS TX disable and command silence confirmed; experimental longitudinal control enabled")
|
||||
else:
|
||||
# A response can be lost after the ECU accepts 0x28. Always attempt to
|
||||
# restore stock transmission before falling back to stock longitudinal.
|
||||
restore_leaf_adas_tx(can_recv, can_send)
|
||||
CP.safetyConfigs[-1].safetyParam &= ~NissanSafetyFlags.LONG_CONTROL.value
|
||||
CP.openpilotLongitudinalControl = False
|
||||
CP.pcmCruise = True
|
||||
ecu_log("Nissan Leaf ADAS TX disable failed; falling back to stock longitudinal control")
|
||||
ecu_log("Nissan Leaf ADAS takeover was not confirmed; falling back to stock longitudinal control")
|
||||
|
||||
@staticmethod
|
||||
def deinit(CP, can_recv, can_send):
|
||||
if not (CP.openpilotLongitudinalControl and CP.carFingerprint == CAR.NISSAN_LEAF):
|
||||
if not (CP.openpilotLongitudinalControl and CP.alphaLongitudinalAvailable and CP.carFingerprint == CAR.NISSAN_LEAF):
|
||||
return
|
||||
|
||||
communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL,
|
||||
0x80 | uds.CONTROL_TYPE.ENABLE_RX_ENABLE_TX,
|
||||
uds.MESSAGE_TYPE.NORMAL])
|
||||
disable_ecu(can_recv, can_send, bus=LEAF_ADAS_ECU_BUS, addr=LEAF_ADAS_ECU_ADDR,
|
||||
com_cont_req=communication_control, response_offset=NISSAN_RX_OFFSET)
|
||||
restore_leaf_adas_tx(can_recv, can_send)
|
||||
|
||||
@@ -6,6 +6,11 @@ from opendbc.car.nissan.values import CAR
|
||||
nissan_checksum = crcmod.mkCrcFun(0x11d, initCrc=0x00, rev=False, xorOut=0xff)
|
||||
|
||||
|
||||
def create_leaf_adas_tester_present():
|
||||
"""KWP2000 tester-present with a response requested, for the 2025 Leaf ADAS ECU."""
|
||||
return CanData(0x707, b"\x02\x3E\x01\x00\x00\x00\x00\x00", 0)
|
||||
|
||||
|
||||
def create_accel_command(raw_command, frame, active):
|
||||
"""Build the Leaf ADAS propulsion/regen request (0x2B0)."""
|
||||
raw_command = int(raw_command)
|
||||
|
||||
@@ -2,9 +2,10 @@ from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
|
||||
from opendbc.car import Bus, ButtonType, gen_empty_fingerprint, structs, uds
|
||||
from opendbc.car import Bus, ButtonType, gen_empty_fingerprint, structs
|
||||
from opendbc.car.can_definitions import CanData
|
||||
from opendbc.car.nissan.carstate import CarState
|
||||
from opendbc.car.nissan.interface import CarInterface, LEAF_2025_SV_PLUS_CAMERA_FW
|
||||
from opendbc.car.nissan.interface import CarInterface, LEAF_2025_SV_PLUS_CAMERA_FW, leaf_adas_commands_silent, restore_leaf_adas_tx
|
||||
from opendbc.car.nissan.values import CAR, CarControllerParams, NissanSafetyFlags
|
||||
|
||||
|
||||
@@ -82,7 +83,7 @@ def test_alpha_long_controller_sends_stock_shaped_commands_and_keepalive():
|
||||
|
||||
assert can_sends[0x2B0][1].hex() == "ff6090ac5b000e03"
|
||||
assert can_sends[0x1C3][1].hex() == "000000006400ff27"
|
||||
assert can_sends[0x707][1].hex() == "023e800000000000"
|
||||
assert can_sends[0x707][1].hex() == "023e010000000000"
|
||||
assert all(can_sends[addr][2] == 1 for addr in (0x2B0, 0x1C3))
|
||||
assert can_sends[0x707][2] == 0
|
||||
|
||||
@@ -137,6 +138,8 @@ def test_leaf_ecu_disable_is_strict_and_falls_back(monkeypatch, ecu_disabled):
|
||||
return ecu_disabled
|
||||
|
||||
monkeypatch.setattr("opendbc.car.nissan.interface.disable_ecu", fake_disable_ecu)
|
||||
monkeypatch.setattr("opendbc.car.nissan.interface.leaf_adas_commands_silent", lambda *_: ecu_disabled)
|
||||
monkeypatch.setattr("opendbc.car.nissan.interface.restore_leaf_adas_tx", lambda *_: True)
|
||||
monkeypatch.setattr("opendbc.car.nissan.interface.ecu_log", lambda *_: None)
|
||||
CarInterface.init(CP, None, None)
|
||||
|
||||
@@ -145,9 +148,10 @@ def test_leaf_ecu_disable_is_strict_and_falls_back(monkeypatch, ecu_disabled):
|
||||
assert calls[0]["bus"] == 0
|
||||
assert calls[0]["response_offset"] == 0x20
|
||||
assert calls[0]["require_response"] is True
|
||||
assert calls[0]["com_cont_req"] == bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL,
|
||||
uds.CONTROL_TYPE.ENABLE_RX_DISABLE_TX,
|
||||
uds.MESSAGE_TYPE.NORMAL])
|
||||
assert calls[0]["diag_request"] == b"\x10\xc0"
|
||||
assert calls[0]["diag_response"] == b"\x50\xc0"
|
||||
assert calls[0]["com_cont_req"] == b"\x28\x01"
|
||||
assert calls[0]["retry"] == 3
|
||||
if not ecu_disabled:
|
||||
assert calls[1]["diag_request"] == b"\x10\x81"
|
||||
assert calls[1]["diag_response"] == b"\x50\x81"
|
||||
@@ -161,9 +165,58 @@ def test_leaf_kwp_session_can_confirm_ecu_disable(monkeypatch):
|
||||
results = iter((False, True))
|
||||
|
||||
monkeypatch.setattr("opendbc.car.nissan.interface.disable_ecu", lambda *args, **kwargs: next(results))
|
||||
monkeypatch.setattr("opendbc.car.nissan.interface.leaf_adas_commands_silent", lambda *_: True)
|
||||
monkeypatch.setattr("opendbc.car.nissan.interface.ecu_log", lambda *_: None)
|
||||
CarInterface.init(CP, None, None)
|
||||
|
||||
assert CP.openpilotLongitudinalControl
|
||||
assert not CP.pcmCruise
|
||||
assert CP.safetyConfigs[-1].safetyParam & NissanSafetyFlags.LONG_CONTROL
|
||||
|
||||
|
||||
def test_leaf_positive_disable_response_without_command_silence_falls_back(monkeypatch):
|
||||
CP = CarInterface.get_params(CAR.NISSAN_LEAF, gen_empty_fingerprint(), SUPPORTED_LEAF_FW, True, False, False, None)
|
||||
restore_calls = []
|
||||
|
||||
monkeypatch.setattr("opendbc.car.nissan.interface.disable_ecu", lambda *args, **kwargs: True)
|
||||
monkeypatch.setattr("opendbc.car.nissan.interface.leaf_adas_commands_silent", lambda *_: False)
|
||||
monkeypatch.setattr("opendbc.car.nissan.interface.restore_leaf_adas_tx", lambda *args: restore_calls.append(args) or True)
|
||||
monkeypatch.setattr("opendbc.car.nissan.interface.ecu_log", lambda *_: None)
|
||||
CarInterface.init(CP, None, None)
|
||||
|
||||
assert len(restore_calls) == 1
|
||||
assert not CP.openpilotLongitudinalControl
|
||||
assert CP.pcmCruise
|
||||
assert not (CP.safetyConfigs[-1].safetyParam & NissanSafetyFlags.LONG_CONTROL)
|
||||
|
||||
|
||||
def test_leaf_adas_command_silence_requires_live_bus_without_stock_commands(monkeypatch):
|
||||
monkeypatch.setattr("opendbc.car.nissan.interface.ecu_log", lambda *_: None)
|
||||
|
||||
def unrelated_bus_traffic(wait_for_one=False):
|
||||
return [] if not wait_for_one else [[CanData(0x123, b"\x00", 1)]]
|
||||
|
||||
assert leaf_adas_commands_silent(unrelated_bus_traffic, settle_time=0, observe_time=0.001)
|
||||
|
||||
def stock_command_traffic(wait_for_one=False):
|
||||
return [] if not wait_for_one else [[CanData(0x2B0, b"\x00" * 8, 1)]]
|
||||
|
||||
assert not leaf_adas_commands_silent(stock_command_traffic, settle_time=0, observe_time=0.001)
|
||||
assert not leaf_adas_commands_silent(lambda wait_for_one=False: [], settle_time=0, observe_time=0.001)
|
||||
|
||||
|
||||
def test_leaf_adas_restore_uses_kwp_enable_normal_transmission(monkeypatch):
|
||||
queries = []
|
||||
|
||||
class FakeQuery:
|
||||
def __init__(self, can_send, can_recv, bus, addrs, request, response, response_offset):
|
||||
queries.append((bus, addrs, request, response, response_offset))
|
||||
|
||||
def get_data(self, timeout):
|
||||
return {(0x707, None): b""}
|
||||
|
||||
monkeypatch.setattr("opendbc.car.nissan.interface.IsoTpParallelQuery", FakeQuery)
|
||||
monkeypatch.setattr("opendbc.car.nissan.interface.ecu_log", lambda *_: None)
|
||||
|
||||
assert restore_leaf_adas_tx(lambda **kwargs: [], lambda msgs: None)
|
||||
assert queries == [(0, [0x707], [b"\x10\xc0", b"\x29\x01"], [b"\x50\xc0", b"\x69"], 0x20)]
|
||||
|
||||
@@ -92,13 +92,16 @@ static bool hyundai_legacy = false;
|
||||
static bool hyundai_can_canfd_blended_hda2 = false;
|
||||
static bool hyundai_acc_main_on_rx_prev = false;
|
||||
|
||||
#define HYUNDAI_CAN_CANFD_BLENDED_HDA2_RX_CHECKS() \
|
||||
#define HYUNDAI_CAN_CANFD_BLENDED_HDA2_COMMON_RX_CHECKS() \
|
||||
{.msg = {{0x260, 1, 8, 100U, .max_counter = 3U, .ignore_quality_flag = true}, \
|
||||
{0x371, 1, 8, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }}}, \
|
||||
{.msg = {{0x386, 1, 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
{.msg = {{0x394, 1, 8, 50U, .max_counter = 7U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
{.msg = {{0x251, 1, 8, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
{.msg = {{0x4F1, 1, 4, 50U, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
|
||||
{.msg = {{0x4F1, 1, 4, 50U, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
|
||||
|
||||
#define HYUNDAI_CAN_CANFD_BLENDED_HDA2_RX_CHECKS() \
|
||||
HYUNDAI_CAN_CANFD_BLENDED_HDA2_COMMON_RX_CHECKS() \
|
||||
HYUNDAI_SCC11_ADDR_CHECK(1) \
|
||||
HYUNDAI_SCC12_ADDR_CHECK(1, true)
|
||||
|
||||
@@ -281,14 +284,21 @@ static bool hyundai_tx_hook(const CANPacket_t *msg) {
|
||||
|
||||
bool tx = true;
|
||||
|
||||
// FCA11: Block any potential actuation
|
||||
// FCA11: Block any potential actuation. The blended HDA II layout uses
|
||||
// different static fields, but its explicit AEB/FCA request bits stay zero.
|
||||
if (msg->addr == 0x38DU) {
|
||||
int CR_VSM_DecCmd = msg->data[1];
|
||||
bool FCA_CmdAct = GET_BIT(msg, 20U);
|
||||
bool CF_VSM_DecCmdAct = GET_BIT(msg, 31U);
|
||||
if (hyundai_can_canfd_blended_hda2) {
|
||||
if (GET_BIT(msg, 16U) || GET_BIT(msg, 19U)) {
|
||||
tx = false;
|
||||
}
|
||||
} else {
|
||||
int CR_VSM_DecCmd = msg->data[1];
|
||||
bool FCA_CmdAct = GET_BIT(msg, 20U);
|
||||
bool CF_VSM_DecCmdAct = GET_BIT(msg, 31U);
|
||||
|
||||
if ((CR_VSM_DecCmd != 0) || FCA_CmdAct || CF_VSM_DecCmdAct) {
|
||||
tx = false;
|
||||
if ((CR_VSM_DecCmd != 0) || FCA_CmdAct || CF_VSM_DecCmdAct) {
|
||||
tx = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,7 +358,7 @@ static bool hyundai_tx_hook(const CANPacket_t *msg) {
|
||||
}
|
||||
|
||||
// UDS: Only tester present ("\x02\x3E\x80\x00\x00\x00\x00\x00") allowed on diagnostics address
|
||||
if (msg->addr == 0x7D0U) {
|
||||
if ((msg->addr == 0x7D0U) || (msg->addr == 0x730U)) {
|
||||
if ((GET_BYTES(msg, 0, 4) != 0x00803E02U) || (GET_BYTES(msg, 4, 4) != 0x0U)) {
|
||||
tx = false;
|
||||
}
|
||||
@@ -399,6 +409,27 @@ static safety_config hyundai_init(uint16_t param) {
|
||||
{0x2A4, 0, 24, .check_relay = true},
|
||||
};
|
||||
|
||||
static const CanMsg HYUNDAI_CAN_CANFD_BLENDED_HDA2_LONG_TX_MSGS[] = {
|
||||
{0x50, 0, 16, .check_relay = true},
|
||||
{0x4F1, 1, 4, .check_relay = false},
|
||||
{0x2A4, 0, 24, .check_relay = true},
|
||||
{0x51, 0, 32, .check_relay = false},
|
||||
{0x730, 1, 8, .check_relay = false},
|
||||
{0x340, 1, 8, .check_relay = true},
|
||||
{0x485, 1, 8, .check_relay = true},
|
||||
{0x420, 1, 8, .check_relay = true},
|
||||
{0x421, 1, 8, .check_relay = true},
|
||||
{0x389, 1, 8, .check_relay = true},
|
||||
{0x38D, 1, 8, .check_relay = false},
|
||||
{0x363, 1, 8, .check_relay = false},
|
||||
{0x398, 1, 8, .check_relay = false},
|
||||
{0x399, 1, 8, .check_relay = false},
|
||||
{0x39A, 1, 8, .check_relay = false},
|
||||
{0x39B, 1, 8, .check_relay = false},
|
||||
{0x39C, 1, 8, .check_relay = false},
|
||||
{0x43A, 1, 8, .check_relay = false},
|
||||
};
|
||||
|
||||
static const CanMsg HYUNDAI_CAN_CANFD_BLENDED_LONG_TX_MSGS[] = {
|
||||
{0x340, 0, 8, .check_relay = true},
|
||||
{0x4F1, 0, 4, .check_relay = false},
|
||||
@@ -462,10 +493,10 @@ static safety_config hyundai_init(uint16_t param) {
|
||||
}
|
||||
if (hyundai_can_canfd_blended_hda2) {
|
||||
static RxCheck hyundai_can_canfd_blended_hda2_long_rx_checks[] = {
|
||||
HYUNDAI_CAN_CANFD_BLENDED_HDA2_RX_CHECKS()
|
||||
HYUNDAI_CAN_CANFD_BLENDED_HDA2_COMMON_RX_CHECKS()
|
||||
};
|
||||
SET_RX_CHECKS(hyundai_can_canfd_blended_hda2_long_rx_checks, ret);
|
||||
SET_TX_MSGS(HYUNDAI_CAN_CANFD_BLENDED_HDA2_TX_MSGS, ret);
|
||||
SET_TX_MSGS(HYUNDAI_CAN_CANFD_BLENDED_HDA2_LONG_TX_MSGS, ret);
|
||||
} else if (hyundai_camera_scc) {
|
||||
if (hyundai_can_refresh_msgs) {
|
||||
SET_TX_MSGS(HYUNDAI_CAMERA_SCC_LONG_REFRESH_TX_MSGS, ret);
|
||||
|
||||
@@ -174,7 +174,8 @@ static bool nissan_tx_hook(const CANPacket_t *msg) {
|
||||
}
|
||||
|
||||
if (nissan_longitudinal && (msg->addr == 0x707U) && (msg->bus == 0U)) {
|
||||
violation |= (msg->data[0] != 0x02U) || (msg->data[1] != 0x3EU) || (msg->data[2] != 0x80U);
|
||||
// KWP2000 TesterPresent, response required. The Leaf camera rejects UDS 0x3E80.
|
||||
violation |= (msg->data[0] != 0x02U) || (msg->data[1] != 0x3EU) || (msg->data[2] != 0x01U);
|
||||
for (int i = 3; i < 8; i++) {
|
||||
violation |= msg->data[i] != 0U;
|
||||
}
|
||||
|
||||
@@ -254,6 +254,10 @@ class TestHyundaiCanCanfdBlendedSafety(TestHyundaiSafety):
|
||||
|
||||
class TestHyundaiCanCanfdBlendedHda2Safety(unittest.TestCase):
|
||||
TX_MSGS = [[0x50, 0], [0x4F1, 1], [0x2A4, 0]]
|
||||
LONG_TX_MSGS = TX_MSGS + [
|
||||
[0x51, 0], [0x730, 1], [0x340, 1], [0x485, 1], [0x420, 1], [0x421, 1], [0x389, 1], [0x38D, 1],
|
||||
[0x363, 1], [0x398, 1], [0x399, 1], [0x39A, 1], [0x39B, 1], [0x39C, 1], [0x43A, 1],
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
self.packer = CANPackerSafety("hyundai_palisade_2023_generated")
|
||||
@@ -291,6 +295,52 @@ class TestHyundaiCanCanfdBlendedHda2Safety(unittest.TestCase):
|
||||
self.assertEqual(-1, self.safety.safety_fwd_hook(2, 0x50))
|
||||
self.assertEqual(-1, self.safety.safety_fwd_hook(2, 0x2A4))
|
||||
|
||||
def test_hda2_longitudinal_support_messages_require_long_flag(self):
|
||||
flags = HyundaiSafetyFlags.CAN_CANFD_BLENDED | HyundaiSafetyFlags.CANFD_LKA_STEERING | HyundaiSafetyFlags.LONG
|
||||
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, flags)
|
||||
self.safety.init_tests()
|
||||
|
||||
for addr, bus in self.LONG_TX_MSGS:
|
||||
if addr == 0x50:
|
||||
msg = self._lkas_msg()
|
||||
elif addr == 0x420:
|
||||
msg = self.packer.make_can_msg_panda("SCC11", bus, {"aReqRaw": 0.0, "aReqValue": 0.0})
|
||||
elif addr == 0x730:
|
||||
msg = libsafety_py.make_CANPacket(addr, bus, b"\x02\x3E\x80\x00\x00\x00\x00\x00")
|
||||
else:
|
||||
length = 32 if addr == 0x51 else 24 if addr == 0x2A4 else 4 if addr == 0x4F1 else 8
|
||||
msg = common.make_msg(bus, addr, length)
|
||||
self.assertTrue(self.safety.safety_tx_hook(msg), hex(addr))
|
||||
|
||||
self.safety.set_safety_hooks(
|
||||
CarParams.SafetyModel.hyundai,
|
||||
HyundaiSafetyFlags.CAN_CANFD_BLENDED | HyundaiSafetyFlags.CANFD_LKA_STEERING,
|
||||
)
|
||||
self.safety.init_tests()
|
||||
for addr, bus in self.LONG_TX_MSGS[len(self.TX_MSGS):]:
|
||||
length = 32 if addr == 0x51 else 8
|
||||
self.assertFalse(self.safety.safety_tx_hook(common.make_msg(bus, addr, length)), hex(addr))
|
||||
|
||||
def test_hda2_longitudinal_acceleration_and_diagnostics_are_checked(self):
|
||||
flags = HyundaiSafetyFlags.CAN_CANFD_BLENDED | HyundaiSafetyFlags.CANFD_LKA_STEERING | HyundaiSafetyFlags.LONG
|
||||
self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, flags)
|
||||
self.safety.init_tests()
|
||||
self.safety.set_controls_allowed(True)
|
||||
|
||||
for accel, allowed in ((-3.5, True), (3.5, True), (-3.51, False), (3.51, False)):
|
||||
msg = self.packer.make_can_msg_panda("SCC11", 1, {"aReqRaw": accel, "aReqValue": accel})
|
||||
self.assertEqual(allowed, self.safety.safety_tx_hook(msg))
|
||||
|
||||
valid_tester = libsafety_py.make_CANPacket(0x730, 1, b"\x02\x3E\x80\x00\x00\x00\x00\x00")
|
||||
invalid_tester = libsafety_py.make_CANPacket(0x730, 1, b"\x03\x28\x83\x01\x00\x00\x00\x00")
|
||||
self.assertTrue(self.safety.safety_tx_hook(valid_tester))
|
||||
self.assertFalse(self.safety.safety_tx_hook(invalid_tester))
|
||||
|
||||
fca_status = self.packer.make_can_msg_panda("FCA11", 1, {"cr_vsm_deccmd": 255, "cf_vsm_deccmdact": 0})
|
||||
fca_request = self.packer.make_can_msg_panda("FCA11", 1, {"aeb_cmd_act": 1})
|
||||
self.assertTrue(self.safety.safety_tx_hook(fca_status))
|
||||
self.assertFalse(self.safety.safety_tx_hook(fca_request))
|
||||
|
||||
|
||||
class TestHyundaiSafetyFCEV(TestHyundaiSafety):
|
||||
def setUp(self):
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
import unittest
|
||||
|
||||
from opendbc.car import make_tester_present_msg
|
||||
from opendbc.car.nissan import nissancan
|
||||
from opendbc.car.nissan.values import NissanSafetyFlags
|
||||
from opendbc.car.structs import CarParams
|
||||
@@ -261,7 +260,7 @@ class TestNissanLeafLongSafety(TestNissanLeafSafety):
|
||||
self.assertTrue(self._tx(self._brake_msg(0, active=False, brake_mode=False)))
|
||||
|
||||
def test_tester_present(self):
|
||||
tester_present = make_tester_present_msg(0x707, 0, suppress_response=True)
|
||||
tester_present = nissancan.create_leaf_adas_tester_present()
|
||||
self.assertTrue(self._tx(self._make_msg(tester_present)))
|
||||
|
||||
for index in range(8):
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
extern const uint8_t gitversion[19];
|
||||
const uint8_t gitversion[19] = "DEV-50e1c1d3-DEBUG";
|
||||
const uint8_t gitversion[19] = "DEV-21805a54-DEBUG";
|
||||
|
||||
@@ -1 +1 @@
|
||||
DEV-50e1c1d3-DEBUG
|
||||
DEV-21805a54-DEBUG
|
||||
Binary file not shown.
@@ -11,7 +11,7 @@ import { MapsManager } from "/assets/components/tools/maps.js"
|
||||
import { NavDestination } from "/assets/components/navigation/navigation_destination.js?v=nav-search-context-2"
|
||||
import { NavKeys } from "/assets/components/navigation/navigation_keys.js?v=app-keys-session-1"
|
||||
import { RouteRecordings } from "/assets/components/recordings/dashcam_routes.js"
|
||||
import { SettingsView } from "/assets/components/settings.js"
|
||||
import { SettingsView } from "/assets/components/settings.js?v=router-cycle-fix-1"
|
||||
import { ScreenRecordings } from "/assets/components/recordings/screen_recordings.js"
|
||||
import { Sidebar } from "/assets/components/sidebar.js?v=lateral-tuning-1"
|
||||
import { SentryMode } from "/assets/components/tools/sentry.js"
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
import { html } from "/assets/vendor/arrow-core.js"
|
||||
import { upperFirst } from "/assets/js/utils.js"
|
||||
import { Navigate } from "/assets/components/router.js"
|
||||
|
||||
function navigate(href) {
|
||||
// Avoid importing router.js here: settings.js is loaded by router.js, and
|
||||
// a cache-busted router URL would otherwise create a second router module.
|
||||
if (typeof window.__theGalaxyNavigate === "function") {
|
||||
return window.__theGalaxyNavigate(href)
|
||||
}
|
||||
window.location.assign(href)
|
||||
}
|
||||
|
||||
export function SettingsView({ params }) {
|
||||
const state = {
|
||||
@@ -15,7 +23,7 @@ export function SettingsView({ params }) {
|
||||
const setting = results.find((item) => item.key === state.selectedSubsection) ?? {}
|
||||
|
||||
if (!setting.subsettings || Object.keys(setting.subsettings).length === 0) {
|
||||
return Navigate(`/settings/${state.selectedSection}`)
|
||||
return navigate(`/settings/${state.selectedSection}`)
|
||||
}
|
||||
|
||||
state.heading = setting.key
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<link rel="stylesheet" href="/assets/components/tools/tsk_manager.css">
|
||||
|
||||
<script type="module">
|
||||
import("/assets/components/router.js?v=favorite-c4-hint-1").catch((err) => {
|
||||
import("/assets/components/router.js?v=router-cycle-fix-1").catch((err) => {
|
||||
console.error("[the_galaxy] bootstrap failed", err);
|
||||
const target = document.getElementById("app") || document.body;
|
||||
const pre = document.createElement("pre");
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[4]
|
||||
SETTINGS_PATH = REPO_ROOT / "starpilot/system/the_galaxy/assets/components/settings.js"
|
||||
ROUTER_PATH = REPO_ROOT / "starpilot/system/the_galaxy/assets/components/router.js"
|
||||
INDEX_PATH = REPO_ROOT / "starpilot/system/the_galaxy/templates/index.html"
|
||||
|
||||
|
||||
def test_settings_does_not_create_a_second_router_module():
|
||||
source = SETTINGS_PATH.read_text(encoding="utf-8")
|
||||
|
||||
assert "/assets/components/router.js" not in source
|
||||
assert "window.__theGalaxyNavigate" in source
|
||||
|
||||
|
||||
def test_router_and_settings_cache_bust_is_consistent():
|
||||
router = ROUTER_PATH.read_text(encoding="utf-8")
|
||||
index = INDEX_PATH.read_text(encoding="utf-8")
|
||||
|
||||
assert "/assets/components/settings.js?v=router-cycle-fix-1" in router
|
||||
assert "/assets/components/router.js?v=router-cycle-fix-1" in index
|
||||
@@ -4464,6 +4464,7 @@ def setup(app):
|
||||
"/assets/components/router.js",
|
||||
"/assets/components/sentry_notifications.js",
|
||||
"/assets/js/utils.js",
|
||||
"/assets/components/settings.js",
|
||||
"/assets/components/home/home.js",
|
||||
"/assets/components/home/home.css",
|
||||
"/assets/components/tools/device_settings.js",
|
||||
|
||||
Reference in New Issue
Block a user