byd: spoof 508 steering feedback to camera on SEAL — fixes ADAS lockout
The Seal's camera faults (ACC + ADAS + AEB warning lights, 'unable to activate ADAS') because panda neutralizes its intercepted 790 LKAS commands while the camera watches the 508 feedback for execution — seeing its requests ignored, it disables the whole ADAS suite. The Han avoids this by echoing the camera's request back in the 792 feedback; the Seal needs the same on its 508 STEERING_TORQUE_ANGLE: - bydcan.create_steering_torque_angle: mirrors the Han spoof logic on the 508 layout — when camera LKAS is active, echo its 790 torque request into MAIN_TORQUE and its 482 angle request into TARGET_ANGLE with Cruise_Activated=1; prepare -> LKSPrepare=1; passive -> neutral - carcontroller: Seal sends the 508 spoof, Han keeps the 792 spoof - carstate: capture the camera's 482 angle command for the spoof - panda: whitelist 508 TX on bus 2 (absolute-limit check), stock 508 blocked 0->2 via check_relay — one config covers both platforms - firmware rebuilt; spoof decode-verified (camera's exact torque+angle echoed back); 120 safety tests + MISRA clean NOTE: the ADAS fault latches — the car needs a full power cycle (or a few minutes off) after flashing this build for the dash warnings to clear.
This commit is contained in:
1 parent
63e9aa6cc1
commit
02f1972e99
23 files changed
+81
-21
No files matched your search
@@ -138,6 +138,47 @@ class BydCAN:
|
||||
values["CHECKSUM"] = byd_checksum(data)
|
||||
return self.packer.make_can_msg("STEERING_TORQUE", CANBUS.cam_bus, values)
|
||||
|
||||
# SEAL: spoofed 508 STEERING_TORQUE_ANGLE feedback towards the camera.
|
||||
# Mirrors the camera's own request state back to it so the stock ADAS does
|
||||
# not fault while panda intercepts its LKAS commands (same trick as the
|
||||
# HAN's 792 spoofing, but on the Seal's 508 message layout).
|
||||
def create_steering_torque_angle(self, eps_steering_torque_msg, mpc_lkas_output,
|
||||
mpc_lkas_request_prepare, mpc_lkas_active,
|
||||
mpc_lkas_angle_output):
|
||||
lks_prepared = eps_steering_torque_msg["LKSPrepare"]
|
||||
cruise_activated = eps_steering_torque_msg["Cruise_Activated"]
|
||||
main_torque = eps_steering_torque_msg["MAIN_TORQUE"]
|
||||
target_angle = eps_steering_torque_msg["TARGET_ANGLE"]
|
||||
|
||||
if mpc_lkas_active:
|
||||
lks_prepared = 0
|
||||
cruise_activated = 1
|
||||
main_torque = mpc_lkas_output
|
||||
target_angle = mpc_lkas_angle_output
|
||||
elif mpc_lkas_request_prepare:
|
||||
lks_prepared = 1
|
||||
cruise_activated = 0
|
||||
main_torque = 0
|
||||
else:
|
||||
lks_prepared = 0
|
||||
cruise_activated = 0
|
||||
main_torque = 0
|
||||
|
||||
values = {
|
||||
"LKSPrepare": lks_prepared,
|
||||
"Cruise_Activated": cruise_activated,
|
||||
"TORQUE_FAILED": eps_steering_torque_msg["TORQUE_FAILED"],
|
||||
"Steer_Torque_Sensor": eps_steering_torque_msg["Steer_Torque_Sensor"],
|
||||
"TARGET_ANGLE": target_angle,
|
||||
"MAIN_TORQUE": main_torque,
|
||||
"Keep_Hands_On_Wheel": 0,
|
||||
"TORQUE_TEMP_FAILED": eps_steering_torque_msg["TORQUE_TEMP_FAILED"],
|
||||
"COUNTER": self._generate_eps_steering_torque_new_counter(),
|
||||
}
|
||||
data = self.packer.make_can_msg("STEERING_TORQUE_ANGLE", CANBUS.cam_bus, values)[1]
|
||||
values["CHECKSUM"] = byd_checksum(data)
|
||||
return self.packer.make_can_msg("STEERING_TORQUE_ANGLE", CANBUS.cam_bus, values)
|
||||
|
||||
def create_acc_cmd(self, acc_cmd_msg, accel):
|
||||
values = {
|
||||
"ACCEL_CMD": accel,
|
||||
|
||||
@@ -30,10 +30,10 @@ class CarController(CarControllerBase):
|
||||
|
||||
self.apply_accel_last = 0
|
||||
|
||||
# EPS steering feedback forwarding (792 STEERING_TORQUE) only applies to
|
||||
# platforms whose EPS reports on 792 (HAN). The SEAL EPS reports on
|
||||
# 508 STEERING_TORQUE_ANGLE which is forwarded stock for now.
|
||||
self.send_steering_feedback = CP.carFingerprint != CAR.BYD_SEAL_PERFORMANCE_25
|
||||
# EPS steering feedback is spoofed towards the camera on both platforms so
|
||||
# the stock ADAS does not fault while its LKAS commands are intercepted:
|
||||
# HAN uses 792 STEERING_TORQUE, SEAL uses 508 STEERING_TORQUE_ANGLE.
|
||||
self.seal_platform = CP.carFingerprint == CAR.BYD_SEAL_PERFORMANCE_25
|
||||
|
||||
def update(self, CC, CC_SP, CS, now_nanos):
|
||||
# car control running in 100Hz
|
||||
@@ -80,12 +80,18 @@ class CarController(CarControllerBase):
|
||||
lkas_request_prepare, lkas_active,
|
||||
lkas_mode, CS.eps_activated)
|
||||
can_sends.append(pack)
|
||||
if self.send_steering_feedback:
|
||||
if self.seal_platform:
|
||||
pack = self.can.create_steering_torque_angle(CS.eps_steering_torque_msg,
|
||||
CS.mpc_lkas_output,
|
||||
CS.mpc_lkas_request_prepare,
|
||||
CS.mpc_lkas_active,
|
||||
CS.mpc_lkas_angle_output)
|
||||
else:
|
||||
pack = self.can.create_steering_torque(CS.eps_steering_torque_msg,
|
||||
CS.mpc_lkas_output,
|
||||
CS.mpc_lkas_request_prepare,
|
||||
CS.mpc_lkas_active)
|
||||
can_sends.append(pack)
|
||||
can_sends.append(pack)
|
||||
|
||||
self.apply_torque_last = apply_torque
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ class CarState(CarStateBase, MadsCarState):
|
||||
self.mpc_lkas_output = 0
|
||||
self.mpc_lkas_active = False
|
||||
self.mpc_lkas_request_prepare = False
|
||||
self.mpc_lkas_angle_output = 0.0
|
||||
|
||||
def update(self, can_parsers) -> tuple[structs.CarState, structs.CarStateSP]:
|
||||
cp = can_parsers[Bus.pt]
|
||||
@@ -106,6 +107,8 @@ class CarState(CarStateBase, MadsCarState):
|
||||
self.mpc_lkas_output = cp_cam.vl["MPC_LKAS_CMD"]["LKAS_Output"]
|
||||
self.mpc_lkas_active = cp_cam.vl["MPC_LKAS_CMD"]["LKAS_ACTIVE"] != 0
|
||||
self.mpc_lkas_request_prepare = cp_cam.vl["MPC_LKAS_CMD"]["LKASPrepare"] != 0
|
||||
# camera's angle-based LKAS request (SEAL), used to spoof the 508 TARGET_ANGLE echo
|
||||
self.mpc_lkas_angle_output = cp_cam.vl["MPC_LKAS_CMD_ANGLE"]["LKAS_Output"]
|
||||
# for generate ACC_CMD
|
||||
self.acc_cmd_msg = copy.copy(cp_adas.vl["ACC_CMD"])
|
||||
return ret, ret_sp
|
||||
|
||||
@@ -42,15 +42,22 @@ static bool byd_tx_hook(const CANPacket_t *msg) {
|
||||
}
|
||||
}
|
||||
|
||||
// STEERING_TORQUE: feedback message towards the camera, torque echoes the
|
||||
// camera's own request. Only sanity-check the absolute limit so stock LKAS
|
||||
// requests don't fault when openpilot is inactive.
|
||||
// STEERING_TORQUE (792, HAN) / STEERING_TORQUE_ANGLE (508, SEAL):
|
||||
// feedback message towards the camera, torque echoes the camera's own
|
||||
// request. Only sanity-check the absolute limit so stock LKAS requests
|
||||
// don't fault when openpilot is inactive.
|
||||
if (msg->addr == 792U) {
|
||||
int main_torque = BYD_GET_MAIN_TORQUE(msg);
|
||||
if (safety_max_limit_check(main_torque, BYD_STEERING_LIMITS.max_torque, -BYD_STEERING_LIMITS.max_torque)) {
|
||||
tx = false;
|
||||
}
|
||||
}
|
||||
if (msg->addr == 508U) {
|
||||
int main_torque = BYD_GET_MAIN_TORQUE_ANGLE(msg);
|
||||
if (safety_max_limit_check(main_torque, BYD_STEERING_LIMITS.max_torque, -BYD_STEERING_LIMITS.max_torque)) {
|
||||
tx = false;
|
||||
}
|
||||
}
|
||||
|
||||
// ACC_CMD: longitudinal actuation
|
||||
if (msg->addr == 814U) {
|
||||
@@ -115,12 +122,14 @@ static void byd_rx_hook(const CANPacket_t *msg) {
|
||||
static safety_config byd_init(uint16_t param) {
|
||||
static const CanMsg BYD_TX_MSGS[] = {
|
||||
{790, 0, 8, .check_relay = true}, // MPC_LKAS_CMD
|
||||
{792, 2, 8, .check_relay = true}, // STEERING_TORQUE
|
||||
{792, 2, 8, .check_relay = true}, // STEERING_TORQUE (HAN)
|
||||
{508, 2, 8, .check_relay = true}, // STEERING_TORQUE_ANGLE (SEAL)
|
||||
};
|
||||
|
||||
static const CanMsg BYD_TX_LONG_MSGS[] = {
|
||||
{790, 0, 8, .check_relay = true}, // MPC_LKAS_CMD
|
||||
{792, 2, 8, .check_relay = true}, // STEERING_TORQUE
|
||||
{792, 2, 8, .check_relay = true}, // STEERING_TORQUE (HAN)
|
||||
{508, 2, 8, .check_relay = true}, // STEERING_TORQUE_ANGLE (SEAL)
|
||||
{814, 0, 8, .check_relay = true}, // ACC_CMD
|
||||
};
|
||||
|
||||
|
||||
@@ -7,8 +7,9 @@ import opendbc.safety.tests.common as common
|
||||
from opendbc.safety.tests.common import CANPackerSafety
|
||||
|
||||
MSG_MPC_LKAS_CMD = 790 # TX by OP, lateral actuation towards EPS
|
||||
MSG_STEERING_TORQUE = 792 # RX from EPS / TX by OP, torque feedback towards camera
|
||||
MSG_ACC_HUD_ADAS = 813 # RX from camera, ACC state
|
||||
MSG_STEERING_TORQUE = 792 # RX from EPS / TX by OP, torque feedback towards camera (HAN)
|
||||
MSG_STEERING_TORQUE_ANGLE = 508 # RX from EPS / TX by OP, torque feedback towards camera (SEAL)
|
||||
MSG_ACC_HUD_ADAS = 813 # RX from ADAS, ACC state
|
||||
MSG_ACC_CMD = 814 # TX by OP, longitudinal actuation
|
||||
MSG_PCM_BUTTONS = 944 # RX from PCM, steering wheel buttons
|
||||
|
||||
@@ -36,10 +37,10 @@ def byd_checksum(msg):
|
||||
|
||||
|
||||
class TestBydSafetyBase(common.CarSafetyTest, common.MotorTorqueSteeringSafetyTest):
|
||||
TX_MSGS = [[MSG_MPC_LKAS_CMD, 0], [MSG_STEERING_TORQUE, 2]]
|
||||
TX_MSGS = [[MSG_MPC_LKAS_CMD, 0], [MSG_STEERING_TORQUE, 2], [MSG_STEERING_TORQUE_ANGLE, 2]]
|
||||
STANDSTILL_THRESHOLD = 0
|
||||
RELAY_MALFUNCTION_ADDRS = {0: (MSG_MPC_LKAS_CMD,), 2: (MSG_STEERING_TORQUE,)}
|
||||
FWD_BLACKLISTED_ADDRS = {0: [MSG_STEERING_TORQUE], 2: [MSG_MPC_LKAS_CMD]}
|
||||
RELAY_MALFUNCTION_ADDRS = {0: (MSG_MPC_LKAS_CMD,), 2: (MSG_STEERING_TORQUE, MSG_STEERING_TORQUE_ANGLE)}
|
||||
FWD_BLACKLISTED_ADDRS = {0: [MSG_STEERING_TORQUE, MSG_STEERING_TORQUE_ANGLE], 2: [MSG_MPC_LKAS_CMD]}
|
||||
|
||||
MAX_TORQUE_LOOKUP = ([0], [300])
|
||||
MAX_RATE_UP = 6
|
||||
@@ -98,9 +99,9 @@ class TestBydStockSafety(TestBydSafetyBase):
|
||||
|
||||
|
||||
class TestBydLongitudinalSafety(TestBydSafetyBase):
|
||||
TX_MSGS = [[MSG_MPC_LKAS_CMD, 0], [MSG_STEERING_TORQUE, 2], [MSG_ACC_CMD, 0]]
|
||||
RELAY_MALFUNCTION_ADDRS = {0: (MSG_MPC_LKAS_CMD, MSG_ACC_CMD), 2: (MSG_STEERING_TORQUE,)}
|
||||
FWD_BLACKLISTED_ADDRS = {0: [MSG_STEERING_TORQUE], 2: [MSG_MPC_LKAS_CMD, MSG_ACC_CMD]}
|
||||
TX_MSGS = [[MSG_MPC_LKAS_CMD, 0], [MSG_STEERING_TORQUE, 2], [MSG_STEERING_TORQUE_ANGLE, 2], [MSG_ACC_CMD, 0]]
|
||||
RELAY_MALFUNCTION_ADDRS = {0: (MSG_MPC_LKAS_CMD, MSG_ACC_CMD), 2: (MSG_STEERING_TORQUE, MSG_STEERING_TORQUE_ANGLE)}
|
||||
FWD_BLACKLISTED_ADDRS = {0: [MSG_STEERING_TORQUE, MSG_STEERING_TORQUE_ANGLE], 2: [MSG_MPC_LKAS_CMD, MSG_ACC_CMD]}
|
||||
|
||||
MIN_ACCEL = 20 # -4.0 m/s^2, raw = (m/s^2 + 5) / 0.05
|
||||
MAX_ACCEL = 140 # 2.0 m/s^2
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,2 +1,2 @@
|
||||
extern const uint8_t gitversion[19];
|
||||
const uint8_t gitversion[19] = "DEV-5684dd9d-DEBUG";
|
||||
const uint8_t gitversion[19] = "DEV-63e9aa6c-DEBUG";
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
DEV-5684dd9d-DEBUG
|
||||
DEV-63e9aa6c-DEBUG
|
||||
Binary file not shown.
Reference in new issue
Block a user