IQ.Pilot Release Commit @ 67fd9c2

This commit is contained in:
IQ.Lvbs CI [bot]
2026-09-01 20:09:51 -05:00
parent f8f9335ba3
commit 4efaff4cb2
58 changed files with 494 additions and 92 deletions

View File

@@ -129,6 +129,8 @@ class CarInterface(CarInterfaceBase):
car_fw: list[structs.CarParams.CarFw], alpha_long: bool, is_release_iq: bool, docs: bool) -> structs.IQCarParams:
if candidate in UNSUPPORTED_DSU_CAR:
ret.iqSafetyFlags |= ToyotaSafetyFlagsIQ.UNSUPPORTED_DSU
if candidate in TSS2_CAR:
ret.iqSafetyFlags |= ToyotaSafetyFlagsIQ.LKAS_HUD
# Detect smartDSU, which intercepts ACC_CMD from the DSU (or radar) allowing openpilot to send it
# 0x2AA is sent by a similar device which intercepts the radar instead of DSU on NO_DSU_CARs

View File

@@ -1,7 +1,7 @@
from iqdbc.car import gen_empty_fingerprint, structs
from iqdbc.car.toyota.interface import CarInterface
from iqdbc.car.toyota.values import CAR, ToyotaFlags
from iqdbc.lvbs.car.toyota.values import ToyotaFlagsIQ
from iqdbc.lvbs.car.toyota.values import ToyotaFlagsIQ, ToyotaSafetyFlagsIQ
def test_secoc_toyota_not_dashcam_on_release():
@@ -34,3 +34,11 @@ def test_smart_dsu_clears_disable_radar_on_radar_acc_toyota():
assert not (cp.flags & ToyotaFlags.DISABLE_RADAR.value)
assert cp.alphaLongitudinalAvailable
assert cp.openpilotLongitudinalControl
def test_lkas_hud_safety_flag_tracks_tss2():
for candidate, expected in ((CAR.TOYOTA_CHR_TSS2, True), (CAR.TOYOTA_PRIUS_V, False)):
fingerprint = gen_empty_fingerprint()
cp = CarInterface.get_params(candidate, fingerprint, [], False, False, False)
cp_iq = CarInterface.get_params_iq(cp, candidate, fingerprint, [], False, False, False)
assert bool(cp_iq.iqSafetyFlags & ToyotaSafetyFlagsIQ.LKAS_HUD) is expected

View File

@@ -679,7 +679,7 @@ class CarState(CarStateBase):
if self.CP.carFingerprint == CAR.PORSCHE_MACAN_MK1:
ret.gearShifter = self.parse_gear_shifter(self.CCP.shifter_values.get(pt_cp.vl["Getriebe_03"]["GE_Waehlhebel"], None))
elif self.CP.transmissionType == TransmissionType.manual:
reverse = bool(pt_cp.vl["Gateway_05"]["BCM1_Rueckfahrlicht_Schalter"])
reverse = bool(br_cp.vl["Gateway_05"]["BCM1_Rueckfahrlicht_Schalter"])
ret.gearShifter = GearShifter.reverse if reverse else GearShifter.drive
else:
ret.gearShifter = GearShifter.drive

View File

@@ -8,7 +8,7 @@ from iqdbc.car.volkswagen.carcontroller import CarController
from iqdbc.car.volkswagen.carstate import CarState
from iqdbc.car.volkswagen.values import (
CAR, CanBus, DashcamOnlyReason, MLB_ACC_COORDINATOR_MSGS, MLB_GEARBOX_MSGS, MLB_MSG_ACC_10,
MLB_MSG_LH_EPS_03, NetworkLocation, RADAR_DISABLE_STATE, TransmissionType,
MLB_MSG_GATEWAY_05, MLB_MSG_LH_EPS_03, NetworkLocation, RADAR_DISABLE_STATE, TransmissionType,
VolkswagenFlags, VolkswagenSafetyFlags, VolkswagenFlagsIQ, get_longitudinal_stopping_speed_override,
)
from iqdbc.car.volkswagen.radar_interface import RadarInterface
@@ -115,7 +115,11 @@ class CarInterface(CarInterfaceBase):
if fingerprinted and MLB_MSG_LH_EPS_03 not in pt_msgs:
ret.flags |= VolkswagenFlagsIQ.IQ_MLB_NO_HCA_EPS.value
if fingerprinted and not any(msg in pt_msgs for msg in MLB_GEARBOX_MSGS):
all_msgs = ecan_msgs | fingerprint[1]
gearbox_seen = any(msg in all_msgs for msg in MLB_GEARBOX_MSGS)
transmission_ecu = any(fw.ecu == structs.CarParams.Ecu.transmission for fw in car_fw)
reverse_switch_seen = MLB_MSG_GATEWAY_05 in fingerprint[1]
if fingerprinted and not gearbox_seen and not transmission_ecu and reverse_switch_seen:
ret.transmissionType = TransmissionType.manual
elif ret.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):

View File

@@ -9,9 +9,9 @@ from iqdbc.car import Bus, DT_CTRL, structs
from iqdbc.car.volkswagen.carstate import CarState
from iqdbc.car.structs import CarParams
from iqdbc.car.volkswagen.interface import CarInterface
from iqdbc.car.volkswagen.values import (CAR, FW_QUERY_CONFIG, MLB_ACC_COORDINATOR_MSGS, MLB_MSG_ACC_10,
MLB_MSG_LH_EPS_03, WMI, VolkswagenFlags, VolkswagenFlagsIQ,
VolkswagenSafetyFlags)
from iqdbc.car.volkswagen.values import (CAR, FW_QUERY_CONFIG, MLB_ACC_COORDINATOR_MSGS, MLB_GEARBOX_MSGS, MLB_MSG_ACC_10,
MLB_MSG_GATEWAY_05, MLB_MSG_GETRIEBE_01, MLB_MSG_LH_EPS_03, WMI, VolkswagenFlags,
VolkswagenFlagsIQ, VolkswagenSafetyFlags)
from iqdbc.car.volkswagen.fingerprints import FW_VERSIONS
Ecu = CarParams.Ecu
@@ -333,6 +333,58 @@ def test_mlb_manual_gear_follows_the_reverse_light_switch():
assert _run(a4, lambda: _a4_mk4_frames(packer, reverse=False)).gearShifter == structs.CarState.GearShifter.drive
def _q5_params(bus0, bus1=(), car_fw=()):
fingerprints = _mlb_fingerprint(0, bus0)
fingerprints[1] = {msg: 8 for msg in bus1}
fingerprints[2] = {msg: 8 for msg in MLB_ECAN_CAMERA}
return CarInterface.get_params(CAR.AUDI_Q5_MK1, fingerprints, list(car_fw), alpha_long=False, is_release=False, docs=False)
MLB_ECAN_GATEWAY_NO_GEARBOX = tuple(msg for msg in MLB_ECAN_GATEWAY if msg not in MLB_GEARBOX_MSGS)
def test_mlb_gearbox_on_the_powertrain_bus_keeps_automatic():
params = _q5_params(MLB_ECAN_GATEWAY_NO_GEARBOX, bus1=(MLB_MSG_GETRIEBE_01, MLB_MSG_GATEWAY_05))
assert params.transmissionType == CarParams.TransmissionType.automatic
def test_mlb_transmission_ecu_firmware_keeps_automatic():
transmission = CarParams.CarFw.new_message(ecu=Ecu.transmission, address=0x7e1)
params = _q5_params(MLB_ECAN_GATEWAY_NO_GEARBOX, bus1=(MLB_MSG_GATEWAY_05,), car_fw=(transmission,))
assert params.transmissionType == CarParams.TransmissionType.automatic
def test_mlb_reverse_switch_on_the_extended_can_alone_keeps_automatic():
params = _q5_params(MLB_ECAN_GATEWAY_NO_GEARBOX + (MLB_MSG_GATEWAY_05,))
assert params.transmissionType == CarParams.TransmissionType.automatic
def test_mlb_manual_needs_no_gearbox_anywhere_and_a_reverse_switch_on_the_powertrain_bus():
params = _q5_params(MLB_ECAN_GATEWAY_NO_GEARBOX, bus1=(MLB_MSG_GATEWAY_05,))
assert params.transmissionType == CarParams.TransmissionType.manual
def test_mlb_manual_gateway_car_reads_reverse_from_the_powertrain_bus():
fingerprints = _mlb_fingerprint(0, MLB_ECAN_GATEWAY_NO_GEARBOX)
fingerprints[1] = {MLB_MSG_GATEWAY_05: 8}
fingerprints[2] = {msg: 8 for msg in MLB_ECAN_CAMERA}
q5 = _build_mlb_car(CAR.AUDI_Q5_MK1, fingerprints)
assert q5.CP.transmissionType == CarParams.TransmissionType.manual
packer = CANPacker("vw_mlb")
frames = lambda reverse: [packer.make_can_msg("Gateway_05", 1, {"BCM1_Rueckfahrlicht_Schalter": int(reverse)})]
assert _run(q5, lambda: frames(True)).gearShifter == structs.CarState.GearShifter.reverse
assert _run(q5, lambda: frames(False)).gearShifter == structs.CarState.GearShifter.drive
assert MLB_MSG_GATEWAY_05 not in q5.can_parsers[Bus.pt].addresses
def test_mlb_automatic_never_subscribes_gateway_05():
q5 = _q5_mk1_car()
q5.update([(int(DT_CTRL * 1e9), [])])
assert MLB_MSG_GATEWAY_05 not in q5.can_parsers[Bus.pt].addresses
assert MLB_MSG_GATEWAY_05 not in q5.can_parsers[Bus.aux].addresses
@pytest.mark.parametrize("button_type", (
structs.CarState.ButtonEvent.Type.setCruise,
structs.CarState.ButtonEvent.Type.resumeCruise,

View File

@@ -348,6 +348,7 @@ MLB_MSG_ACC_01 = 0x109
MLB_MSG_ACC_05 = 0x10D
MLB_MSG_ACC_02 = 0x30C
MLB_MSG_ACC_10 = 0x117
MLB_MSG_GATEWAY_05 = 0x39C
MLB_ACC_COORDINATOR_MSGS = (MLB_MSG_ACC_01, MLB_MSG_ACC_05, MLB_MSG_ACC_02)
MLB_GEARBOX_MSGS = (MLB_MSG_GETRIEBE_01, MLB_MSG_GETRIEBE_02, MLB_MSG_GETRIEBE_03, MLB_MSG_GETRIEBE_04)

View File

@@ -17,5 +17,5 @@ class ToyotaSafetyFlagsIQ:
DEFAULT = 0
UNSUPPORTED_DSU = 1
GAS_INTERCEPTOR = 2
LKAS_HUD = 4

View File

@@ -39,7 +39,6 @@
#define TOYOTA_COMMON_RX_CHECKS(lta) \
{.msg = {{ 0xaa, 0, 8, 83U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
{.msg = {{0x260, 0, 8, 50U, .ignore_counter = true, .ignore_quality_flag=!(lta)}, { 0 }, { 0 }}}, \
{.msg = {{0x412, 2, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 1U}, { 0 }, { 0 }}}, \
#define TOYOTA_RX_CHECKS(lta) \
TOYOTA_COMMON_RX_CHECKS(lta) \
@@ -66,6 +65,9 @@
#define TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK \
{.msg = {{0x201, 0, 6, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
#define TOYOTA_LKAS_HUD_ADDR_CHECK \
{.msg = {{0x412, 2, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 1U}, { 0 }, { 0 }}}, \
static bool toyota_secoc = false;
static bool toyota_alt_brake = false;
static bool toyota_stock_longitudinal = false;
@@ -433,6 +435,7 @@ static safety_config toyota_init(uint16_t param) {
const uint16_t TOYOTA_PARAM_IQ_UNSUPPORTED_DSU = 1;
const uint16_t TOYTOA_PARAM_IQ_GAS_INTERCEPTOR = 2;
const uint16_t TOYOTA_PARAM_IQ_LKAS_HUD = 4;
#ifdef ALLOW_DEBUG
const uint32_t TOYOTA_PARAM_SECOC = 8UL << TOYOTA_PARAM_OFFSET;
@@ -446,6 +449,7 @@ static safety_config toyota_init(uint16_t param) {
const bool toyota_unsupported_dsu = GET_FLAG(current_safety_param_iq, TOYOTA_PARAM_IQ_UNSUPPORTED_DSU);
enable_gas_interceptor = GET_FLAG(current_safety_param_iq, TOYTOA_PARAM_IQ_GAS_INTERCEPTOR);
const bool toyota_lkas_hud = GET_FLAG(current_safety_param_iq, TOYOTA_PARAM_IQ_LKAS_HUD);
// gas interceptor should not be used if openpilot is not controlling longitudinal or is a TSK car
if (toyota_stock_longitudinal || toyota_secoc) {
@@ -471,6 +475,7 @@ static safety_config toyota_init(uint16_t param) {
static RxCheck toyota_secoc_rx_checks[] = {
TOYOTA_SECOC_RX_CHECKS
TOYOTA_PCM_CRUISE_2_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
SET_RX_CHECKS(toyota_secoc_rx_checks, ret);
@@ -479,6 +484,7 @@ static safety_config toyota_init(uint16_t param) {
static RxCheck toyota_lta_rx_checks[] = {
TOYOTA_RX_CHECKS(true)
TOYOTA_PCM_CRUISE_2_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
SET_RX_CHECKS(toyota_lta_rx_checks, ret);
@@ -486,18 +492,22 @@ static safety_config toyota_init(uint16_t param) {
static RxCheck toyota_lka_rx_checks[] = {
TOYOTA_RX_CHECKS(false)
TOYOTA_PCM_CRUISE_2_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
static RxCheck toyota_lka_alt_brake_rx_checks[] = {
TOYOTA_ALT_BRAKE_RX_CHECKS(false)
TOYOTA_PCM_CRUISE_2_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
static RxCheck toyota_lka_unsupported_dsu_rx_checks[] = {
TOYOTA_RX_CHECKS(false)
TOYOTA_DSU_CRUISE_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
static RxCheck toyota_lka_alt_brake_unsupported_dsu_rx_checks[] = {
TOYOTA_ALT_BRAKE_RX_CHECKS(false)
TOYOTA_DSU_CRUISE_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
if (!toyota_alt_brake) {
@@ -523,6 +533,7 @@ static safety_config toyota_init(uint16_t param) {
TOYOTA_RX_CHECKS(true)
TOYOTA_PCM_CRUISE_2_ADDR_CHECK
TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
SET_RX_CHECKS(toyota_lta_interceptor_rx_checks, ret);
@@ -531,21 +542,25 @@ static safety_config toyota_init(uint16_t param) {
TOYOTA_RX_CHECKS(false)
TOYOTA_PCM_CRUISE_2_ADDR_CHECK
TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
static RxCheck toyota_lka_alt_brake_interceptor_rx_checks[] = {
TOYOTA_ALT_BRAKE_RX_CHECKS(false)
TOYOTA_PCM_CRUISE_2_ADDR_CHECK
TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
static RxCheck toyota_lka_unsupported_dsu_interceptor_rx_checks[] = {
TOYOTA_RX_CHECKS(false)
TOYOTA_DSU_CRUISE_ADDR_CHECK
TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
static RxCheck toyota_lka_alt_brake_unsupported_dsu_interceptor_rx_checks[] = {
TOYOTA_ALT_BRAKE_RX_CHECKS(false)
TOYOTA_DSU_CRUISE_ADDR_CHECK
TOYOTA_GAS_INTERCEPTOR_ADDR_CHECK
TOYOTA_LKAS_HUD_ADDR_CHECK
};
if (!toyota_alt_brake) {
@@ -564,6 +579,10 @@ static safety_config toyota_init(uint16_t param) {
}
}
if (!toyota_lkas_hud) {
ret.rx_checks_len -= 1;
}
return ret;
}

View File

@@ -21,8 +21,8 @@ TOYOTA_COMMON_LONG_TX_MSGS = [[0x283, 0], [0x2E6, 0], [0x2E7, 0], [0x33E, 0], [0
GAS_INTERCEPTOR_TX_MSGS = [[0x200, 0]]
UNSUPPORTED_DSU = [
{"SAFETY_PARAM_IQ": ToyotaSafetyFlagsIQ.DEFAULT},
{"SAFETY_PARAM_IQ": ToyotaSafetyFlagsIQ.UNSUPPORTED_DSU},
{"SAFETY_PARAM_IQ": ToyotaSafetyFlagsIQ.LKAS_HUD},
{"SAFETY_PARAM_IQ": ToyotaSafetyFlagsIQ.UNSUPPORTED_DSU | ToyotaSafetyFlagsIQ.LKAS_HUD},
]
@@ -33,7 +33,7 @@ class TestToyotaSafetyBase(common.CarSafetyTest, common.LongitudinalAccelSafetyT
FWD_BLACKLISTED_ADDRS = {2: [0x2E4, 0x412, 0x191, 0x343]}
EPS_SCALE = 73
SAFETY_PARAM_IQ: int = 0
SAFETY_PARAM_IQ: int = ToyotaSafetyFlagsIQ.LKAS_HUD
packer: CANPackerSafety
safety: libsafety_py.LibSafety
@@ -96,6 +96,9 @@ class TestToyotaSafetyBase(common.CarSafetyTest, common.LongitudinalAccelSafetyT
return self.packer.make_can_msg_safety("LKAS_HUD", 2, values)
def test_enable_control_allowed_with_aol_button(self):
self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ | ToyotaSafetyFlagsIQ.LKAS_HUD)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota, self.safety.get_current_safety_param())
self.safety.init_tests()
for enable_aol in (True, False):
with self.subTest("enable_aol", aol_enabled=enable_aol):
self.safety.set_aol_params(enable_aol, False, False)
@@ -120,6 +123,16 @@ class TestToyotaSafetyBase(common.CarSafetyTest, common.LongitudinalAccelSafetyT
self.safety.set_controls_allowed_lat(False)
self.safety.set_aol_params(False, False, False)
def test_lkas_button_requires_lkas_hud(self):
self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ & ~ToyotaSafetyFlagsIQ.LKAS_HUD)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota, self.safety.get_current_safety_param())
self.safety.init_tests()
self.safety.set_aol_params(True, False, False)
button_state = self.safety.get_aol_button_press()
self._rx(self._lkas_button_msg(True))
self.assertEqual(button_state, self.safety.get_aol_button_press())
self.assertFalse(self.safety.get_controls_allowed_lat())
def test_diagnostics(self, stock_longitudinal: bool = False, ecu_disabled: bool = True):
for should_tx, msg in ((False, b"\x6D\x02\x3E\x00\x00\x00\x00\x00"), # fwdCamera tester present
(False, b"\x0F\x03\xAA\xAA\x00\x00\x00\x00"), # non-tester present
@@ -250,6 +263,7 @@ class TestToyotaSafetyAngle(TestToyotaSafetyBase, common.AngleSteeringSafetyTest
def setUp(self):
self.packer = CANPackerSafety("toyota_nodsu_pt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota, self.EPS_SCALE | ToyotaSafetyFlags.LTA)
self.safety.init_tests()
@@ -431,6 +445,7 @@ class TestToyotaStockLongitudinalAngle(TestToyotaStockLongitudinalBase, TestToyo
def setUp(self):
self.packer = CANPackerSafety("toyota_nodsu_pt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota,
self.EPS_SCALE | ToyotaSafetyFlags.STOCK_LONGITUDINAL | ToyotaSafetyFlags.LTA)
self.safety.init_tests()
@@ -445,6 +460,7 @@ class TestToyotaSecOcSafetyBase(TestToyotaSafetyBase):
def setUp(self):
self.packer = CANPackerSafety("toyota_secoc_pt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota,
self.EPS_SCALE | ToyotaSafetyFlags.SECOC)
self.safety.init_tests()
@@ -485,6 +501,7 @@ class TestToyotaSecOcSafetyStockLongitudinal(TestToyotaSecOcSafetyBase, TestToyo
def setUp(self):
self.packer = CANPackerSafety("toyota_secoc_pt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota,
self.EPS_SCALE | ToyotaSafetyFlags.STOCK_LONGITUDINAL | ToyotaSafetyFlags.SECOC)
self.safety.init_tests()
@@ -498,6 +515,7 @@ class TestToyotaSecOcSafety(TestToyotaSecOcSafetyBase):
def setUp(self):
self.packer = CANPackerSafety("toyota_secoc_pt_generated")
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
self.safety.set_safety_hooks(CarParams.SafetyModel.toyota, self.EPS_SCALE | ToyotaSafetyFlags.SECOC)
self.safety.init_tests()