Restore Subaru Firmware Recognition

This commit is contained in:
firestar5683
2026-10-19 00:47:35 -05:00
parent 3a8dbe75f1
commit 5968a0620e
2 changed files with 108 additions and 0 deletions
@@ -37,18 +37,24 @@ FW_VERSIONS = {
CAR.SUBARU_ASCENT_2023: {
(Ecu.abs, 0x7b0, None): [
b'\xa5 #\x03\x00',
b'\xa5 %\x03\x01',
],
(Ecu.eps, 0x746, None): [
b'%\xc0\xd0\x11',
b'U\xc0\xd0\x10',
],
(Ecu.fwdCamera, 0x787, None): [
b'\x05!\x08\x1dK\x05!\x08\x01/',
b'\x17!\x08\x01A\x12!\x08\x00;',
b'\x17!\x08\x01A\x00\x00\x00\x00\x00',
],
(Ecu.engine, 0x7a2, None): [
b'\xe5,\xa0P\x07',
b'\x11,\xa00\x07',
],
(Ecu.transmission, 0x7a3, None): [
b'\x04\xfe\xf3\x00\x00',
b'\x05\xfe\xe7\x00\x00',
],
},
CAR.SUBARU_LEGACY: {
@@ -587,4 +593,37 @@ FW_VERSIONS = {
b'\xa8\xfe\xf41\x00',
],
},
CAR.SUBARU_CROSSTREK_2025: {
(Ecu.abs, 0x7b0, None): [
b'\xa2 $\x15\x05',
b'\xa2 $\x17\x06',
],
(Ecu.fwdCamera, 0x787, None): [
b'\x1d!\x08\x00F\x14!\x08\x00=',
b'\x1b!\x08\x00D\x11!\x08\x01;',
],
(Ecu.engine, 0x7a2, None): [
b'\x04"cP\x07',
b'\xe8!cp\x07',
],
},
CAR.SUBARU_LEGACY_2025: {
(Ecu.abs, 0x7b0, None): [
b'\xa1 $\x11\x00',
],
(Ecu.eps, 0x746, None): [
b'[\xc0\xd1\x10\x00',
],
(Ecu.fwdCamera, 0x787, None): [
b'\x1a!\x08\x00C\x0e!\x08\x018',
],
(Ecu.engine, 0x7a2, None): [
b'\x08,\xa0p\x07',
],
(Ecu.transmission, 0x7a3, None): [
b'\xeb\x17U!r',
],
},
}
@@ -0,0 +1,69 @@
"""Supported Subaru identities preserve exact matching and stock-only admission."""
import unittest
from opendbc.car.structs import CarParams
from opendbc.car.fw_versions import match_fw_to_car_exact
from opendbc.car.subaru.fingerprints import FW_VERSIONS
from opendbc.car.subaru.interface import CarInterface
from opendbc.car.subaru.values import CAR
RESTORED = [
('SUBARU_ASCENT_2023', 'abs', 1968, 'a520250301'),
('SUBARU_ASCENT_2023', 'eps', 1862, '55c0d010'),
('SUBARU_ASCENT_2023', 'fwdCamera', 1927, '1721080141122108003b'),
('SUBARU_ASCENT_2023', 'fwdCamera', 1927, '17210801410000000000'),
('SUBARU_ASCENT_2023', 'engine', 1954, '112ca03007'),
('SUBARU_ASCENT_2023', 'transmission', 1955, '05fee70000'),
('SUBARU_CROSSTREK_2025', 'abs', 1968, 'a220241505'),
('SUBARU_CROSSTREK_2025', 'abs', 1968, 'a220241706'),
('SUBARU_CROSSTREK_2025', 'fwdCamera', 1927, '1d21080046142108003d'),
('SUBARU_CROSSTREK_2025', 'fwdCamera', 1927, '1b21080044112108013b'),
('SUBARU_CROSSTREK_2025', 'engine', 1954, '0422635007'),
('SUBARU_CROSSTREK_2025', 'engine', 1954, 'e821637007'),
('SUBARU_LEGACY_2025', 'abs', 1968, 'a120241100'),
('SUBARU_LEGACY_2025', 'eps', 1862, '5bc0d11000'),
('SUBARU_LEGACY_2025', 'fwdCamera', 1927, '1a210800430e21080138'),
('SUBARU_LEGACY_2025', 'engine', 1954, '082ca07007'),
('SUBARU_LEGACY_2025', 'transmission', 1955, 'eb17552172'),
]
class TestSupportedSubaruFirmware(unittest.TestCase):
def test_each_restored_identity_reaches_the_real_exact_matcher(self):
for name, ecu_name, address, encoded in RESTORED:
with self.subTest(platform=name, ecu=ecu_name, firmware=encoded):
platform = CAR[name]
self.assertIn(platform, FW_VERSIONS)
versions = FW_VERSIONS[platform]
live = {(addr, sub): {values[0]} for (_, addr, sub), values in versions.items()}
live[address, None] = {bytes.fromhex(encoded)}
self.assertEqual(match_fw_to_car_exact(live, match_brand='subaru', log=False), {platform})
def test_unknown_engine_and_camera_still_reject_the_platform(self):
for name in sorted({row[0] for row in RESTORED}):
platform = CAR[name]
for (ecu, address, sub), _ in FW_VERSIONS[platform].items():
if ecu not in (CarParams.Ecu.engine, CarParams.Ecu.fwdCamera):
continue
with self.subTest(platform=name, ecu=ecu):
live = {(addr, sa): {values[0]} for (_, addr, sa), values in FW_VERSIONS[platform].items()}
live[address, sub] = {b'unknown firmware'}
self.assertNotIn(platform, match_fw_to_car_exact(live, match_brand='subaru', log=False))
def test_existing_stock_admission_and_disabled_alpha_are_preserved(self):
words = {CAR.SUBARU_ASCENT_2023: 177, CAR.SUBARU_CROSSTREK_2025: 17, CAR.SUBARU_LEGACY_2025: 145}
for platform, word in words.items():
for alpha in (False, True):
for release in (False, True):
with self.subTest(platform=platform, alpha=alpha, release=release):
cp = CarInterface.get_params(platform, {0: {}, 1: {}, 2: {}}, [], alpha, release, False)
self.assertFalse(cp.dashcamOnly)
self.assertFalse(cp.alphaLongitudinalAvailable)
self.assertFalse(cp.openpilotLongitudinalControl)
self.assertTrue(cp.pcmCruise)
self.assertEqual(cp.safetyConfigs[0].safetyParam, word)
def test_three_byte_diagnostic_response_is_not_a_camera_identity(self):
for platform in (CAR.SUBARU_ASCENT_2023, CAR.SUBARU_LEGACY_2025):
for versions in FW_VERSIONS[platform].values():
self.assertNotIn(bytes.fromhex('20020e'), versions)