Keep removed-camera Volt traffic off the absent camera bus

This commit is contained in:
firestar5683
2026-10-20 12:58:05 -05:00
parent aeb33f3ae7
commit ded5368547
5 changed files with 75 additions and 4 deletions
+1 -1
View File
@@ -1200,7 +1200,7 @@ class CarController(CarControllerBase):
self.bolt_removed_cancel_credit_used = CS.conventional_cancel_credit.credit_ns
can_sends.append(gmcan.create_buttons(self.packer_pt, CanBus.POWERTRAIN, (CS.buttons_counter + 1) % 4, CruiseButtons.CANCEL))
if self.CP.networkLocation == NetworkLocation.fwdCamera and not self.bolt_cc_profile:
if self.CP.networkLocation == NetworkLocation.fwdCamera and not self.bolt_cc_profile and not self.volt_camera_removed:
# Silence "Take Steering" alert sent by camera, forward PSCMStatus with HandsOffSWlDetectionStatus=1
if self.frame % 10 == 0:
can_sends.append(gmcan.create_pscm_status(self.packer_pt, CanBus.CAMERA, CS.pscm_status))
@@ -91,6 +91,13 @@ class TestVoltAlternateBrake(unittest.TestCase):
ci = CarInterface(cp)
packer = CANPacker(DBC[cp.carFingerprint][Bus.pt])
for tick, expected in enumerate(baseline['tx']):
# Keep every frozen vehicle-side byte. Only the removed camera's
# obsolete PSCM replacement is intentionally absent in this topology.
if is_volt_camera_removed(cp):
self.assertIn(name, ('removed-0', 'removed-1'))
camera_status = [message for message in expected if message[0] == 0x184 and message[2] == 2]
self.assertEqual(len(camera_status), int(tick % 10 == 0))
expected = [message for message in expected if not (message[0] == 0x184 and message[2] == 2)]
now = 1_000_000_000 + tick * 10_000_000
speed = 20. if tick < 40 or tick >= 100 else 0. if tick < 80 else 6.
active, brake, gas = tick < 60 or tick >= 90, 60 <= tick < 65, 65 <= tick < 70
@@ -0,0 +1,60 @@
"""Route 11177: a removed camera must never receive forwarded or host traffic."""
import pytest
from opendbc.can import CANPacker
from opendbc.car import Bus, structs
from opendbc.car.gm.interface import CarInterface
from opendbc.car.gm.tests.test_volt_camera_removed import removed_params, feed_removed
from opendbc.car.gm.tests.test_volt_camera_control import camera_params, feed_camera
from opendbc.car.gm.values import CAR, DBC
from opendbc.safety.tests.libsafety import libsafety_py
@pytest.mark.parametrize('alpha', [False, True])
@pytest.mark.parametrize('alternate', [False, True])
def test_removed_camera_controller_uses_only_vehicle_bus(alpha, alternate):
cp = removed_params(alpha=alpha, alternate=alternate)
ci = CarInterface(cp)
packer = CANPacker(DBC[cp.carFingerprint][Bus.pt])
sent = []
for tick in range(24):
now = 1_000_000_000 + tick * 40_000_000
cs, _ = feed_removed(ci, packer, now, counter=tick % 4, active=False)
assert cs.canValid and not cs.canTimeout
cc = structs.CarControl(enabled=False, latActive=False, longActive=False)
_, frames = ci.apply(cc.as_reader(), now + 2)
assert all(frame[2] == 0 for frame in frames)
sent.extend(frames)
assert any(frame[0] == 0x180 for frame in sent)
@pytest.mark.parametrize('word', [0xC150, 0xC151])
def test_removed_camera_native_has_no_forwarding_or_camera_transmit(word):
safety = libsafety_py.libsafety
release = safety.set_safety_hooks(structs.CarParams.SafetyModel.allOutput, 0) != 0
assert safety.set_safety_hooks(structs.CarParams.SafetyModel.gm, word) == 0
safety.init_tests()
if release and word == 0xC151:
assert not safety.safety_config_valid()
return
for bus in (0, 1, 2):
for address in range(0x800):
assert safety.safety_fwd_hook(bus, address) == -1
packer = CANPacker(DBC[CAR.CHEVROLET_VOLT_CAMERA][Bus.pt])
frame = packer.make_can_msg('PSCMStatus', 2, {})
assert not safety.safety_tx_hook(libsafety_py.make_CANPacket(frame[0], frame[2], frame[1]))
@pytest.mark.parametrize('alpha', [False, True])
def test_connected_camera_retains_its_status_delivery(alpha):
cp = camera_params(alpha=alpha)
ci = CarInterface(cp)
packer = CANPacker(DBC[cp.carFingerprint][Bus.pt])
sent = []
for tick in range(12):
now = 1_000_000_000 + tick * 40_000_000
cs, _ = feed_camera(ci, packer, now, counter=tick % 4, active=False)
assert cs.canValid and not cs.canTimeout
_, frames = ci.apply(structs.CarControl().as_reader(), now + 2)
sent.extend(frames)
assert any(frame[0] == 0x184 and frame[2] == 2 for frame in sent)
+6 -2
View File
@@ -549,6 +549,8 @@ static bool gm_ascm_adas_valid(const CANPacket_t *msg) {
}
static bool gm_tx_hook(const CANPacket_t *msg) {
// This topology has no camera-side receiver after harness interception.
if (gm_volt_camera_removed && (msg->bus == 2U)) { return false; }
const TorqueSteeringLimits GM_STEERING_LIMITS = {
.max_torque = 300,
.max_rate_up = 10,
@@ -1093,14 +1095,12 @@ static safety_config gm_init(uint16_t safety_param) {
static const CanMsg GM_VOLT_REMOVED_STOCK_TX_MSGS[] = {
{0x180, 0, 4, .check_relay = false}, {0x1E1, 0, 7, .check_relay = false},
{0x184, 2, 8, .check_relay = false},
};
#ifdef ALLOW_DEBUG
static const CanMsg GM_VOLT_REMOVED_LONG_TX_MSGS[] = {
{0x180, 0, 4, .check_relay = false}, {0x315, 0, 5, .check_relay = false},
{0x2CB, 0, 8, .check_relay = false}, {0x370, 0, 6, .check_relay = false},
{0x409, 0, 7, .check_relay = false}, {0x40A, 0, 7, .check_relay = false},
{0x184, 2, 8, .check_relay = false},
};
#endif
static RxCheck gm_volt_removed_rx_checks[] = {
@@ -1851,6 +1851,10 @@ static safety_config gm_init(uint16_t safety_param) {
gm_pcm_cruise = false;
}
// A removed Volt camera leaves bus 2 unacknowledged after relay interception.
// Forwarding vehicle traffic there fills TX queues and stalls host CAN reads.
if (gm_volt_camera_removed) { ret.disable_forwarding = true; }
// ASCM does not forward any messages
if ((gm_hw == GM_ASCM) && !gm_camera_gateway) {
ret.disable_forwarding = true;
@@ -109,7 +109,7 @@ class TestGmVoltCameraRemoved(unittest.TestCase):
self.assertEqual(self.safety.safety_fwd_hook(0, 0x184), -1)
self.assertEqual(self.safety.safety_fwd_hook(2, 0x180), -1)
for address in (0x315, 0x2CB, 0x370, 0x2CD):
self.assertEqual(self.safety.safety_fwd_hook(2, address), -1 if word == 0xC151 else 0)
self.assertEqual(self.safety.safety_fwd_hook(2, address), -1)
self.mode(0xC150)
self.physical()
for middle in (5, 0x4007, 0x1005, 4):