Detect C-HR CAN filters alongside native radar traffic

This commit is contained in:
firestar5683
2026-11-03 20:22:32 -06:00
parent 2929a25afe
commit 14534287c1
4 changed files with 23 additions and 14 deletions
@@ -13,11 +13,11 @@ PROFILES = {
}
def _camry_radar_bus(candidate, bus, messages):
# The 2018–20 Camry exposes an independent eight-byte 2FF stream alongside
def _cluster_radar_bus(candidate, bus, messages):
# The 2018–20 Camry and 2017–20 C-HR expose an independent eight-byte 2FF stream alongside
# its six cluster-radar frames on bus1 (cluster_radar.CLUSTERS). It is not
# the four-byte filter advertisement or a bus0 smartDSU status source.
return (candidate == CAR.TOYOTA_CAMRY and bus == 1 and messages.get(0x2FF) == 8 and
return (candidate in (CAR.TOYOTA_CAMRY, CAR.TOYOTA_CHR) and bus == 1 and messages.get(0x2FF) == 8 and
all(messages.get(address) == 8 for address in range(0x680, 0x686)))
@@ -29,12 +29,12 @@ def hardware_supported(candidate, fingerprint):
# Panda discovery may also expose its forwarded camera-bus copy.
if (candidate in PROFILES and fingerprint.get(0, {}).get(0x2FF) == 4 and
not any(address in messages for messages in fingerprint.values() for address in (0x201, 0x2AA)) and
all((bus in (0, 2) and messages[0x2FF] == 4) or _camry_radar_bus(candidate, bus, messages)
all((bus in (0, 2) and messages[0x2FF] == 4) or _cluster_radar_bus(candidate, bus, messages)
for bus, messages in fingerprint.items() if 0x2FF in messages)):
return True
return (candidate in PROFILES and fingerprint.get(0, {}).get(0x2AA) == 8 and
all(bus in (0, 2) and frames[0x2AA] == 8 for bus, frames in fingerprint.items() if 0x2AA in frames) and
not any(0x201 in frames or 0x2FF in frames and not _camry_radar_bus(candidate, bus, frames)
not any(0x201 in frames or 0x2FF in frames and not _cluster_radar_bus(candidate, bus, frames)
for bus, frames in fingerprint.items()))
@@ -11,3 +11,11 @@ daemon_gc_scope = helpers.daemon_gc_scope
@pytest.mark.parametrize('aol', [False, True])
def test_camry_chr_filter_actual_callers(candidate, alpha, disable, aol, tmp_path):
helpers.run_case(candidate, alpha, disable, 0, tmp_path, aol=aol)
@pytest.mark.parametrize('alpha,disable', [(False, False), (True, False), (True, True)])
@pytest.mark.parametrize('aol', [False, True])
def test_chr_filter_with_independent_cluster_radar_actual_callers(alpha, disable, aol, tmp_path):
advertisements = [(0x2FF, bytes(4), 0), (0x2FF, bytes(4), 2), (0x2FF, bytes(8), 1)]
advertisements.extend((address, bytes(8), 1) for address in range(0x680, 0x686))
helpers.run_case(CAR.TOYOTA_CHR, alpha, disable, 0, tmp_path, aol=aol, filter_advertisements=advertisements)
@@ -1,4 +1,4 @@
"""Camry cluster-radar traffic must not impersonate a bus-0 filter status."""
"""Camry/C-HR cluster-radar traffic must not impersonate a bus-0 filter status."""
import pytest
from opendbc.car import gen_empty_fingerprint
from opendbc.car.toyota import radar_filter
@@ -15,27 +15,28 @@ def observed():
return fp
@pytest.mark.parametrize('candidate', (CAR.TOYOTA_CAMRY, CAR.TOYOTA_CHR))
@pytest.mark.parametrize('alpha', (False, True))
@pytest.mark.parametrize('primary', (0x2FF, 0x2AA))
def test_camry_radar_bus_preserves_exact_filter_owner(alpha, primary):
def test_camry_radar_bus_preserves_exact_filter_owner(candidate, alpha, primary):
fp = observed()
if primary == 0x2AA:
fp[0] = fp[2] = {primary: 8}
canonical = gen_empty_fingerprint()
canonical[0][primary] = 4 if primary == 0x2FF else 8
expected = CarInterface.get_params(CAR.TOYOTA_CAMRY, canonical, [], alpha, False, False)
actual = CarInterface.get_params(CAR.TOYOTA_CAMRY, fp, [], alpha, False, False)
assert radar_filter.hardware_supported(CAR.TOYOTA_CAMRY, fp)
expected = CarInterface.get_params(candidate, canonical, [], alpha, False, False)
actual = CarInterface.get_params(candidate, fp, [], alpha, False, False)
assert radar_filter.hardware_supported(candidate, fp)
assert actual.to_dict() == expected.to_dict()
assert actual.safetyConfigs[0].safetyParam == (0x1049 if alpha else 0x1249)
assert actual.openpilotLongitudinalControl == alpha and qualified(actual)
@pytest.mark.parametrize('candidate', (CAR.TOYOTA_CAMRY, CAR.TOYOTA_CHR))
@pytest.mark.parametrize('bad', ('missing_filter', 'bus1_short', 'missing_cluster', 'bad_cluster',
'wrong_cluster_bus', 'wrong_model', 'bus1_advert', 'mixed_status', 'pedal'))
def test_camry_radar_bus_is_not_general_adapter_evidence(bad):
def test_camry_radar_bus_is_not_general_adapter_evidence(candidate, bad):
fp = observed()
candidate = CAR.TOYOTA_CAMRY
if bad == 'missing_filter':
fp[0].clear()
elif bad == 'bus1_short':
@@ -47,7 +48,7 @@ def test_camry_radar_bus_is_not_general_adapter_evidence(bad):
elif bad == 'wrong_cluster_bus':
fp[3] = fp.pop(1)
elif bad == 'wrong_model':
candidate = CAR.TOYOTA_CHR
candidate = CAR.TOYOTA_CHR_TSS2
elif bad == 'bus1_advert':
fp[1][0x2FF] = 4
elif bad == 'mixed_status':
+1 -1
View File
@@ -1 +1 @@
{"protected_inventory_sha256": "dc0fc34a78b6ecec51ba5a4ecfd601088ed237535b321ef878019980d3b8b465", "schema_version": 1}
{"protected_inventory_sha256": "7769f133116304f49b7b3419263f618e02451e31af54f2dc3354feea9e76cb16", "schema_version": 1}