From 9c0cbcd5f48801bc4b8cfa317023bc4cb9a8245e Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Mon, 26 Oct 2026 21:54:11 -0500 Subject: [PATCH] Ignore Toyota transmit receipts when checking adapter identity --- .../opendbc/car/toyota/camera_2aa_filter.py | 4 ++ opendbc_repo/opendbc/car/toyota/dsu_bypass.py | 4 ++ .../opendbc/car/toyota/prius_advert_filter.py | 4 ++ opendbc_repo/opendbc/car/toyota/prius_sdsu.py | 4 ++ .../toyota/tests/test_hardware_rx_identity.py | 44 +++++++++++++++++++ .../test_prius_retrofit_advert_callers.py | 3 ++ .../toyota/tests/test_rav4h_caller_native.py | 3 ++ 7 files changed, 66 insertions(+) create mode 100644 openpilot/starpilot/car/toyota/tests/test_hardware_rx_identity.py diff --git a/opendbc_repo/opendbc/car/toyota/camera_2aa_filter.py b/opendbc_repo/opendbc/car/toyota/camera_2aa_filter.py index e1c87b67bd..adcb6f3856 100644 --- a/opendbc_repo/opendbc/car/toyota/camera_2aa_filter.py +++ b/opendbc_repo/opendbc/car/toyota/camera_2aa_filter.py @@ -98,6 +98,10 @@ class CameraTwoAACANParser(AdvertFilterCANParser): for stamp, frames in strings: accepted = [] for address, data, bus in frames: + # pandad marks TX confirmations/rejections with bus >= 128; they + # are not received hardware (see panda.h CAN_*_BUS_OFFSET). + if bus >= 128: + continue if address in (0x201, 0x2FF): self.hardware_ambiguous = True continue diff --git a/opendbc_repo/opendbc/car/toyota/dsu_bypass.py b/opendbc_repo/opendbc/car/toyota/dsu_bypass.py index e574eb0ff7..4d11dd1304 100644 --- a/opendbc_repo/opendbc/car/toyota/dsu_bypass.py +++ b/opendbc_repo/opendbc/car/toyota/dsu_bypass.py @@ -139,6 +139,10 @@ class BypassCANParser(CANParser): for stamp, frames in strings: accepted = [] for address, data, bus in frames: + # pandad marks TX confirmations/rejections with bus >= 128; they + # are not received hardware (see panda.h CAN_*_BUS_OFFSET). + if bus >= 128: + continue if address in (0x201, 0x2FF, 0x2AA): self.ambiguous = True if bus == self.bus: diff --git a/opendbc_repo/opendbc/car/toyota/prius_advert_filter.py b/opendbc_repo/opendbc/car/toyota/prius_advert_filter.py index bddff757a4..7dea967ad4 100644 --- a/opendbc_repo/opendbc/car/toyota/prius_advert_filter.py +++ b/opendbc_repo/opendbc/car/toyota/prius_advert_filter.py @@ -82,6 +82,10 @@ class PriusAdvertCANParser(AdvertFilterCANParser): for stamp, frames in strings: frames = list(frames) for address, data, bus in frames: + # pandad marks TX confirmations/rejections with bus >= 128; they + # are not received hardware (see panda.h CAN_*_BUS_OFFSET). + if bus >= 128: + continue if address in (0x201, 0x2AA) or address == 0x2FF and (bus not in (0, 2) or len(data) != 4): self.hardware_ambiguous = True batches.append((stamp, frames)) diff --git a/opendbc_repo/opendbc/car/toyota/prius_sdsu.py b/opendbc_repo/opendbc/car/toyota/prius_sdsu.py index cd3198ac65..ad7acadac6 100644 --- a/opendbc_repo/opendbc/car/toyota/prius_sdsu.py +++ b/opendbc_repo/opendbc/car/toyota/prius_sdsu.py @@ -85,6 +85,10 @@ class PriusSDSUCANParser(Rav4hCANParser): for stamp, frames in strings: accepted = [] for address, data, bus in frames: + # pandad marks TX confirmations/rejections with bus >= 128; they + # are not received hardware (see panda.h CAN_*_BUS_OFFSET). + if bus >= 128: + continue if address in (0x201, 0x2AA) or address == 0x2FF and (bus not in (0, 2) or len(data) == 4): self.hardware_ambiguous = True if bus == self.bus and address in (0x1D3, 0x262): diff --git a/openpilot/starpilot/car/toyota/tests/test_hardware_rx_identity.py b/openpilot/starpilot/car/toyota/tests/test_hardware_rx_identity.py new file mode 100644 index 0000000000..1c0d2c0954 --- /dev/null +++ b/openpilot/starpilot/car/toyota/tests/test_hardware_rx_identity.py @@ -0,0 +1,44 @@ +"""Transport receipts must neither revoke hardware identity nor refresh RX leases.""" +import pytest +from opendbc.can import CANPacker +from opendbc.car import Bus +from opendbc.car.toyota import camera_2aa_filter, dsu_bypass, prius_advert_filter, prius_sdsu +from opendbc.car.toyota.values import CAR, DBC + +PARSERS = (prius_advert_filter.PriusAdvertCANParser, prius_sdsu.PriusSDSUCANParser, + camera_2aa_filter.CameraTwoAACANParser, dsu_bypass.BypassCANParser) + + +def ambiguous(parser): + return getattr(parser, 'hardware_ambiguous', getattr(parser, 'ambiguous', False)) + + +@pytest.mark.parametrize('parser_type', PARSERS) +@pytest.mark.parametrize('bus', (128, 130, 132, 192, 194, 196)) +def test_receipts_do_not_change_identity_or_supply_main_eps(parser_type, bus): + dbc = DBC[CAR.TOYOTA_PRIUS][Bus.pt] + packer = CANPacker(dbc) + parser = parser_type(dbc, [('PCM_CRUISE_2', 10), ('EPS_STATUS', 25)], 0) + main = packer.make_can_msg('PCM_CRUISE_2', 0, {'MAIN_ON': 1}) + eps = packer.make_can_msg('EPS_STATUS', 0, {'LKA_STATE': 1}) + receipts = [(a, data, bus) for a, data, _ in (main, eps)] + receipts += [(a, bytes(n), bus) for a, n in ((0x201, 6), (0x2AA, 8), (0x2FF, 4), (0x2FF, 8))] + parser.update([(2_000_000_000, receipts)]) + assert not ambiguous(parser) and not parser.main_valid and not parser.eps_valid + parser.update([(2_010_000_000, [main, eps])]) + stamp = parser.ts_nanos['PCM_CRUISE_2']['MAIN_ON'] + assert not ambiguous(parser) and parser.main_valid and parser.eps_valid + parser.update([(2_020_000_000, receipts)]) + assert not ambiguous(parser) and parser.main_valid and parser.eps_valid + assert parser.ts_nanos['PCM_CRUISE_2']['MAIN_ON'] == stamp + + +@pytest.mark.parametrize('parser_type', PARSERS) +@pytest.mark.parametrize('bus', (0, 1, 2, 4)) +def test_real_conflicting_hardware_stays_latched(parser_type, bus): + dbc = DBC[CAR.TOYOTA_PRIUS][Bus.pt] + parser = parser_type(dbc, [('PCM_CRUISE_2', 10), ('EPS_STATUS', 25)], 0) + parser.update([(2_000_000_000, [(0x201, bytes(6), bus)])]) + assert ambiguous(parser) + parser.update([(2_010_000_000, [])]) + assert ambiguous(parser) diff --git a/openpilot/starpilot/car/toyota/tests/test_prius_retrofit_advert_callers.py b/openpilot/starpilot/car/toyota/tests/test_prius_retrofit_advert_callers.py index ec2e95f37a..3ddcdf6165 100644 --- a/openpilot/starpilot/car/toyota/tests/test_prius_retrofit_advert_callers.py +++ b/openpilot/starpilot/car/toyota/tests/test_prius_retrofit_advert_callers.py @@ -19,6 +19,9 @@ def test_eps73_advert_actual_cold_callers(candidate,stock,host_heartbeat_bridge) frames=helpers.physical(packer,**fields) assert len(next(data for address,data,bus in frames if address==0x262 and bus==0))==8 frames.extend(((0x2FF,bytes.fromhex('80007409'),0),(0x2FF,bytes.fromhex('80007409'),2))) + # Route 16c1c1b1b2152da0/00000001--a0679e3a1b: after the + # safety handoff, forwarded four-byte advertisements return on bus 130. + frames.extend((address,data,bus+128) for address,data,bus in list(frames) if bus == 2 or address == 0x2FF) return frames def observe(tick,host,cs,cc,safety,native): diff --git a/openpilot/starpilot/car/toyota/tests/test_rav4h_caller_native.py b/openpilot/starpilot/car/toyota/tests/test_rav4h_caller_native.py index fe5722f7fb..520c194a60 100644 --- a/openpilot/starpilot/car/toyota/tests/test_rav4h_caller_native.py +++ b/openpilot/starpilot/car/toyota/tests/test_rav4h_caller_native.py @@ -419,6 +419,9 @@ def run_case(stock, scenario='nominal', *, aol=True, candidate=CAR.TOYOTA_RAV4H, malformed = packer.make_can_msg('SDSU', 0, {'STATE': 0}) frames.append((malformed[0], malformed[1][:7], malformed[2])) for a, d, bus in frames: + # USB TX receipts are delivered to host parsers, never native RX. + if bus >= 128: + continue accepted = bool(safety.safety_rx_hook(libsafety_py.make_CANPacket(a, bus, d))) expected = not (a == 0x2FF and bus == 0 and 0 < (d[2] >> 4) < 7) if native_rx_expected is not None: