IQ.Pilot Release Commit @ d2ce8a8

This commit is contained in:
IQ.Lvbs CI [bot]
2026-08-28 08:35:52 -05:00
parent 9206164707
commit ee1dca77c7
210 changed files with 19726 additions and 455 deletions

View File

@@ -454,10 +454,10 @@ class CarController(CarControllerBase):
hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
hda2_long = hda2 and self.CP.openpilotLongitudinalControl
# steering control
if camera_scc:
can_sends.extend(hyundaicanfd.create_steering_messages_camera_scc(self.frame, self.packer, self.CP, self.CAN, CC, apply_steer_req, apply_torque, CS, apply_angle, self.lkas_max_torque, angle_control))
else:
can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_torque, apply_angle, self.lkas_max_torque, angle_control))
can_sends.extend(hyundaicanfd.create_steering_messages(
self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_torque,
apply_angle, self.lkas_max_torque, angle_control,
))
# prevent LFA from activating on HDA2 by sending "no lane lines detected" to ADAS ECU
if self.frame % 5 == 0 and hda2 and not camera_scc:

View File

@@ -12,20 +12,6 @@ LaneChangeDirection = log.LaneChangeDirection
TurnDirection = log.Desire
def hyundai_crc8(data: bytes) -> int:
poly = 0x2F
crc = 0xFF
for byte in data:
crc ^= byte
for _ in range(8):
if crc & 0x80:
crc = ((crc << 1) ^ poly) & 0xFF
else:
crc = (crc << 1) & 0xFF
return crc ^ 0xFF
class CanBus(CanBusBase):
def __init__(self, CP, fingerprint=None, lka_steering=None) -> None:
super().__init__(CP, fingerprint)
@@ -84,95 +70,6 @@ class CanBus(CanBusBase):
# LKAS
# 201 - 2a0
def create_steering_messages_camera_scc(frame, packer, CP, CAN, CC, lat_active, apply_steer, CS, apply_angle, max_torque, angle_control):
emergency_steering = False
if CS.adrv_0x161 is not None:
values = CS.adrv_0x161
emergency_steering = values["ALERTS_1"] in [11, 12, 13, 14, 15, 21, 22, 23, 24, 25, 26]
ret = []
if CS.mdps is not None:
values = copy.copy(CS.mdps)
#rx_counter = values.pop("COUNTER", None)
if angle_control:
if CS.lfa_alt is not None:
values["LFA2_ACTIVE"] = CS.lfa_alt["LKAS_ANGLE_ACTIVE"]
else:
if CS.lfa is not None:
values["LKA_ACTIVE"] = 1 if CS.lfa["STEER_REQ"] == 1 else 0
if frame % 1000 < 40:
values["STEERING_COL_TORQUE"] += 220
#ret.append(packer.make_can_msg("MDPS", CAN.CAM, values, rx_counter = rx_counter))
ret.append(packer.make_can_msg("MDPS", CAN.CAM, values))
if frame % 10 == 0:
if CS.steer_touch_2af is not None:
values = copy.copy(CS.steer_touch_2af)
if frame % 1000 < 40:
values["TOUCH_DETECT"] = 3
values["TOUCH1"] = 50
values["TOUCH2"] = 50
values["CHECKSUM_"] = 0
dat = packer.make_can_msg("STEER_TOUCH_2AF", 0, values)[1]
values["CHECKSUM_"] = hyundai_crc8(dat[1:8])
ret.append(packer.make_can_msg("STEER_TOUCH_2AF", CAN.CAM, values))
if angle_control:
if CS.lfa_alt is not None:
values = copy.copy(CS.lfa_alt)
rx_counter = values.pop("COUNTER", None)
if emergency_steering:
pass
else:
#values = {} #CS.lfa_alt
values["LKAS_ANGLE_ACTIVE"] = 2 if CC.latActive else 1
values["LKAS_ANGLE_CMD"] = -apply_angle
values["LKAS_ANGLE_MAX_TORQUE"] = max_torque if CC.latActive else 0
ret.append(packer.make_can_msg("LFA_ALT", CAN.ECAN, values, rx_counter = rx_counter))
if CS.lfa is not None:
values = copy.copy(CS.lfa)
rx_counter = values.pop("COUNTER", None)
if not emergency_steering:
values["LKA_MODE"] = 0
values["LKA_ICON"] = 2 if CC.latActive else 1
values["TORQUE_REQUEST"] = -1024 # apply_steer,
values["VALUE63"] = 0 # LKA_ASSIST
values["STEER_REQ"] = 0 # 1 if lat_active else 0,
values["HAS_LANE_SAFETY"] = 0 # hide LKAS settings
values["LKA_ACTIVE"] = 3 if CC.latActive else 0 # this changes sometimes, 3 seems to indicate engaged
values["VALUE64"] = 0 #STEER_MODE, NEW_SIGNAL_2
values["LKAS_ANGLE_CMD"] = -25.6 #-apply_angle,
values["LKAS_ANGLE_ACTIVE"] = 0 #2 if lat_active else 1,
values["LKAS_ANGLE_MAX_TORQUE"] = 0 #max_torque if lat_active else 0,
values["NEW_SIGNAL_1"] = 10
ret.append(packer.make_can_msg("LFA", CAN.ECAN, values, rx_counter = rx_counter))
elif CS.lfa is not None:
values = {}
values["LKA_MODE"] = 2
values["LKA_ICON"] = 2 if lat_active else 1
values["TORQUE_REQUEST"] = apply_steer
values["STEER_REQ"] = 1 if lat_active else 0
values["VALUE64"] = 0 # STEER_MODE, NEW_SIGNAL_2
values["HAS_LANE_SAFETY"] = 0
values["LKA_ACTIVE"] = 0 # NEW_SIGNAL_1
values["DampingGain"] = 0 if lat_active else 100
#values["VALUE63"] = 0
#values["VALUE82_SET256"] = 0
ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
return ret
def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_steer, apply_angle, max_torque, angle_control):
ret = []

View File

@@ -193,6 +193,22 @@ def accel_during_driver_override(accel: float, gas_pressed: bool, keep_long_acti
return 0.0 if gas_pressed and keep_long_active else accel
def ea_send_ready(stock_values, last_counter):
return bool(stock_values) and stock_values["COUNTER"] != last_counter
EA_BLINKER_STEP = 2
def next_ea_counter(tx_counter, stock_counter):
return ((stock_counter if tx_counter is None else tx_counter) + 1) % 16
def ea_blinker_command(left_request, right_request, left_active, right_active):
blinker_active = left_active or right_active
return left_request and not blinker_active, right_request and not blinker_active
class CarController(CarControllerBase):
def __init__(self, dbc_names, CP, CP_IQ):
from iqpilot.system.proprietary_runtime._verified_import import import_verified_module
@@ -241,6 +257,8 @@ class CarController(CarControllerBase):
self.sng_handoff_active = False
self.acc_counter_seeded = False
self.klr_counter_last = None
self.ea_counter_last = None
self.ea_tx_counter = None
self.eps_timer_soft_disable_alert = False
self.hca_frame_timer_running = 0
self.hca_frame_same_torque = 0
@@ -462,9 +480,14 @@ class CarController(CarControllerBase):
self.klr_counter_last = CS.klr_stock_values["COUNTER"]
if self.CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
if self.frame % 2 == 0:
if CS.ea_hud_stock_values and self.frame % EA_BLINKER_STEP == 0:
self.ea_tx_counter = next_ea_counter(self.ea_tx_counter, CS.ea_hud_stock_values["COUNTER"])
left_blinker, right_blinker = ea_blinker_command(
CC.leftBlinker, CC.rightBlinker, CS.left_blinker_active, CS.right_blinker_active,
)
can_sends.append(self.CCS.create_blinker_control(self.packer_pt, self.CAN.pt, CS.ea_hud_stock_values, CS.ea_control_stock_values,
CC.leftBlinker, CC.rightBlinker, self.hide_ea_error))
left_blinker, right_blinker, self.hide_ea_error, self.ea_tx_counter))
self.ea_counter_last = CS.ea_hud_stock_values["COUNTER"]
if self.CP.openpilotLongitudinalControl and self.CCS in (mqbcan, mlbcan) and not self.acc_counter_seeded and CS.acc_stock_counters:
seed_msgs = ("ACC_01", "ACC_02") if self.CCS is mlbcan else ("ACC_02", "ACC_06", "ACC_07", "ACC_10")

View File

@@ -55,8 +55,9 @@ def create_eps_update(packer, bus, eps_stock_values, ea_simulated_torque):
return packer.make_can_msg("LH_EPS_03", bus, values)
def create_blinker_control(packer, bus, ea_hud_stock_values, ea_control_stock_values, left_blinker, right_blinker, hide_error):
def create_blinker_control(packer, bus, ea_hud_stock_values, ea_control_stock_values, left_blinker, right_blinker, hide_error, counter=None):
values = {s: ea_hud_stock_values[s] for s in [
"COUNTER",
"EA_Texte",
"ACF_Lampe_Hands_Off",
"EA_Infotainment_Anf",
@@ -69,6 +70,9 @@ def create_blinker_control(packer, bus, ea_hud_stock_values, ea_control_stock_va
"EA_Unknown",
]}
if counter is not None:
values["COUNTER"] = counter
if ea_hud_stock_values["EA_Blinken"] == 0:
values.update({
"EA_Blinken": 1 if left_blinker else (2 if right_blinker else ea_hud_stock_values["EA_Blinken"]),

View File

@@ -2,9 +2,11 @@
from iqdbc.can import CANPacker, CANParser
from iqdbc.car.volkswagen import mebcan
from iqdbc.car.volkswagen.carcontroller import ea_blinker_command, ea_send_ready, next_ea_counter
EA_HUD_VALUES = {
"COUNTER": 0,
"EA_Texte": 0,
"ACF_Lampe_Hands_Off": 0,
"EA_Infotainment_Anf": 0,
@@ -23,21 +25,74 @@ def blinker_values(dbc, requests):
packer = CANPacker(dbc)
parser = CANParser(dbc, [("EA_02", 50)], 0)
values = []
for left, right in requests:
for counter, stock_blinker, left, right in requests:
ea_hud_values = {**EA_HUD_VALUES, "COUNTER": counter, "EA_Blinken": stock_blinker}
msg = mebcan.create_blinker_control(
packer, 0, EA_HUD_VALUES, EA_CONTROL_VALUES, left, right, False,
packer, 0, ea_hud_values, EA_CONTROL_VALUES, left, right, False,
)
parser.update([0, [msg]])
values.append(int(parser.vl["EA_02"]["EA_Blinken"]))
values.append((int(parser.vl["EA_02"]["COUNTER"]), int(parser.vl["EA_02"]["EA_Blinken"])))
return values
def blinker_value(dbc, counter, stock_blinker, left, right, override_counter=None):
packer = CANPacker(dbc)
parser = CANParser(dbc, [("EA_02", 50)], 0)
ea_hud_values = {**EA_HUD_VALUES, "COUNTER": counter, "EA_Blinken": stock_blinker}
msg = mebcan.create_blinker_control(
packer, 0, ea_hud_values, EA_CONTROL_VALUES, left, right, False, override_counter,
)
parser.update([0, [msg]])
return int(parser.vl["EA_02"]["COUNTER"]), int(parser.vl["EA_02"]["EA_Blinken"])
def test_nav_blinker_request_remains_asserted_until_released():
requests = [(True, False)] * 100 + [(False, False)]
assert blinker_values("vw_meb", requests) == [1] * 100 + [0]
requests = [(counter % 16, 0, True, False) for counter in range(100)] + [(4, 0, False, False)]
assert blinker_values("vw_meb", requests) == [(counter % 16, 1) for counter in range(100)] + [(4, 0)]
def test_nav_blinker_directions_on_meb_variants():
requests = [(True, False), (False, True), (False, False)]
requests = [(7, 0, True, False), (8, 0, False, True), (9, 0, False, False)]
for dbc in ("vw_meb", "vw_meb_2024", "vw_mqbevo"):
assert blinker_values(dbc, requests) == [1, 2, 0]
assert blinker_values(dbc, requests) == [(7, 1), (8, 2), (9, 0)]
def test_stock_blinker_has_priority_over_nav_request():
requests = [(10, 1, False, True), (11, 2, True, False), (12, 3, True, False)]
assert blinker_values("vw_meb", requests) == [(10, 1), (11, 2), (12, 3)]
def test_ea_frame_is_sent_once_per_stock_counter():
last_counter = None
sends = []
for counter in (5, 5, 5, 6, 6, 7):
stock_values = {"COUNTER": counter}
if ea_send_ready(stock_values, last_counter):
sends.append(counter)
last_counter = counter
assert sends == [5, 6, 7]
def test_blinker_counter_can_continue_between_stock_frames():
assert blinker_value("vw_meb", 8, 0, True, False, 9) == (9, 1)
assert blinker_value("vw_meb", 8, 0, True, False, 10) == (10, 1)
def test_stock_blinker_priority_survives_counter_override():
assert blinker_value("vw_meb", 8, 2, True, False, 9) == (9, 2)
def test_nav_blinker_retriggers_only_between_lamp_cycles():
assert ea_blinker_command(True, False, False, False) == (True, False)
assert ea_blinker_command(True, False, True, False) == (False, False)
assert ea_blinker_command(True, False, False, False) == (True, False)
assert ea_blinker_command(False, True, False, True) == (False, False)
def test_blinker_counter_runs_at_20_ms():
tx_counter = None
counters = []
for _ in range(10):
tx_counter = next_ea_counter(tx_counter, 14)
counters.append(tx_counter)
assert counters == [15, 0, 1, 2, 3, 4, 5, 6, 7, 8]

View File

@@ -210,6 +210,7 @@ def _a4_mk4_frames(packer, reverse=False, eps_torque=None):
packer.make_can_msg("Kombi_02", 1, {"KBI_Inhalt_Tank": 40, "KBI_Kilometerstand": 100000}),
packer.make_can_msg("Airbag_02", 1, {"AB_Gurtschloss_FA": 3}),
packer.make_can_msg("Gateway_05", 1, {"BCM1_Rueckfahrlicht_Schalter": int(reverse)}),
packer.make_can_msg("LH_EPS_01", 1, {}),
]
if eps_torque is not None:
msgs.append(packer.make_can_msg("LH_EPS_03", 1, {"EPS_Lenkmoment": abs(eps_torque),

View File

@@ -7,7 +7,7 @@
#pragma GCC diagnostic ignored "-Wunused-function"
const TorqueSteeringLimits HYUNDAI_CANFD_STEERING_LIMITS = {
.max_torque = 512, //270,
.max_torque = 270,
.max_rt_delta = 112,
.max_rate_up = 2,
@@ -85,34 +85,34 @@ const CanMsg HYUNDAI_CANFD_HDA2_LONG_TX_MSGS[] = {
{203, 0, 24}, // CB
{373, 2, 24}, // TCS(0x175)
{506, 2, 32}, // CLUSTER_SPEED_LIMIT
{234, 2, 24}, // MDPS
{687, 2, 8}, // STEER_TOUCH_2AF
{0x4BE, 2, 8}, // NEW_MSG_4BE (may be corner radar enabler x)
{0x4B9, 2, 8}, // NEW_MSG_4B9 (may be corner radar enabler)
};
#define HYUNDAI_CANFD_HDA1_TX_MSGS_COMMON(longitudinal) \
{0x12A, 0, 16, .check_relay = true}, \
{0x1A0, 0, 32, .check_relay = (longitudinal)}, \
{0x1CF, 0, 8, .check_relay = false}, \
{0x1CF, 2, 8, .check_relay = (longitudinal)}, \
{0x1E0, 0, 16, .check_relay = true}, \
{0x160, 0, 16, .check_relay = (longitudinal)}, \
{0x7D0, 0, 8, .check_relay = false}, \
{0x1AA, 2, 16, .check_relay = (longitudinal)}, \
{0x0CB, 0, 24, .check_relay = (longitudinal)}, \
{0x175, 2, 24, .check_relay = (longitudinal)}, \
{0x161, 0, 32, .check_relay = (longitudinal)}, \
{0x162, 0, 32, .check_relay = (longitudinal)}, \
{0x1EA, 0, 32, .check_relay = (longitudinal)}, \
{0x200, 0, 8, .check_relay = (longitudinal)}, \
{0x4A3, 2, 8, .check_relay = false}, \
{0x4B4, 2, 8, .check_relay = false}, \
const CanMsg HYUNDAI_CANFD_HDA1_TX_MSGS[] = {
{0x12A, 0, 16}, // LFA
{0x1A0, 0, 32}, // CRUISE_INFO
{0x1CF, 0, 8}, // CRUISE_BUTTON
{0x1CF, 2, 8}, // CRUISE_BUTTON
{0x1E0, 0, 16}, // LFAHDA_CLUSTER
{0x160, 0, 16}, // ADRV_0x160
{0x7D0, 0, 8}, // tester present for radar ECU disable
{0x1AA, 2, 16}, // CRUISE_ALT_BUTTONS , carrot
{203, 0, 24}, // CB
{373, 2, 24}, // TCS(0x175)
{353, 0, 32}, // ADRV_353
{354, 0, 32}, // CORNER_RADAR_HIGHWAY
{512, 0, 8}, // ADRV_0x200
{1187, 2, 8}, // 4A3
{1204, 2, 8}, // 4B4
{373, 2, 24}, // TCS(0x175)
{234, 2, 24}, // MDPS
{687, 2, 8}, // STEER_TOUCH_2AF
HYUNDAI_CANFD_HDA1_TX_MSGS_COMMON(false)
};
const CanMsg HYUNDAI_CANFD_HDA1_LONG_TX_MSGS[] = {
HYUNDAI_CANFD_HDA1_TX_MSGS_COMMON(true)
};
@@ -221,7 +221,6 @@ const int HYUNDAI_PARAM_CANFD_ALT_BUTTONS = 32;
const int HYUNDAI_PARAM_CANFD_HDA2_ALT_STEERING = 128;
bool hyundai_canfd_alt_buttons = false;
bool hyundai_canfd_hda2_alt_steering = false;
bool hyundai_canfd_buffered_fwd = false;
int hyundai_canfd_hda2_get_lkas_addr(void) {
return hyundai_canfd_hda2_alt_steering ? 0x110 : 0x50;
@@ -275,8 +274,6 @@ CanfdTxState canfd_tx_states[] = {
{0x1AA, 2, 50, 0U, 0U}, // 426: CRUISE_ALT_BUTTONS
{0x1CF, 2, 50, 0U, 0U}, // 463: CRUISE_BUTTON
{0x1FA, 2, 10, 0U, 0U}, // 506: CLUSTER_SPEED_LIMIT
{0x0EA, 2, 100, 0U, 0U}, // 234: MDPS
{0x2AF, 2, 10, 0U, 0U}, // 687: STEER_TOUCH_2AF
{0x4A3, 2, 5, 0U, 0U}, // 1187: HDA_INFO_4A3
{0x4B4, 2, 10, 0U, 0U}, // 1204: NEW_MSG_4B4
{0x4BE, 2, 10, 0U, 0U}, // 1214: NEW_MSG_4BE
@@ -295,30 +292,6 @@ static CanfdTxState* find_canfd_tx_state(int bus, int addr) {
}
static void hyundai_canfd_set_counter(CANPacket_t* to_push, uint8_t counter) {
if (GET_LEN(to_push) == 8U) {
to_push->data[1] = (to_push->data[1] & 0x0FU) | ((counter & 0x0FU) << 4);
}
else {
to_push->data[2] = counter;
}
}
static void hyundai_canfd_set_checksum(CANPacket_t* to_push, uint16_t checksum) {
to_push->data[0] = (uint8_t)(checksum & 0xFFU);
to_push->data[1] = (uint8_t)((checksum >> 8U) & 0xFFU);
}
static void hyundai_canfd_update_checksum(CANPacket_t* to_push) {
to_push->data[0] = 0U;
to_push->data[1] = 0U;
uint32_t checksum = hyundai_common_canfd_compute_checksum(to_push);
hyundai_canfd_set_checksum(to_push, (uint16_t)checksum);
}
static void canfd_apply_counter_and_update_checksum(CANPacket_t* dst, uint8_t counter) {
hyundai_canfd_set_counter(dst, counter);
hyundai_canfd_update_checksum(dst);
}
static void canfd_record_tx_time(int bus, int addr, bool tx) {
CanfdTxState* st = find_canfd_tx_state(bus, addr);
if (st != NULL) {
@@ -334,126 +307,6 @@ static bool canfd_should_block_fwd(int tx_bus, int addr, uint32_t now) {
return (now - st->last_tx_us) < st->timeout_us;
}
#define CANFD_BFWD_MAX_QUEUE 2
#define CANFD_BFWD_REUSE_MAX 2
typedef struct {
int addr;
int dst_bus;
bool enabled;
bool started;
uint8_t head;
uint8_t tail;
uint8_t count;
uint8_t reuse_left;
bool has_last_pkt;
CANPacket_t last_pkt;
CANPacket_t q[CANFD_BFWD_MAX_QUEUE];
} CanfdBufferedFwd;
CanfdBufferedFwd canfd_bfwd[] = {
{.addr = 0x1A0, .dst_bus = 0, .enabled = true }, // SCC_CONTROL
{.addr = 0x12A, .dst_bus = 0, .enabled = true }, // LFA
{.addr = 0x0CB, .dst_bus = 0, .enabled = true }, // LFA_ALT
{.addr = 0x0EA, .dst_bus = 2, .enabled = true }, // MDPS
{.addr = 0x1AA, .dst_bus = 2, .enabled = true }, // CRUISE_ALT_BUTTONS
// {.addr = 0x1CF, .dst_bus = 2, .enabled = true }, // CRUISE_BUTTON
{.addr = 0x175, .dst_bus = 2, .enabled = true }, // TCS
{ 0 },
};
static void canfd_copy_packet(CANPacket_t* dst, const CANPacket_t* src) {
dst->fd = src->fd;
dst->returned = 0U;
dst->rejected = 0U;
dst->extended = src->extended;
dst->addr = src->addr;
dst->bus = src->bus;
dst->data_len_code = src->data_len_code;
for (uint8_t i = 0U; i < GET_LEN(src); i++) {
dst->data[i] = src->data[i];
}
}
static CanfdBufferedFwd* canfd_bfwd_find(int addr, int dst_bus) {
for (int i = 0; canfd_bfwd[i].addr > 0; i++) {
if (canfd_bfwd[i].enabled &&
(canfd_bfwd[i].addr == addr) &&
(canfd_bfwd[i].dst_bus == dst_bus)) {
return &canfd_bfwd[i];
}
}
return NULL;
}
static void canfd_bfwd_reset(CanfdBufferedFwd* st) {
st->started = false;
st->head = 0U;
st->tail = 0U;
st->count = 0U;
st->reuse_left = 0U;
st->has_last_pkt = false;
st->last_pkt = (CANPacket_t){0};
}
static void canfd_bfwd_push(CanfdBufferedFwd* st, const CANPacket_t* pkt) {
if ((st == NULL) || !st->enabled) return;
if (GET_BUS(pkt) != st->dst_bus) return;
// queue<75><65> <20>̹<EFBFBD> 2<><32><EFBFBD><EFBFBD> <20>̹<EFBFBD> <20><> packet<65><74> <20><><EFBFBD><EFBFBD>
if (st->count >= CANFD_BFWD_MAX_QUEUE) {
return;
}
canfd_copy_packet(&st->q[st->tail], pkt);
st->tail = (st->tail + 1U) % CANFD_BFWD_MAX_QUEUE;
st->count++;
st->started = true;
}
static bool canfd_bfwd_pop(CanfdBufferedFwd* st, CANPacket_t* pkt) {
if ((st == NULL) || !st->enabled) {
return false;
}
if (!st->started || (st->count == 0U)) {
return false;
}
canfd_copy_packet(pkt, &st->q[st->head]);
st->head = (st->head + 1U) % CANFD_BFWD_MAX_QUEUE;
st->count--;
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> packet <20><><EFBFBD><EFBFBD>
canfd_copy_packet(&st->last_pkt, pkt);
st->has_last_pkt = true;
st->reuse_left = CANFD_BFWD_REUSE_MAX;
if (st->count == 0U) {
st->started = false;
}
return true;
}
static bool canfd_bfwd_reuse_last(CanfdBufferedFwd* st, CANPacket_t* pkt) {
if ((st == NULL) || !st->enabled) {
return false;
}
if (!st->has_last_pkt || (st->reuse_left == 0U)) {
return false;
}
canfd_copy_packet(pkt, &st->last_pkt);
st->reuse_left--;
return true;
}
static void hyundai_canfd_rx_hook(const CANPacket_t *to_push) {
int bus = GET_BUS(to_push);
int addr = GET_ADDR(to_push);
@@ -538,26 +391,7 @@ static void hyundai_canfd_rx_hook(const CANPacket_t *to_push) {
}
static bool hyundai_canfd_tx_hook(const CANPacket_t *to_send_const) {
CANPacket_t* to_send = (CANPacket_t*)to_send_const;
const TorqueSteeringLimits HYUNDAI_CANFD_STEERING_LIMITS = {
.max_torque = 512,
.max_rt_delta = 112,
.max_rate_up = 10,
.max_rate_down = 10,
.driver_torque_allowance = 250,
.driver_torque_multiplier = 2,
.type = TorqueDriverLimited,
// the EPS faults when the steering angle is above a certain threshold for too long. to prevent this,
// we allow setting torque actuation bit to 0 while maintaining the requested torque value for two consecutive frames
.min_valid_request_frames = 89,
.max_invalid_request_frames = 2,
.min_valid_request_rt_interval = 810000, // 810ms; a ~10% buffer on cutting every 90 frames
.has_steer_req_tolerance = true,
};
static bool hyundai_canfd_tx_hook(const CANPacket_t *to_send) {
bool tx = true;
int addr = GET_ADDR(to_send);
@@ -618,14 +452,6 @@ static bool hyundai_canfd_tx_hook(const CANPacket_t *to_send_const) {
if (violation) {
tx = false;
}
else if (hyundai_canfd_buffered_fwd) {
CanfdBufferedFwd* bfwd = canfd_bfwd_find(addr, GET_BUS(to_send));
if (bfwd != NULL) {
canfd_bfwd_push(bfwd, to_send);
//tx = false;
return true;
}
}
canfd_record_tx_time(GET_BUS(to_send), addr, tx);
@@ -633,6 +459,10 @@ static bool hyundai_canfd_tx_hook(const CANPacket_t *to_send_const) {
}
static bool hyundai_canfd_fwd_hook(int bus_num, int addr) {
if (!hyundai_canfd_hda2) {
return (bus_num == 0) && (addr == 0x4B9);
}
uint32_t now = microsecond_timer_get();
if (bus_num == 0) {
if (canfd_should_block_fwd(2, addr, now)) {
@@ -653,16 +483,11 @@ static safety_config hyundai_canfd_init(uint16_t param) {
canfd_tx_states[i].last_tx_us = 0U;
}
for (int i = 0; canfd_bfwd[i].addr > 0; i++) {
canfd_bfwd_reset(&canfd_bfwd[i]);
}
hyundai_common_init(param);
gen_crc_lookup_table_16(0x1021, hyundai_canfd_crc_lut);
hyundai_canfd_alt_buttons = GET_FLAG(param, HYUNDAI_PARAM_CANFD_ALT_BUTTONS);
hyundai_canfd_hda2_alt_steering = GET_FLAG(param, HYUNDAI_PARAM_CANFD_HDA2_ALT_STEERING);
hyundai_canfd_buffered_fwd = hyundai_camera_scc;
// no long for radar-SCC HDA1 yet
//if (!hyundai_canfd_hda2 && !hyundai_camera_scc) {
@@ -680,8 +505,8 @@ static safety_config hyundai_canfd_init(uint16_t param) {
else ret = BUILD_SAFETY_CFG(hyundai_canfd_hda2_long_rx_checks, HYUNDAI_CANFD_HDA2_LONG_TX_MSGS);
}
} else {
ret = hyundai_canfd_alt_buttons ? BUILD_SAFETY_CFG(hyundai_canfd_long_alt_buttons_rx_checks, HYUNDAI_CANFD_HDA1_TX_MSGS) : \
BUILD_SAFETY_CFG(hyundai_canfd_long_rx_checks, HYUNDAI_CANFD_HDA1_TX_MSGS);
ret = hyundai_canfd_alt_buttons ? BUILD_SAFETY_CFG(hyundai_canfd_long_alt_buttons_rx_checks, HYUNDAI_CANFD_HDA1_LONG_TX_MSGS) : \
BUILD_SAFETY_CFG(hyundai_canfd_long_rx_checks, HYUNDAI_CANFD_HDA1_LONG_TX_MSGS);
}
} else {
if (hyundai_canfd_hda2 && hyundai_camera_scc) {

View File

@@ -44,12 +44,12 @@ def test_canfd_steering_limits(safety, param, addr, length):
assert not safety.safety_tx_hook(canfd_steer(addr, length, 1))
safety.set_controls_allowed(True)
assert safety.safety_tx_hook(canfd_steer(addr, length, 10))
safety.set_desired_torque_last(512)
safety.set_rt_torque_last(512)
assert safety.safety_tx_hook(canfd_steer(addr, length, 512))
assert not safety.safety_tx_hook(canfd_steer(addr, length, 513))
assert not safety.safety_tx_hook(canfd_steer(addr, length, -513))
assert safety.safety_tx_hook(canfd_steer(addr, length, 2))
safety.set_desired_torque_last(270)
safety.set_rt_torque_last(270)
assert safety.safety_tx_hook(canfd_steer(addr, length, 270))
assert not safety.safety_tx_hook(canfd_steer(addr, length, 271))
assert not safety.safety_tx_hook(canfd_steer(addr, length, -271))
def test_canfd_tx_whitelist_and_buttons(safety):
@@ -90,6 +90,31 @@ def test_canfd_camera_scc_button_passthrough(safety):
assert safety.safety_tx_hook(packet(0x1CF, 2, 8, {2: 4}))
def test_canfd_camera_scc_single_owner_forwarding(safety):
safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, HyundaiSafetyFlags.CAMERA_SCC)
safety.init_tests()
safety.set_timer(1_000_000)
assert safety.safety_fwd_hook(2, 0x12A) == -1
assert safety.safety_fwd_hook(2, 0x1E0) == -1
assert safety.safety_fwd_hook(2, 0x1A0) == 0
assert safety.safety_fwd_hook(0, 0xEA) == 2
assert not safety.safety_tx_hook(packet(0xEA, 2, 24))
assert not safety.safety_tx_hook(packet(0x2AF, 2, 8))
def test_canfd_camera_scc_longitudinal_single_owner_forwarding(safety):
param = HyundaiSafetyFlags.CAMERA_SCC | HyundaiSafetyFlags.LONG
safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, param)
safety.init_tests()
safety.set_timer(1_000_000)
assert safety.safety_fwd_hook(2, 0x12A) == -1
assert safety.safety_fwd_hook(2, 0x1A0) == -1
assert safety.safety_fwd_hook(0, 0x175) == -1
assert safety.safety_fwd_hook(0, 0xEA) == 2
def test_canfd_stock_longitudinal_only_allows_cancel(safety):
safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, 0)
safety.init_tests()

View File

@@ -2,7 +2,7 @@ import pytest
from iqdbc.car import gen_empty_fingerprint, structs
from iqdbc.car.hyundai.interface import CarInterface
from iqdbc.car.hyundai.values import CAR
from iqdbc.car.hyundai.values import CAR, HyundaiFlags
from iqdbc.safety.tests.libsafety import libsafety_py
@@ -37,3 +37,24 @@ def test_controller_frames_match_configured_safety(candidate, alpha_long, monkey
packet = libsafety_py.make_CANPacket(address, bus, data)
rejection = f"{candidate.value} frame {frame}: safety rejected address={address:#x} bus={bus} data={data.hex()}"
assert safety.safety_tx_hook(packet), rejection
def test_ev6_camera_scc_has_one_lfa_sender(monkeypatch, tmp_path):
monkeypatch.setenv("PARAMS_ROOT", str(tmp_path))
fingerprint = gen_empty_fingerprint()
cp = CarInterface.get_params(CAR.KIA_EV6, fingerprint, [], False, False, False)
cp.flags &= ~HyundaiFlags.CANFD_HDA2.value
cp.flags |= HyundaiFlags.CANFD_CAMERA_SCC.value
cp_iq = CarInterface.get_params_iq(cp, CAR.KIA_EV6, fingerprint, [], False, False, False)
interface = CarInterface(cp, cp_iq)
interface.update([])
control = structs.CarControl.new_message()
control.enabled = True
control.latActive = True
control.actuators.torque = 0.01
for _ in range(20):
_, can_sends = interface.apply(control.as_reader(), structs.IQCarControl())
assert [(address, bus) for address, _, bus in can_sends if address == 0x12A] == [(0x12A, 0)]
assert all(address not in (0xEA, 0x2AF) for address, _, _ in can_sends)