mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-10-28 09:03:46 +08:00
Restore EPS8 Toyota smartDSU ownership
This commit is contained in:
@@ -8,7 +8,7 @@ from opendbc.car.common.pid import PIDController
|
||||
from opendbc.car.secoc import add_mac, build_sync_mac
|
||||
from opendbc.car.interfaces import CarControllerBase
|
||||
from opendbc.car.toyota import toyotacan
|
||||
from opendbc.car.toyota import prius_longitudinal, rav4h_filter, pedal
|
||||
from opendbc.car.toyota import prius_longitudinal, rav4h_filter, pedal, eps8_sdsu
|
||||
from opendbc.car.toyota.door_locks import DoorLocks
|
||||
from opendbc.car.toyota.values import CAR, CarControllerParams, ToyotaFlags, TOYOTA_AUTO_HOLD_CARS, uses_toyota_auto_hold_aeb
|
||||
from opendbc.can import CANPacker
|
||||
@@ -82,6 +82,7 @@ class CarController(CarControllerBase):
|
||||
self.standstill_req = False
|
||||
self.last_standstill = False
|
||||
self.prius_longitudinal = prius_longitudinal.enabled(CP)
|
||||
self.eps8_hybrid = eps8_sdsu.configured(CP) and bool(CP.flags & ToyotaFlags.HYBRID)
|
||||
self.permit_braking = True
|
||||
self.steer_rate_counter = 0
|
||||
self.distance_button = 0
|
||||
@@ -271,6 +272,10 @@ class CarController(CarControllerBase):
|
||||
self.last_standstill = CS.out.standstill
|
||||
if not long_active and CS.out.standstill:
|
||||
self.standstill_req = True
|
||||
elif self.eps8_hybrid:
|
||||
# Retain the existing hybrid resume behavior while active. The shared
|
||||
# owner guard below still holds neutral when LONG or its source is lost.
|
||||
self.standstill_req = not long_active and CS.out.standstill
|
||||
elif rav4h_long or not self.CP.flags & ToyotaFlags.HYBRID.value:
|
||||
should_resume = long_active and actuators.accel > 0 if rav4h_long else actuators.accel > 0
|
||||
if should_resume:
|
||||
|
||||
@@ -178,7 +178,7 @@ class CarState(CarStateBase):
|
||||
if self.CP.flags & ToyotaFlags.TSS2 and not self.CP.flags & ToyotaFlags.DISABLE_RADAR.value:
|
||||
# The radar filter intercepts this message. Preserve stock PCS/AEB
|
||||
# observations without making intercepted ACC_CONTROL a required input.
|
||||
if not self.CP.flags & ToyotaFlags.RADAR_CAN_FILTER:
|
||||
if not self.CP.flags & ToyotaFlags.RADAR_CAN_FILTER and not rav4h_filter_configured(self.CP):
|
||||
self.acc_type = cp_acc.vl["ACC_CONTROL"]["ACC_TYPE"]
|
||||
ret.stockFcw = bool(cp_acc.vl["PCS_HUD"]["FCW"])
|
||||
|
||||
@@ -226,7 +226,7 @@ class CarState(CarStateBase):
|
||||
buttonEvents.extend(create_button_events(1, 0, {1: ButtonType.lkas}) +
|
||||
create_button_events(0, 1, {1: ButtonType.lkas}))
|
||||
|
||||
if self.CP.flags & ToyotaFlags.TSS2 and not (self.CP.flags & (ToyotaFlags.RADAR_ACC | ToyotaFlags.SECOC)):
|
||||
if self.CP.flags & ToyotaFlags.TSS2 and not (self.CP.flags & (ToyotaFlags.RADAR_ACC | ToyotaFlags.SECOC | ToyotaFlags.LONG_FILTER)):
|
||||
# distance button is wired to the ACC module (camera or radar)
|
||||
prev_distance_button = self.distance_button
|
||||
self.distance_button = cp_acc.vl["ACC_CONTROL"]["DISTANCE"]
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
"""Eight-byte EPS smartDSU ownership, separate from EPS5 and radar advertisements."""
|
||||
|
||||
from opendbc.car import structs
|
||||
from opendbc.car.toyota.values import CAR, ToyotaFlags
|
||||
|
||||
CARS = frozenset(
|
||||
(
|
||||
CAR.TOYOTA_ALPHARD_TSS2,
|
||||
CAR.TOYOTA_AVALON_TSS2,
|
||||
CAR.TOYOTA_CAMRY_TSS2,
|
||||
CAR.TOYOTA_COROLLA_TSS2,
|
||||
CAR.TOYOTA_HIGHLANDER_TSS2,
|
||||
CAR.TOYOTA_PRIUS_TSS2,
|
||||
CAR.TOYOTA_RAV4_TSS2,
|
||||
CAR.TOYOTA_MIRAI,
|
||||
CAR.LEXUS_ES_TSS2,
|
||||
CAR.LEXUS_NX_TSS2,
|
||||
CAR.LEXUS_LC_TSS2,
|
||||
CAR.LEXUS_RX_TSS2,
|
||||
CAR.LEXUS_IS_TSS2,
|
||||
CAR.LEXUS_RC_TSS2,
|
||||
CAR.TOYOTA_AVALON_2019,
|
||||
CAR.LEXUS_LS,
|
||||
CAR.TOYOTA_CAMRY,
|
||||
CAR.TOYOTA_CHR,
|
||||
CAR.TOYOTA_CHR_TSS2,
|
||||
CAR.TOYOTA_RAV4_TSS2_2022,
|
||||
CAR.TOYOTA_RAV4_TSS2_2023,
|
||||
)
|
||||
)
|
||||
WORDS = frozenset((0x8049, 0x8249, 0x8449, 0x8649))
|
||||
|
||||
|
||||
def words(candidate):
|
||||
return (0x8449, 0x8649) if candidate == CAR.TOYOTA_RAV4_TSS2_2023 else (0x8049, 0x8249)
|
||||
|
||||
|
||||
def hardware_supported(candidate, fingerprint, car_fw):
|
||||
if (
|
||||
candidate not in CARS
|
||||
or fingerprint.get(0, {}).get(0x2FF) != 8
|
||||
or any(0x2FF in messages for bus, messages in fingerprint.items() if bus != 0)
|
||||
or any(address in messages for messages in fingerprint.values() for address in (0x201, 0x2AA))
|
||||
):
|
||||
return False
|
||||
# TSS2 camera ACC is normally on bus2. It is not evidence of a DSU bypass.
|
||||
if not CAR(candidate).config.flags & ToyotaFlags.TSS2 and any(address in fingerprint.get(2, {}) for address in (0x343, 0x4CB)):
|
||||
return False
|
||||
from opendbc.car.toyota.fingerprints import FW_VERSIONS
|
||||
|
||||
known = FW_VERSIONS[candidate]
|
||||
required = {structs.CarParams.Ecu.eps, structs.CarParams.Ecu.fwdCamera}
|
||||
if any(ecu == structs.CarParams.Ecu.fwdRadar for ecu, _, _ in known):
|
||||
required.add(structs.CarParams.Ecu.fwdRadar)
|
||||
for ecu in required:
|
||||
observed = [fw for fw in car_fw if fw.ecu == ecu]
|
||||
if not observed or any(
|
||||
fw.logging or fw.bus != 0 or fw.brand != "toyota" or bytes(fw.fwVersion) not in known.get((ecu, fw.address, fw.subAddress or None), ()) for fw in observed
|
||||
):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def apply(cp, alpha_long):
|
||||
cp.flags |= int(ToyotaFlags.LONG_FILTER)
|
||||
cp.flags &= ~int(ToyotaFlags.DISABLE_RADAR)
|
||||
gated = bool(cp.flags & (ToyotaFlags.NO_DSU | ToyotaFlags.RADAR_ACC))
|
||||
cp.alphaLongitudinalAvailable = gated
|
||||
cp.openpilotLongitudinalControl = bool(alpha_long or not gated or cp.flags & ToyotaFlags.TSS2 and not cp.flags & ToyotaFlags.RADAR_ACC)
|
||||
cp.safetyConfigs[0].safetyParam = words(cp.carFingerprint)[not cp.openpilotLongitudinalControl]
|
||||
|
||||
|
||||
def configured(cp):
|
||||
if (
|
||||
cp is None
|
||||
or cp.brand != "toyota"
|
||||
or cp.carFingerprint not in CARS
|
||||
or cp.notCar
|
||||
or cp.passive
|
||||
or cp.dashcamOnly
|
||||
or cp.secOcRequired
|
||||
or not cp.pcmCruise
|
||||
or len(cp.safetyConfigs) != 1
|
||||
):
|
||||
return False
|
||||
required = int(CAR(cp.carFingerprint).config.flags | ToyotaFlags.LONG_FILTER)
|
||||
if CAR(cp.carFingerprint).config.flags & ToyotaFlags.TSS2:
|
||||
required |= int(ToyotaFlags.RAISED_ACCEL_LIMIT)
|
||||
allowed = required | int(ToyotaFlags.HYBRID | ToyotaFlags.HAS_BSM)
|
||||
if cp.carFingerprint in (CAR.TOYOTA_RAV4_TSS2_2022, CAR.TOYOTA_RAV4_TSS2_2023):
|
||||
allowed |= int(ToyotaFlags.ARS510_RADAR | ToyotaFlags.ARS510_FUSED)
|
||||
expected_type = structs.CarParams.SteerControlType.angle if cp.carFingerprint == CAR.TOYOTA_RAV4_TSS2_2023 else structs.CarParams.SteerControlType.torque
|
||||
return bool(
|
||||
cp.flags & required == required
|
||||
and not int(cp.flags) & ~allowed
|
||||
and (not cp.flags & ToyotaFlags.ARS510_FUSED or cp.flags & ToyotaFlags.ARS510_RADAR)
|
||||
and cp.steerControlType == expected_type
|
||||
and cp.safetyConfigs[0].safetyModel == structs.CarParams.SafetyModel.toyota
|
||||
and cp.safetyConfigs[0].safetyParam == words(cp.carFingerprint)[not cp.openpilotLongitudinalControl]
|
||||
)
|
||||
|
||||
|
||||
def prepare_stock(cp):
|
||||
if not configured(cp):
|
||||
return False
|
||||
cp.openpilotLongitudinalControl = False
|
||||
cp.safetyConfigs[0].safetyParam = words(cp.carFingerprint)[1]
|
||||
cp.autoResumeSng = False
|
||||
return True
|
||||
@@ -189,12 +189,16 @@ class CarInterface(CarInterfaceBase):
|
||||
stop_and_go = True
|
||||
elif candidate == CAR.TOYOTA_RAV4H and 0x2FF in fingerprint.get(0, {}):
|
||||
ret.dashcamOnly = True
|
||||
from opendbc.car.toyota import eps8_sdsu
|
||||
eps8_filter = eps8_sdsu.hardware_supported(candidate, fingerprint, car_fw)
|
||||
if eps8_filter:
|
||||
eps8_sdsu.apply(ret, alpha_long)
|
||||
# Toyota EPS accepts lateral commands down to zero. Keep the existing
|
||||
# native/axis/fault gates; a stock cruise stop does not withdraw steering.
|
||||
ret.steerAtStandstill = ret.minSteerSpeed <= 0.
|
||||
ret.autoResumeSng = ret.openpilotLongitudinalControl and (
|
||||
(rav4h_sdsu and candidate in (CAR.TOYOTA_RAV4H, CAR.TOYOTA_HIGHLANDER, CAR.TOYOTA_SIENNA)) or
|
||||
not ret.flags & ToyotaFlags.LONG_FILTER)
|
||||
(eps8_filter and bool(ret.flags & ToyotaFlags.TSS2)) or not ret.flags & ToyotaFlags.LONG_FILTER)
|
||||
|
||||
if radar_filter and not ret.flags & ToyotaFlags.TSS2:
|
||||
ret.autoResumeSng = False # Preserve the pre-TSS2 stock stop timer.
|
||||
@@ -206,7 +210,7 @@ class CarInterface(CarInterfaceBase):
|
||||
# to a negative value, so it won't matter.
|
||||
ret.minEnableSpeed = -1. if stop_and_go else MIN_ACC_SPEED
|
||||
|
||||
if ret.flags & (ToyotaFlags.TSS2 | ToyotaFlags.LONG_FILTER) and not rav4h_sdsu:
|
||||
if ret.flags & ToyotaFlags.TSS2 or ret.flags & ToyotaFlags.LONG_FILTER and not (rav4h_sdsu or eps8_filter):
|
||||
ret.flags |= ToyotaFlags.RAISED_ACCEL_LIMIT.value
|
||||
|
||||
# Hybrids have much quicker longitudinal actuator response
|
||||
|
||||
@@ -34,6 +34,9 @@ def hardware_supported(candidate, fingerprint, car_fw):
|
||||
|
||||
|
||||
def configured(cp):
|
||||
from opendbc.car.toyota import eps8_sdsu
|
||||
if eps8_sdsu.configured(cp):
|
||||
return True
|
||||
if (cp is None or cp.brand != "toyota" or cp.carFingerprint not in EPS5_SDSU_CARS or
|
||||
not cp.pcmCruise or cp.dashcamOnly or cp.notCar or cp.passive or
|
||||
cp.steerControlType != structs.CarParams.SteerControlType.torque or len(cp.safetyConfigs) != 1):
|
||||
@@ -58,6 +61,9 @@ def enabled(cp):
|
||||
|
||||
|
||||
def prepare_stock(cp):
|
||||
from opendbc.car.toyota import eps8_sdsu
|
||||
if eps8_sdsu.prepare_stock(cp):
|
||||
return True
|
||||
if not configured(cp):
|
||||
return False
|
||||
cp.flags &= ~int(ToyotaFlags.AUTO_BRAKE_HOLD)
|
||||
|
||||
@@ -156,7 +156,7 @@ static bool toyota_get_quality_flag_valid(const CANPacket_t *msg) {
|
||||
}
|
||||
} else {
|
||||
}
|
||||
if (toyota_aol_rav4h_filter && (msg->addr == 0x2FFU)) {
|
||||
if (toyota_sdsu_status && (msg->addr == 0x2FFU)) {
|
||||
const unsigned int state = msg->data[2] >> 4U;
|
||||
valid = (GET_LEN(msg) == 8U) && ((state == 0U) || (state == 7U));
|
||||
}
|
||||
@@ -211,7 +211,7 @@ static void toyota_rx_hook(const CANPacket_t *msg) {
|
||||
((unsigned int)msg->data[2] << 8U) + msg->data[3]) / 2U;
|
||||
gas_pressed = gas > 805U;
|
||||
}
|
||||
if (toyota_aol_rav4h_filter && (msg->addr == 0x2FFU) && (GET_LEN(msg) == 8U)) {
|
||||
if (toyota_sdsu_status && (msg->addr == 0x2FFU) && (GET_LEN(msg) == 8U)) {
|
||||
// Only normal sDSU state owns replacement LONG. AEB stays healthy and retains independent LAT.
|
||||
toyota_sdsu_control = (msg->data[2] >> 4U) == 0U;
|
||||
}
|
||||
@@ -353,8 +353,8 @@ static bool toyota_tx_hook(const CANPacket_t *msg) {
|
||||
!gas_pressed && !brake_pressed && GET_BIT(msg, 39U) && (gas1 >= 475U) && (gas1 <= 1275U) && (gas2 >= 949U) && (gas2 <= 1749U) &&
|
||||
(gas2 >= (gas1 + 473U)) && (gas2 <= (gas1 + 475U))));
|
||||
}
|
||||
const bool filter_ready = !(toyota_aol_rav4h_filter || toyota_pedal) || aol_rx_healthy();
|
||||
const bool filter_long_ready = filter_ready && (!toyota_aol_rav4h_filter || toyota_sdsu_control);
|
||||
const bool filter_ready = !(toyota_sdsu_status || toyota_pedal) || aol_rx_healthy();
|
||||
const bool filter_long_ready = filter_ready && (!toyota_sdsu_status || toyota_sdsu_control);
|
||||
|
||||
// Check if msg is sent on BUS 0
|
||||
if (msg->bus == 0U) {
|
||||
@@ -580,7 +580,7 @@ static safety_config toyota_init(uint16_t param) {
|
||||
|
||||
toyota_alt_brake = GET_FLAG(param, TOYOTA_PARAM_ALT_BRAKE);
|
||||
toyota_stock_longitudinal = GET_FLAG(param, TOYOTA_PARAM_STOCK_LONGITUDINAL);
|
||||
toyota_radar_diagnostics_allowed = !toyota_stock_longitudinal && !toyota_secoc && (param != 0x1049U) && (param != 0x1449U);
|
||||
toyota_radar_diagnostics_allowed = !toyota_stock_longitudinal && !toyota_secoc && (param != 0x1049U) && (param != 0x1449U) && !toyota_eps8_sdsu;
|
||||
toyota_lta = GET_FLAG(param, TOYOTA_PARAM_LTA);
|
||||
toyota_dbc_eps_torque_factor = param & TOYOTA_EPS_FACTOR;
|
||||
|
||||
@@ -601,7 +601,7 @@ static safety_config toyota_init(uint16_t param) {
|
||||
if (toyota_stock_longitudinal) {
|
||||
SET_TX_MSGS(TOYOTA_TX_MSGS, ret);
|
||||
} else {
|
||||
if ((param == 0x1049U) || (param == 0x9049U) || (param == 0x1449U)) {
|
||||
if ((param == 0x1049U) || (param == 0x9049U) || (param == 0x1449U) || toyota_eps8_sdsu) {
|
||||
SET_TX_MSGS(TOYOTA_FILTER_LONG_TX_MSGS_SET, ret);
|
||||
} else {
|
||||
SET_TX_MSGS(TOYOTA_LONG_TX_MSGS, ret);
|
||||
@@ -619,9 +619,13 @@ static safety_config toyota_init(uint16_t param) {
|
||||
// Check the quality flag for angle measurement when using LTA, since it's not set on TSS-P cars
|
||||
static RxCheck toyota_lta_rx_checks[] = {
|
||||
TOYOTA_RX_CHECKS(true)
|
||||
{.msg = {{0x2FF, 0, 8, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = false}, { 0 }, { 0 }}},
|
||||
};
|
||||
|
||||
SET_RX_CHECKS(toyota_lta_rx_checks, ret);
|
||||
if (!toyota_sdsu_status) {
|
||||
ret.rx_checks_len -= 1;
|
||||
}
|
||||
} else {
|
||||
// The final entry belongs only to the exact RAV4H filter profile. Share
|
||||
// the ordinary checks instead of duplicating their mutable status table.
|
||||
@@ -637,12 +641,12 @@ static safety_config toyota_init(uint16_t param) {
|
||||
.ignore_checksum = !toyota_pedal, .ignore_counter = !toyota_pedal,
|
||||
.max_counter = toyota_pedal ? 15U : 0U, .ignore_quality_flag = toyota_alt_cruise};
|
||||
SET_RX_CHECKS(toyota_lka_rx_checks, ret);
|
||||
if (!toyota_pedal && !toyota_alt_cruise && (param != 0x9049U) && (param != 0x9249U)) {
|
||||
if (!toyota_pedal && !toyota_alt_cruise && !toyota_sdsu_status) {
|
||||
ret.rx_checks_len -= 1; // Ordinary profiles do not require smartDSU.
|
||||
}
|
||||
}
|
||||
|
||||
if (((param & 0xC000U) != 0U) && !toyota_alt_cruise && (param != 0x9049U) && (param != 0x9249U)) {
|
||||
if (((param & 0xC000U) != 0U) && !toyota_alt_cruise && !toyota_sdsu_status) {
|
||||
ret.tx_msgs_len = 0;
|
||||
}
|
||||
if (((param & 0x2000U) != 0U) && !toyota_pedal) {
|
||||
|
||||
@@ -8,6 +8,8 @@ static bool toyota_aol_secoc = false;
|
||||
static bool toyota_aol_stock = false;
|
||||
static bool toyota_aol_lta = false;
|
||||
static bool toyota_aol_rav4h_filter = false;
|
||||
static bool toyota_sdsu_status = false;
|
||||
static bool toyota_eps8_sdsu = false;
|
||||
static bool toyota_sdsu_control = false;
|
||||
static bool toyota_aol_main = false;
|
||||
static bool toyota_aol_drive = false;
|
||||
@@ -51,7 +53,7 @@ static uint8_t toyota_aol_permission(void) {
|
||||
if (fresh && toyota_aol_main && toyota_aol_drive && toyota_aol_doors_closed && toyota_aol_eps) {
|
||||
permission = request & 1U;
|
||||
if (!toyota_aol_stock && controls_allowed && toyota_aol_belt && !gas_pressed && !brake_pressed &&
|
||||
(!toyota_aol_rav4h_filter || toyota_sdsu_control)) {
|
||||
(!toyota_sdsu_status || toyota_sdsu_control)) {
|
||||
permission |= request & 2U;
|
||||
}
|
||||
}
|
||||
@@ -123,17 +125,19 @@ static void toyota_aol_observe(const CANPacket_t *msg) {
|
||||
|
||||
static void toyota_aol_configure(uint16_t param) {
|
||||
toyota_aol_reset();
|
||||
toyota_eps8_sdsu = (param == 0x8049U) || (param == 0x8249U) || (param == 0x8449U) || (param == 0x8649U);
|
||||
toyota_alt_cruise = param == 0x424DU;
|
||||
toyota_aol_lta = (param == 0x449U) || (param == 0x649U) || (param == 0x1449U) || (param == 0x1649U);
|
||||
toyota_aol_lta = (param == 0x449U) || (param == 0x649U) || (param == 0x1449U) || (param == 0x1649U) || (param == 0x8449U) || (param == 0x8649U);
|
||||
toyota_pedal = (param == 0x2049U) || (param == 0x2249U);
|
||||
toyota_aol_rav4h_filter = (param == 0x9049U) || (param == 0x9249U);
|
||||
toyota_aol_stock = (param == 585U) || (param == 4681U) || (param == 0x9249U) || (param == 0x2249U) || toyota_alt_cruise || (param == 0x649U) || (param == 0x1649U);
|
||||
toyota_sdsu_status = toyota_aol_rav4h_filter || toyota_eps8_sdsu;
|
||||
toyota_aol_stock = (param == 585U) || (param == 4681U) || (param == 0x9249U) || (param == 0x2249U) || toyota_alt_cruise || (param == 0x649U) || (param == 0x1649U) || (param == 0x8249U) || (param == 0x8649U);
|
||||
#ifdef ALLOW_DEBUG
|
||||
toyota_aol_secoc = (param == 2121U);
|
||||
#else
|
||||
toyota_aol_secoc = false;
|
||||
#endif
|
||||
toyota_aol_enabled = (toyota_aol_lta && (alternative_experience == 32)) || (toyota_aol_stock && (alternative_experience == 32)) ||
|
||||
toyota_aol_enabled = (toyota_eps8_sdsu && (alternative_experience == 32)) || (toyota_aol_lta && (alternative_experience == 32)) || (toyota_aol_stock && (alternative_experience == 32)) ||
|
||||
#ifdef ALLOW_DEBUG
|
||||
(toyota_aol_secoc && (alternative_experience == 32)) ||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
import pytest
|
||||
from opendbc.can import CANPacker
|
||||
from opendbc.car import structs
|
||||
from opendbc.safety.tests.libsafety import libsafety_py
|
||||
from openpilot.starpilot.car.toyota.tests import test_pedal_caller_native as helpers
|
||||
|
||||
source_matched_native = helpers.source_matched_native
|
||||
WORDS = (0x8049, 0x8249, 0x8449, 0x8649)
|
||||
|
||||
|
||||
class Physical:
|
||||
def __init__(self, word, experience=32):
|
||||
self.native = libsafety_py.libsafety
|
||||
self.native.init_tests()
|
||||
self.native.set_alternative_experience(experience)
|
||||
assert self.native.set_safety_hooks(structs.CarParams.SafetyModel.toyota, word) == 0
|
||||
self.native.set_aol_test_heartbeat(True)
|
||||
self.word, self.now = word, 1_000_000
|
||||
self.packer = CANPacker("toyota_nodsu_pt_generated")
|
||||
|
||||
def tick(self, *, cruise=True, status=0, bad=None, **fields):
|
||||
self.now += 10_000
|
||||
self.native.set_timer(self.now)
|
||||
frames = helpers.physical(self.packer, cruise=cruise, **fields)
|
||||
frames = [f for f in frames if f[0] not in (0x260, 0x262)]
|
||||
frames += [
|
||||
self.packer.make_can_msg("STEER_TORQUE_SENSOR", 0, {"STEER_ANGLE": 0.0573}),
|
||||
self.packer.make_can_msg("EPS_STATUS", 0, {"LKA_STATE": fields.get("eps", 1), "LTA_STATE": fields.get("eps", 1)}),
|
||||
]
|
||||
if status is not None:
|
||||
frames.append(self.packer.make_can_msg("SDSU", 0, {"STATE": status}))
|
||||
for address, data, bus in frames:
|
||||
if address == 0x262 and bad == "eps_checksum":
|
||||
data = data[:-1] + bytes([data[-1] ^ 1])
|
||||
if address == 0x262 and bad == "eps_length":
|
||||
data = data[:5]
|
||||
if address == 0x2FF and bad == "status_length":
|
||||
data = data[:7]
|
||||
if address == 0x2FF and bad == "status_bus":
|
||||
bus = 2
|
||||
self.native.safety_rx_hook(libsafety_py.make_CANPacket(address, bus, data))
|
||||
self.native.safety_tick()
|
||||
self.native.aol_set_host_request(3)
|
||||
|
||||
def accel(self, value=0.1, cancel=0):
|
||||
a, d, b = self.packer.make_can_msg("ACC_CONTROL", 0, {"ACCEL_CMD": value, "CANCEL_REQ": cancel})
|
||||
return self.native.safety_tx_hook(libsafety_py.make_CANPacket(a, b, d))
|
||||
|
||||
def close(self):
|
||||
self.native.set_alternative_experience(0)
|
||||
self.native.set_safety_hooks(structs.CarParams.SafetyModel.noOutput, 0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("word", WORDS)
|
||||
def test_status_lease_state_aeb_and_recovery(word):
|
||||
case = Physical(word)
|
||||
try:
|
||||
assert case.native.aol_get_permission_mask() == 0
|
||||
for _ in range(25):
|
||||
case.tick(cruise=False, status=None)
|
||||
assert case.native.aol_get_permission_mask() == 0
|
||||
for _ in range(25):
|
||||
case.tick(cruise=False)
|
||||
assert case.native.aol_get_permission_mask() == 1
|
||||
for _ in range(25):
|
||||
case.tick()
|
||||
expected = 1 if word & 0x200 else 3
|
||||
assert case.native.aol_get_permission_mask() == expected
|
||||
assert bool(case.accel()) == (expected == 3)
|
||||
case.tick(status=7)
|
||||
assert case.native.safety_config_valid()
|
||||
assert case.native.aol_get_permission_mask() == 1 and not case.accel()
|
||||
case.tick(status=2)
|
||||
assert not case.native.safety_config_valid()
|
||||
assert case.native.aol_get_permission_mask() == 0 and not case.accel()
|
||||
for _ in range(25):
|
||||
case.tick(cruise=False)
|
||||
for _ in range(25):
|
||||
case.tick()
|
||||
assert case.native.aol_get_permission_mask() == expected
|
||||
finally:
|
||||
case.close()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("word", WORDS)
|
||||
@pytest.mark.parametrize("bad", ["eps_checksum", "eps_length", "status_length", "status_bus"])
|
||||
def test_malformed_or_wrong_bus_cannot_refresh_required_sources(word, bad):
|
||||
case = Physical(word)
|
||||
try:
|
||||
for _ in range(25):
|
||||
case.tick(cruise=False)
|
||||
for _ in range(25):
|
||||
case.tick()
|
||||
assert case.native.aol_get_permission_mask() == (1 if word & 0x200 else 3)
|
||||
for _ in range(25):
|
||||
case.tick(bad=bad)
|
||||
assert case.native.aol_get_permission_mask() == 0 and not case.accel()
|
||||
finally:
|
||||
case.close()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("word", WORDS)
|
||||
@pytest.mark.parametrize("fault", ["main", "gear", "eps", "brake", "gas"])
|
||||
def test_physical_permission_withdrawal(word, fault):
|
||||
case = Physical(word)
|
||||
try:
|
||||
for _ in range(25):
|
||||
case.tick(cruise=False)
|
||||
for _ in range(25):
|
||||
case.tick()
|
||||
case.tick(**{"main": {"main": False}, "gear": {"gear": 16}, "eps": {"eps": 9}, "brake": {"brake": True}, "gas": {"gas": True}}[fault])
|
||||
assert case.native.aol_get_permission_mask() == (1 if fault in ("brake", "gas") else 0)
|
||||
assert not case.accel()
|
||||
finally:
|
||||
case.close()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("word", WORDS)
|
||||
def test_ordinary_cruise_and_stock_cancel_only(word):
|
||||
case = Physical(word, 0)
|
||||
try:
|
||||
for _ in range(25):
|
||||
case.tick(cruise=False)
|
||||
for _ in range(25):
|
||||
case.tick()
|
||||
assert case.native.get_controls_allowed()
|
||||
assert bool(case.accel()) == (not word & 0x200)
|
||||
assert case.accel(0, 1)
|
||||
for value in (-3.501, 2.001):
|
||||
assert not case.accel(value)
|
||||
for _ in range(25):
|
||||
case.tick(status=None)
|
||||
assert not case.accel()
|
||||
finally:
|
||||
case.close()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("word", [0x8048, 0x804A, 0x8149, 0x8248, 0x8448, 0x844A, 0x8648, 0x8749, 0xA049])
|
||||
def test_unqualified_adjacent_words_have_no_commands(word):
|
||||
case = Physical(word)
|
||||
try:
|
||||
for _ in range(25):
|
||||
case.tick(cruise=False)
|
||||
for _ in range(25):
|
||||
case.tick()
|
||||
assert case.native.aol_get_permission_mask() == 0 and not case.accel()
|
||||
finally:
|
||||
case.close()
|
||||
@@ -167,7 +167,7 @@ int main() {
|
||||
}
|
||||
|
||||
for (uint32_t word = 0U; word <= 65535U; ++word) {
|
||||
const bool expected = (word == 73U) || (word == 585U) || (word == 4169U) || (word == 4681U) || (word == 2121U) || (word == 0x9049U) || (word == 0x9249U) || (word == 0x2049U) || (word == 0x2249U) || (word == 0x424DU) || (word == 0x449U) || (word == 0x649U) || (word == 0x1449U) || (word == 0x1649U);
|
||||
const bool expected = (word == 73U) || (word == 585U) || (word == 4169U) || (word == 4681U) || (word == 2121U) || (word == 0x9049U) || (word == 0x9249U) || (word == 0x2049U) || (word == 0x2249U) || (word == 0x424DU) || (word == 0x449U) || (word == 0x649U) || (word == 0x1449U) || (word == 0x1649U) || (word == 0x8049U) || (word == 0x8249U) || (word == 0x8449U) || (word == 0x8649U);
|
||||
auto toyota = status();
|
||||
toyota.safety_mode = 2U;
|
||||
toyota.safety_param = static_cast<uint16_t>(word);
|
||||
@@ -432,14 +432,19 @@ int main() {
|
||||
assert(!aol_capable(absent, GM_AOL_PROFILE.mode, VEHICLE_REGISTRY));
|
||||
}
|
||||
|
||||
// One mode28 registry entry admits the ordinary PE transport as well as
|
||||
// the unchanged Ioniq6 profiles; this is not an independent AOL grant.
|
||||
// Ordinary PE transport and the separately qualified LONG/AOL profile
|
||||
// both require the native capability; adjacent unqualified words stay denied.
|
||||
auto pe = status();
|
||||
pe.safety_mode = HYUNDAI_AOL_PROFILE.mode;
|
||||
pe.safety_param = 0x5491U;
|
||||
assert(aol_capable(pe, HYUNDAI_AOL_PROFILE.mode, VEHICLE_REGISTRY));
|
||||
assert(aol_runtime_enabled(false, pe, VEHICLE_REGISTRY));
|
||||
for (uint16_t denied : {0x5490U, 0x5493U, 0x5495U, 0x5411U, 0x54B1U, 0x5691U}) {
|
||||
for (uint16_t admitted : {0x5491U, 0x5495U}) {
|
||||
pe.safety_param = admitted;
|
||||
assert(aol_capable(pe, HYUNDAI_AOL_PROFILE.mode, VEHICLE_REGISTRY));
|
||||
assert(aol_runtime_enabled(false, pe, VEHICLE_REGISTRY));
|
||||
pe.capability_flags = 0U;
|
||||
assert(!aol_capable(pe, HYUNDAI_AOL_PROFILE.mode, VEHICLE_REGISTRY));
|
||||
pe.capability_flags = 1U;
|
||||
}
|
||||
for (uint16_t denied : {0x5490U, 0x5493U, 0x5497U, 0x5411U, 0x54B1U, 0x5691U}) {
|
||||
pe.safety_param = denied;
|
||||
assert(!aol_capable(pe, HYUNDAI_AOL_PROFILE.mode, VEHICLE_REGISTRY));
|
||||
}
|
||||
@@ -481,7 +486,7 @@ int main() {
|
||||
0x7090U, 0x7092U, 0x7208U, 0x720AU, 0x7228U, 0x722AU, 0x7809U, 0x7829U,
|
||||
};
|
||||
for (uint32_t word = 0U; word <= 0xFFFFU; ++word) {
|
||||
bool expected = word == 0x0815U || word == 0x0895U || word == 0x8815U || word == 0x8895U || word == 0x5491U || word == 0x5C91U || word == 0x5C95U;
|
||||
bool expected = word == 0x0815U || word == 0x0895U || word == 0x8815U || word == 0x8895U || word == 0x5491U || word == 0x5C91U || word == 0x5C95U || word == 0x5495U;
|
||||
for (uint16_t stock_word : stock_canfd_words) {
|
||||
expected = expected || word == stock_word;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ from opendbc.car.toyota.values import CAR, ToyotaFlags, ToyotaSafetyFlags, EPS_S
|
||||
from openpilot.starpilot.aol.policy import AolVehiclePolicy
|
||||
from openpilot.starpilot.aol.intent import AolCardIntent, AOL_TOGGLE
|
||||
|
||||
AOL_WORDS = frozenset((73, 585, 4169, 4681, 2121, 0x9049, 0x9249, 0x2049, 0x2249, 0x424D, 0x449, 0x649, 0x1449, 0x1649))
|
||||
AOL_WORDS = frozenset((73, 585, 4169, 4681, 2121, 0x9049, 0x9249, 0x2049, 0x2249, 0x424D, 0x449, 0x649, 0x1449, 0x1649, 0x8049, 0x8249, 0x8449, 0x8649))
|
||||
|
||||
|
||||
SECOC_TORQUE_CARS = frozenset((CAR.TOYOTA_SIENNA_4TH_GEN,))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "selfdrive/pandad/aol_protocol.h"
|
||||
|
||||
inline bool toyota_aol_param(uint16_t param) {
|
||||
return (param == 73U) || (param == 585U) || (param == 4169U) || (param == 4681U) || (param == 2121U) || (param == 0x9049U) || (param == 0x9249U) || (param == 0x2049U) || (param == 0x2249U) || (param == 0x424DU) || (param == 0x449U) || (param == 0x649U) || (param == 0x1449U) || (param == 0x1649U);
|
||||
return (param == 73U) || (param == 585U) || (param == 4169U) || (param == 4681U) || (param == 2121U) || (param == 0x9049U) || (param == 0x9249U) || (param == 0x2049U) || (param == 0x2249U) || (param == 0x424DU) || (param == 0x449U) || (param == 0x649U) || (param == 0x1449U) || (param == 0x1649U) || (param == 0x8049U) || (param == 0x8249U) || (param == 0x8449U) || (param == 0x8649U);
|
||||
}
|
||||
|
||||
inline constexpr AolSafetyProfile TOYOTA_AOL_PROFILE{2U, toyota_aol_param, true};
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
import pytest
|
||||
from opendbc.car import gen_empty_fingerprint
|
||||
from opendbc.car.toyota import eps8_sdsu
|
||||
from opendbc.car.toyota.interface import CarInterface
|
||||
from opendbc.car.toyota.values import CAR, ToyotaFlags
|
||||
from openpilot.starpilot.car.toyota.tests.test_pedal_caller_native import firmware
|
||||
from openpilot.starpilot.car.toyota.aol import qualified
|
||||
|
||||
|
||||
@pytest.mark.parametrize('candidate', sorted(eps8_sdsu.CARS))
|
||||
@pytest.mark.parametrize('alpha', [False, True])
|
||||
def test_eps8_sdsu_factory_and_saved_off(candidate, alpha):
|
||||
fp = gen_empty_fingerprint()
|
||||
fp[0][0x2FF] = 8
|
||||
cp = CarInterface.get_params(candidate, fp, firmware(candidate), alpha, False, False)
|
||||
assert eps8_sdsu.configured(cp) and qualified(cp)
|
||||
long = (
|
||||
alpha
|
||||
or not candidate.config.flags & (ToyotaFlags.NO_DSU | ToyotaFlags.RADAR_ACC)
|
||||
or bool(candidate.config.flags & ToyotaFlags.TSS2 and not candidate.config.flags & ToyotaFlags.RADAR_ACC)
|
||||
)
|
||||
assert cp.openpilotLongitudinalControl == long
|
||||
assert not cp.flags & ToyotaFlags.DISABLE_RADAR
|
||||
assert cp.safetyConfigs[0].safetyParam == eps8_sdsu.words(candidate)[not long]
|
||||
assert eps8_sdsu.prepare_stock(cp)
|
||||
assert eps8_sdsu.configured(cp) and qualified(cp) and not cp.openpilotLongitudinalControl
|
||||
|
||||
|
||||
@pytest.mark.parametrize('candidate', sorted(eps8_sdsu.CARS))
|
||||
@pytest.mark.parametrize('bad', ['length', 'mirror', 'pedal', 'mixed', 'firmware'])
|
||||
def test_eps8_hardware_boundaries(candidate, bad):
|
||||
fp = gen_empty_fingerprint()
|
||||
fp[0][0x2FF] = 8
|
||||
fw = firmware(candidate)
|
||||
if bad == 'length':
|
||||
fp[0][0x2FF] = 4
|
||||
if bad == 'mirror':
|
||||
fp[2][0x2FF] = 8
|
||||
if bad == 'pedal':
|
||||
fp[0][0x201] = 6
|
||||
if bad == 'mixed':
|
||||
fp[0][0x2AA] = 8
|
||||
if bad == 'firmware':
|
||||
fw = []
|
||||
assert not eps8_sdsu.hardware_supported(candidate, fp, fw)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('candidate', [CAR.TOYOTA_RAV4_PRIME, CAR.TOYOTA_SIENNA_4TH_GEN, CAR.TOYOTA_RAV4H, CAR.TOYOTA_PRIUS])
|
||||
def test_other_native_topologies_not_claimed(candidate):
|
||||
fp = gen_empty_fingerprint()
|
||||
fp[0][0x2FF] = 8
|
||||
assert not eps8_sdsu.hardware_supported(candidate, fp, firmware(candidate))
|
||||
|
||||
|
||||
@pytest.mark.parametrize("candidate", sorted(eps8_sdsu.CARS))
|
||||
@pytest.mark.parametrize("alpha", [False, True])
|
||||
@pytest.mark.parametrize("hybrid", [False, True])
|
||||
def test_sdsu_keeps_existing_vehicle_configuration_and_tune(candidate, alpha, hybrid):
|
||||
from opendbc.car import structs
|
||||
from opendbc.car.toyota.values import CarControllerParams
|
||||
from opendbc.car.toyota.radar_filter import PROFILES
|
||||
|
||||
fw = firmware(candidate)
|
||||
if hybrid:
|
||||
fw.append(
|
||||
structs.CarParams.CarFw(ecu=structs.CarParams.Ecu.hybrid, address=0x7E2, fwVersion=b"synthetic hybrid ECU response", brand="toyota", bus=0, logging=True)
|
||||
)
|
||||
existing = gen_empty_fingerprint()
|
||||
if candidate in PROFILES:
|
||||
existing[0][0x2AA] = 8
|
||||
new = gen_empty_fingerprint()
|
||||
new[0][0x2FF] = 8
|
||||
reference = CarInterface.get_params(candidate, existing, fw, alpha, False, False)
|
||||
actual = CarInterface.get_params(candidate, new, fw, alpha, False, False)
|
||||
before, after = reference.to_dict(), actual.to_dict()
|
||||
for field in ("flags", "safetyConfigs", "openpilotLongitudinalControl", "alphaLongitudinalAvailable", "autoResumeSng"):
|
||||
before.pop(field, None)
|
||||
after.pop(field, None)
|
||||
assert before == after
|
||||
baseline_limits, new_limits = CarControllerParams(reference), CarControllerParams(actual)
|
||||
assert (baseline_limits.ACCEL_MIN, baseline_limits.ACCEL_MAX) == (new_limits.ACCEL_MIN, new_limits.ACCEL_MAX)
|
||||
@@ -0,0 +1,89 @@
|
||||
import pytest
|
||||
from opendbc.car.toyota import eps8_sdsu
|
||||
from opendbc.car.toyota.values import CAR, ToyotaFlags
|
||||
from openpilot.starpilot.car.toyota.tests import test_rav4h_caller_native as helpers
|
||||
from openpilot.starpilot.car.toyota.tests.test_toyota_cpp_transport import host_heartbeat_bridge as host_heartbeat_bridge
|
||||
|
||||
source_matched_native = helpers.source_matched_native
|
||||
daemon_gc_scope = helpers.daemon_gc_scope
|
||||
|
||||
|
||||
def run(candidate, stock, bridge, scenario='nominal', aol=True, alpha=True, disable_setting=None, firmware=None, hybrid_release=False):
|
||||
angle = candidate == CAR.TOYOTA_RAV4_TSS2_2023
|
||||
camera = bool(candidate.config.flags & ToyotaFlags.TSS2 and not candidate.config.flags & ToyotaFlags.RADAR_ACC)
|
||||
|
||||
def physical(packer, **fields):
|
||||
frames = helpers.physical(packer, **fields)
|
||||
frames = [f for f in frames if f[0] not in (0x260, 0x262)]
|
||||
frames += [
|
||||
packer.make_can_msg('STEER_TORQUE_SENSOR', 0, {'STEER_ANGLE': 0.0573}),
|
||||
packer.make_can_msg('EPS_STATUS', 0, {'LKA_STATE': fields.get('eps', 1), 'LTA_STATE': fields.get('eps', 1)}),
|
||||
packer.make_can_msg('PCS_HUD', 2 if camera else 0, {}),
|
||||
]
|
||||
if camera:
|
||||
frames.append(packer.make_can_msg('PRE_COLLISION', 2, {}))
|
||||
return frames
|
||||
|
||||
helpers.run_case(
|
||||
stock,
|
||||
scenario,
|
||||
candidate=candidate,
|
||||
bridge=bridge,
|
||||
input_clock=True,
|
||||
aol=aol,
|
||||
sdsu_words=eps8_sdsu.words(candidate),
|
||||
alpha_long=alpha,
|
||||
disable_setting=disable_setting,
|
||||
physical_frames=physical,
|
||||
angle=angle,
|
||||
brake_stop_check_start=355,
|
||||
firmware_override=firmware,
|
||||
assert_hybrid_release=hybrid_release,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('candidate', sorted(eps8_sdsu.CARS))
|
||||
@pytest.mark.parametrize('stock', [False, True])
|
||||
def test_each_eps8_full_caller(candidate, stock, host_heartbeat_bridge):
|
||||
run(candidate, stock, host_heartbeat_bridge)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('candidate', [CAR.TOYOTA_CAMRY, CAR.TOYOTA_COROLLA_TSS2, CAR.TOYOTA_RAV4_TSS2_2023])
|
||||
@pytest.mark.parametrize('stock', [False, True])
|
||||
@pytest.mark.parametrize('scenario', ['physical', 'faults', 'bad_dlc', 'off'])
|
||||
def test_eps8_fault_source_and_preference_callers(candidate, stock, scenario, host_heartbeat_bridge):
|
||||
run(candidate, stock, host_heartbeat_bridge, scenario)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('candidate', [CAR.TOYOTA_CAMRY, CAR.TOYOTA_COROLLA_TSS2, CAR.TOYOTA_RAV4_TSS2_2023])
|
||||
@pytest.mark.parametrize('stock', [False, True])
|
||||
def test_eps8_ordinary_cruise_callers(candidate, stock, host_heartbeat_bridge):
|
||||
run(candidate, stock, host_heartbeat_bridge, aol=False)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'candidate', [CAR.TOYOTA_CAMRY, CAR.TOYOTA_CHR, CAR.TOYOTA_CHR_TSS2, CAR.TOYOTA_RAV4_TSS2_2022, CAR.TOYOTA_RAV4_TSS2_2023, CAR.TOYOTA_COROLLA_TSS2]
|
||||
)
|
||||
def test_eps8_alpha_off_actual_callers(candidate, host_heartbeat_bridge):
|
||||
stock = bool(candidate.config.flags & ToyotaFlags.RADAR_ACC or not candidate.config.flags & ToyotaFlags.TSS2)
|
||||
run(candidate, stock, host_heartbeat_bridge, alpha=False, disable_setting=False)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("candidate", [CAR.TOYOTA_CAMRY, CAR.TOYOTA_CAMRY_TSS2, CAR.TOYOTA_RAV4_TSS2_2023])
|
||||
def test_detected_hybrid_preserves_active_resume(candidate, host_heartbeat_bridge):
|
||||
from opendbc.car import structs
|
||||
from opendbc.car.toyota.values import FW_QUERY_CONFIG
|
||||
|
||||
# Firmware acquisition boundary: model a response from Toyota's real logging
|
||||
# hybrid query. Keep the catalog EPS/camera/radar identity used for enrollment.
|
||||
assert (structs.CarParams.Ecu.hybrid, 0x7E2, None) in FW_QUERY_CONFIG.extra_ecus
|
||||
fw = helpers.firmware(candidate)
|
||||
fw.append(
|
||||
structs.CarParams.CarFw(ecu=structs.CarParams.Ecu.hybrid, address=0x7E2, fwVersion=b"synthetic hybrid ECU response", brand="toyota", bus=0, logging=True)
|
||||
)
|
||||
run(candidate, False, host_heartbeat_bridge, scenario="hybrid_stop", firmware=fw, hybrid_release=True)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("candidate", [CAR.TOYOTA_AVALON_2019, CAR.LEXUS_LS])
|
||||
def test_nongated_legacy_sdsu_alpha_off(candidate, host_heartbeat_bridge):
|
||||
run(candidate, False, host_heartbeat_bridge, alpha=False, disable_setting=False)
|
||||
@@ -23,7 +23,7 @@ from opendbc.can import CANPacker
|
||||
from opendbc.car import Bus, car_helpers, gen_empty_fingerprint, structs
|
||||
from opendbc.car.fw_versions import match_fw_to_car
|
||||
from opendbc.car.toyota.fingerprints import FW_VERSIONS
|
||||
from opendbc.car.toyota.values import CAR, DBC
|
||||
from opendbc.car.toyota.values import CAR, DBC, ToyotaFlags
|
||||
from opendbc.car.toyota.tests.test_auto_hold import decode
|
||||
from opendbc.safety.tests.libsafety import libsafety_py
|
||||
from openpilot.cereal import messaging
|
||||
@@ -224,7 +224,9 @@ def control_inputs(controls, published, state, sd_events, native, now):
|
||||
return values
|
||||
|
||||
|
||||
def run_case(stock, scenario='nominal', *, aol=True, candidate=CAR.TOYOTA_RAV4H, bridge=None, input_clock=False, brake_stop_check_start=350):
|
||||
def run_case(stock, scenario='nominal', *, aol=True, candidate=CAR.TOYOTA_RAV4H, bridge=None, input_clock=False, brake_stop_check_start=350,
|
||||
sdsu_words=(0x9049, 0x9249), alpha_long=False, disable_setting=None, physical_frames=None, angle=False,
|
||||
firmware_override=None, assert_hybrid_release=False):
|
||||
SYNTHETIC_LAST.clear()
|
||||
NATIVE_LAST.clear()
|
||||
safety = libsafety_py.libsafety
|
||||
@@ -235,11 +237,12 @@ def run_case(stock, scenario='nominal', *, aol=True, candidate=CAR.TOYOTA_RAV4H,
|
||||
('OpenpilotEnabledToggle', True),
|
||||
('SafeMode', False),
|
||||
('AlwaysOnLateral', aol),
|
||||
('DisableOpenpilotLongitudinal', stock),
|
||||
('DisableOpenpilotLongitudinal', stock if disable_setting is None else disable_setting),
|
||||
('AlphaLongitudinalEnabled', alpha_long),
|
||||
('ToyotaAutoHold', False),
|
||||
):
|
||||
params.put_bool(k, v, block=True)
|
||||
fw = firmware(candidate)
|
||||
fw = firmware(candidate) if firmware_override is None else firmware_override
|
||||
exact, found = match_fw_to_car(fw, '', log=False)
|
||||
assert exact and found == {candidate}
|
||||
fp = gen_empty_fingerprint()
|
||||
@@ -252,7 +255,7 @@ def run_case(stock, scenario='nominal', *, aol=True, candidate=CAR.TOYOTA_RAV4H,
|
||||
):
|
||||
host = card_module.Car()
|
||||
assert host.CP.openpilotLongitudinalControl == (not stock)
|
||||
assert host.CP.safetyConfigs[0].safetyParam == (0x9249 if stock else 0x9049)
|
||||
assert host.CP.safetyConfigs[0].safetyParam == sdsu_words[stock]
|
||||
assert host.CP.alternativeExperience == 32
|
||||
controls, sd = Controls(), sd_module.SelfdriveD(CP=host.CP)
|
||||
assert controls.CP.to_dict() == host.CP.to_dict()
|
||||
@@ -307,7 +310,7 @@ def run_case(stock, scenario='nominal', *, aol=True, candidate=CAR.TOYOTA_RAV4H,
|
||||
patch.object(time, 'clock_gettime_ns', side_effect=lambda c: clock[0] if c in (time.CLOCK_MONOTONIC, time.CLOCK_BOOTTIME) else real_clock(c))
|
||||
)
|
||||
try:
|
||||
for tick in range(1, {'nominal': 251, 'physical': 601, 'faults': 801, 'bad_dlc': 801, 'off': 401, 'cold_low': 251}[scenario]):
|
||||
for tick in range(1, {'nominal': 251, 'physical': 601, 'faults': 801, 'bad_dlc': 801, 'off': 401, 'cold_low': 251, 'hybrid_stop': 251}[scenario]):
|
||||
if deterministic:
|
||||
clock[0] += 10_000_000
|
||||
else:
|
||||
@@ -316,6 +319,8 @@ def run_case(stock, scenario='nominal', *, aol=True, candidate=CAR.TOYOTA_RAV4H,
|
||||
now = time.monotonic_ns()
|
||||
safety.set_timer((now // 1000) & 0xFFFFFFFF)
|
||||
fields = {'cruise': tick >= 150}
|
||||
if scenario == 'hybrid_stop':
|
||||
fields.update(stopped=200 <= tick < 230)
|
||||
if scenario == 'cold_low':
|
||||
fields.update(cruise=False, stopped=True)
|
||||
if scenario == 'physical':
|
||||
@@ -335,7 +340,7 @@ def run_case(stock, scenario='nominal', *, aol=True, candidate=CAR.TOYOTA_RAV4H,
|
||||
)
|
||||
elif scenario == 'off' and tick == 250:
|
||||
params.put_bool('DisableOpenpilotLongitudinal', not stock, block=True)
|
||||
frames = physical(packer, **fields)
|
||||
frames = (physical if physical_frames is None else physical_frames)(packer, **fields)
|
||||
if scenario == 'bad_dlc' and 630 <= tick < 665:
|
||||
malformed = packer.make_can_msg('SDSU', 0, {'STATE': 0})
|
||||
frames.append((malformed[0], malformed[1][:7], malformed[2]))
|
||||
@@ -397,8 +402,15 @@ def run_case(stock, scenario='nominal', *, aol=True, candidate=CAR.TOYOTA_RAV4H,
|
||||
if f.address == 0x2E4:
|
||||
decoded = decode(host.CP, (f.address, bytes(f.dat), f.src), 'STEERING_LKA')
|
||||
positive_steering |= bool(decoded['STEER_REQUEST'] and decoded['STEER_TORQUE_CMD'])
|
||||
elif f.address == 0x191 and angle:
|
||||
decoded = decode(host.CP, (f.address, bytes(f.dat), f.src), 'STEERING_LTA')
|
||||
positive_steering |= bool(decoded['STEER_REQUEST'] and decoded['STEER_ANGLE_CMD'])
|
||||
elif f.address == 0x343:
|
||||
positive_accel |= decode(host.CP, (f.address, bytes(f.dat), f.src), 'ACC_CONTROL')['ACCEL_CMD'] > 0
|
||||
acc = decode(host.CP, (f.address, bytes(f.dat), f.src), 'ACC_CONTROL')
|
||||
positive_accel |= acc['ACCEL_CMD'] > 0
|
||||
if assert_hybrid_release and cc.longActive:
|
||||
assert host.CP.flags & ToyotaFlags.HYBRID
|
||||
assert acc['RELEASE_STANDSTILL'] == 1, ('active hybrid resume behavior changed', tick, acc)
|
||||
trace.append(
|
||||
{
|
||||
'tick': tick,
|
||||
@@ -422,7 +434,7 @@ def run_case(stock, scenario='nominal', *, aol=True, candidate=CAR.TOYOTA_RAV4H,
|
||||
}
|
||||
)
|
||||
nominal = tick >= 220 and (
|
||||
scenario in ('nominal', 'cold_low')
|
||||
scenario in ('nominal', 'cold_low', 'hybrid_stop')
|
||||
or scenario == 'off'
|
||||
and tick < 250
|
||||
or scenario == 'physical'
|
||||
@@ -458,7 +470,7 @@ def run_case(stock, scenario='nominal', *, aol=True, candidate=CAR.TOYOTA_RAV4H,
|
||||
if scenario == 'off' and tick >= 310:
|
||||
if stock:
|
||||
assert not host.CP.openpilotLongitudinalControl and not cc.longActive
|
||||
assert host.CP.safetyConfigs[0].safetyParam == 0x9249
|
||||
assert host.CP.safetyConfigs[0].safetyParam == sdsu_words[1]
|
||||
else:
|
||||
assert not host.CI.CC.rav4h_filter_input.update(time.monotonic_ns())
|
||||
for f in outgoing.sendcan:
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"protected_inventory_sha256": "7ad958f6080cde1c5e80081ee1cd24927df9a703189143fcb8d15c8918cc5564", "schema_version": 1}
|
||||
{"protected_inventory_sha256": "8ea2d6a19e2bab4b32310b820f3061f94c9dd66957fc2c1ba8686131932c1949", "schema_version": 1}
|
||||
|
||||
Reference in New Issue
Block a user