byd: fix SEAL bus topology from live dump — ADAS on bus 0, PCM_BUTTONS confirmed

Live bus dump from the Seal showed a different topology than the Han:
- ACC_HUD_ADAS (813) + ACC_CMD (814) are broadcast on the vehicle CAN
  (bus 0), not the camera CAN. Panda rx check expected 813 on bus 2 and
  never saw it -> safety config invalid -> controls blocked forever.
- PCM_BUTTONS (944) confirmed on bus 0 at 20Hz (MADS button placement OK)
- 482 MPC_LKAS_CMD_ANGLE present on bus 2 (angle LKAS cmd; for future use)

Changes:
- carstate: ADAS messages (ACC_HUD_ADAS/ACC_CMD) read from bus 0 on SEAL,
  bus 2 on HAN (cp_adas accessor); parsers built per platform/bus
- panda byd.h: 813 cruise check is bus-independent; rx checks accept
  813 on bus 0 or 2, 944 on bus 0 or 2 (first-seen-wins)
- interface: disable openpilot longitudinal for SEAL — stock ACC_CMD
  originates on bus 0 where the panda cannot intercept it. Stock ACC +
  MADS lateral it is (which is the point of MADS anyway).
- panda firmware rebuilt

Verified: SEAL (cruise+lkas button via bus 0, alphaLong=False) and
HAN (bus 2 topology, alphaLong=True) both canValid; 120 safety tests +
MISRA clean.
This commit is contained in:
Quintine committed 2026-07-25 18:57:17 +10:00
1 parent 5684dd9d0e
commit 1abd13736b
21 files changed
+46 -30

No files matched your search

+28 -15
View File
@@ -22,6 +22,10 @@ class CarState(CarStateBase, MadsCarState):
else:
self.steer_msg = "STEERING_TORQUE"
# ADAS cruise state (ACC_HUD_ADAS) and stock ACC echo (ACC_CMD) are on
# the vehicle CAN (bus 0) on the SEAL, camera CAN (bus 2) on the HAN
self.adas_on_pt_bus = CP.carFingerprint == CAR.BYD_SEAL_PERFORMANCE_25
self.mpc_lkas_cmd_msg = None
self.eps_steering_torque_msg = None
self.eps_prepared = False
@@ -35,6 +39,7 @@ class CarState(CarStateBase, MadsCarState):
def update(self, can_parsers) -> tuple[structs.CarState, structs.CarStateSP]:
cp = can_parsers[Bus.pt]
cp_cam = can_parsers[Bus.cam]
cp_adas = cp if self.adas_on_pt_bus else cp_cam
ret = structs.CarState()
ret_sp = structs.CarStateSP()
@@ -59,13 +64,13 @@ class CarState(CarStateBase, MadsCarState):
ret.steerFaultPermanent = cp.vl[self.steer_msg]["TORQUE_FAILED"] != 0
ret.steerFaultTemporary = cp.vl[self.steer_msg]["TORQUE_FAILED"] != 0
ret.stockAeb = cp_cam.vl["ACC_HUD_ADAS"]["AEB"] == 1
ret.stockFcw = cp_cam.vl["ACC_HUD_ADAS"]["FCW"] == 1 # Forward Collision Warning
ret.stockAeb = cp_adas.vl["ACC_HUD_ADAS"]["AEB"] == 1
ret.stockFcw = cp_adas.vl["ACC_HUD_ADAS"]["FCW"] == 1 # Forward Collision Warning
# Cruise state
ret.cruiseState.enabled = cp_cam.vl["ACC_HUD_ADAS"]["CRUISE_STATE"] in (3, 5) # (Active, Override)
ret.cruiseState.speed = cp_cam.vl["ACC_HUD_ADAS"]["SET_SPEED"] * 10 * CV.KPH_TO_MS
ret.cruiseState.available = cp_cam.vl["ACC_HUD_ADAS"]["CRUISE_STATE"] not in (8, 9) # (Failure, PermanentFailure)
ret.cruiseState.enabled = cp_adas.vl["ACC_HUD_ADAS"]["CRUISE_STATE"] in (3, 5) # (Active, Override)
ret.cruiseState.speed = cp_adas.vl["ACC_HUD_ADAS"]["SET_SPEED"] * 10 * CV.KPH_TO_MS
ret.cruiseState.available = cp_adas.vl["ACC_HUD_ADAS"]["CRUISE_STATE"] not in (8, 9) # (Failure, PermanentFailure)
ret.cruiseState.standstill = False # This needs to be false, since we can resume from stop without sending anything special
# Gear
@@ -102,7 +107,7 @@ class CarState(CarStateBase, MadsCarState):
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
# for generate ACC_CMD
self.acc_cmd_msg = copy.copy(cp_cam.vl["ACC_CMD"])
self.acc_cmd_msg = copy.copy(cp_adas.vl["ACC_CMD"])
return ret, ret_sp
@staticmethod
@@ -123,6 +128,23 @@ class CarState(CarStateBase, MadsCarState):
("PCM_BUTTONS", float('nan')),
]
cam_messages = [
# stock camera command echoes, only present when stock ADAS is active
("MPC_LKAS_CMD", float('nan')),
# SEAL camera also broadcasts an angle-based LKAS command (parsed for future use)
("MPC_LKAS_CMD_ANGLE", float('nan')),
# PCM_BUTTONS may be forwarded on the camera bus on some harnesses
("PCM_BUTTONS", float('nan')),
]
# ADAS cruise state and stock ACC echo: vehicle CAN (bus 0) on the SEAL,
# camera CAN (bus 2) on the HAN. Alive-check ACC_HUD_ADAS only on the bus it lives on.
adas_messages = [("ACC_HUD_ADAS", 10), ("ACC_CMD", float('nan'))]
if CP.carFingerprint == CAR.BYD_SEAL_PERFORMANCE_25:
pt_messages.extend(adas_messages)
else:
cam_messages.extend(adas_messages)
# EPS steering feedback message differs by platform; alive-check only
# the one this car has, parse the other opportunistically
if CP.carFingerprint == CAR.BYD_SEAL_PERFORMANCE_25:
@@ -132,15 +154,6 @@ class CarState(CarStateBase, MadsCarState):
pt_messages.append(("STEERING_TORQUE", 10))
pt_messages.append(("STEERING_TORQUE_ANGLE", float('nan')))
cam_messages = [
("ACC_HUD_ADAS", 10),
# stock camera command echoes, only present when stock ADAS is active
("MPC_LKAS_CMD", float('nan')),
("ACC_CMD", float('nan')),
# PCM_BUTTONS may be forwarded on the camera bus on some harnesses
("PCM_BUTTONS", float('nan')),
]
return {
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], pt_messages, CANBUS.main_bus),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], cam_messages, CANBUS.cam_bus),
+5 -2
View File
@@ -32,8 +32,11 @@ class CarInterface(CarInterfaceBase):
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
# longitudinal control parameters
ret.alphaLongitudinalAvailable = True
if alpha_long:
# HAN: openpilot long available (ACC_CMD replaced on the tapped camera bus).
# SEAL: stock ACC_CMD is broadcast directly on the vehicle CAN (bus 0),
# so it cannot be intercepted/replaced by the panda — stock ACC only (MADS).
ret.alphaLongitudinalAvailable = candidate != CAR.BYD_SEAL_PERFORMANCE_25
if alpha_long and ret.alphaLongitudinalAvailable:
ret.openpilotLongitudinalControl = True
ret.startingState = True
ret.startAccel = 0.1
+11 -11
View File
@@ -65,6 +65,13 @@ static bool byd_tx_hook(const CANPacket_t *msg) {
}
static void byd_rx_hook(const CANPacket_t *msg) {
// ACC_HUD_ADAS: cruise state. Vehicle CAN (bus 0) on SEAL, camera CAN (bus 2) on HAN
if (msg->addr == 813U) {
// CRUISE_STATE in (3, 5) == (Active, Override)
uint8_t cruise_state = (msg->data[5] >> 4U) & 0x0FU;
pcm_cruise_check((cruise_state == 3U) || (cruise_state == 5U));
}
// Main Bus
if (msg->bus == 0U) {
// PEDAL
@@ -101,15 +108,6 @@ static void byd_rx_hook(const CANPacket_t *msg) {
if (msg->addr == 944U) {
mads_button_press = GET_BIT(msg, BYD_LKAS_ON_BTN_BIT) ? MADS_BUTTON_PRESSED : MADS_BUTTON_NOT_PRESSED;
}
}
// Cam Bus
else if (msg->bus == 2U) {
// ACC_HUD_ADAS
if (msg->addr == 813U) {
// CRUISE_STATE in (3, 5) == (Active, Override)
uint8_t cruise_state = (msg->data[5] >> 4U) & 0x0FU;
pcm_cruise_check((cruise_state == 3U) || (cruise_state == 5U));
}
} else {
}
}
@@ -134,8 +132,10 @@ static safety_config byd_init(uint16_t param) {
{.msg = {{287, 0, 5, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // STEER_MODULE
{.msg = {{792, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, // STEERING_TORQUE (HAN)
{508, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }}}, // STEERING_TORQUE_ANGLE (SEAL)
{.msg = {{944, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // PCM_BUTTONS
{.msg = {{813, 2, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // ACC_HUD_ADAS
{.msg = {{944, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, // PCM_BUTTONS (vehicle CAN)
{944, 2, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }}}, // PCM_BUTTONS (camera CAN)
{.msg = {{813, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, // ACC_HUD_ADAS (SEAL: vehicle CAN)
{813, 2, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }}}, // ACC_HUD_ADAS (HAN: camera CAN)
{.msg = {{307, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // STALKS
{.msg = {{660, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // METER_CLUSTER
{.msg = {{790, 2, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // MPC_LKAS_CMD
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
View File
@@ -1,2 +1,2 @@
extern const uint8_t gitversion[19];
const uint8_t gitversion[19] = "DEV-264ebf95-DEBUG";
const uint8_t gitversion[19] = "DEV-5684dd9d-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
View File
@@ -1 +1 @@
DEV-264ebf95-DEBUG
DEV-5684dd9d-DEBUG
Binary file not shown.