Files
sunnypilot-byd/tools/car_porting/examples/subaru_fuzzy_fingerprint.ipynb
T
github-actions[bot] de77c89cf6 sunnypilot v2026.002.000
version: sunnypilot v2026.002.000 (staging)
date: 2026-07-21T07:44:02
master commit: 2c334ede443d7391d27575af8c854a095ba702a8
2026-07-21 07:44:02 +00:00

17 KiB

In [6]:
from opendbc.car import structs
from opendbc.car.subaru.values import CAR, SubaruFlags
from opendbc.car.subaru.fingerprints import FW_VERSIONS

TEST_PLATFORMS = set(CAR) - CAR.with_flags(SubaruFlags.PREGLOBAL)

Ecu = structs.CarParams.Ecu

FW_BY_ECU = {platform: {ecu: versions for (ecu, addr, sub_addr), versions in fw_versions.items()} for platform, fw_versions in FW_VERSIONS.items()}
In [7]:
PLATFORM_CODES = {
    Ecu.abs: {
        0: {
            b'\xa5': [CAR.SUBARU_ASCENT, CAR.SUBARU_ASCENT_2023],
            b'\xa2': [CAR.SUBARU_IMPREZA, CAR.SUBARU_IMPREZA_2020, CAR.SUBARU_CROSSTREK_HYBRID],
            b'\xa1': [CAR.SUBARU_OUTBACK, CAR.SUBARU_LEGACY, CAR.SUBARU_OUTBACK_2023],
            b'\xa3': [CAR.SUBARU_FORESTER, CAR.SUBARU_FORESTER_HYBRID, CAR.SUBARU_FORESTER_2022],
            b'z': [CAR.SUBARU_IMPREZA],
        }
    }
}

YEAR_CODES = {
    Ecu.abs: {
        2: {
            b'\x18': 2018,
            b'\x19': 2019,
            b'\x20': 2020,
            b'\x21': 2021,
            b'\x22': 2022,
            b'\x23': 2023,
        }
    }
}
In [8]:
def get_codes(platforms, codes):
  results = []
  for platform in platforms:
    for ecu in codes:
      for i in codes[ecu]:
        if isinstance(i, tuple):
          j = slice(i[0], i[1])
        else:
          j = slice(i, i+1)
        for version in FW_BY_ECU[platform][ecu]:
          code = version[j]
          if code not in codes[ecu][i]:
            print(f"{platform} {code.hex()} not in {codes[ecu][i].keys()}")
          else:
            results.append((platform, codes[ecu][i][code]))
  return results
In [9]:
def test_year_code(platform, year):
  car_docs = CAR(platform).config.car_docs
  if isinstance(car_docs, list):
    car_docs = car_docs[0]
  years = [int(y) for y in car_docs.year_list]
  correct_year = year in years
  print(f"{correct_year=!s: <6} {platform=: <32} {year=: <5} {years=}")

codes = get_codes(TEST_PLATFORMS, YEAR_CODES)
for platform, year in codes:
  test_year_code(platform, year)
SUBARU_IMPREZA 08 not in dict_keys([b'\x18', b'\x19', b' ', b'!', b'"', b'#'])
SUBARU_IMPREZA 08 not in dict_keys([b'\x18', b'\x19', b' ', b'!', b'"', b'#'])
SUBARU_IMPREZA 0c not in dict_keys([b'\x18', b'\x19', b' ', b'!', b'"', b'#'])
SUBARU_IMPREZA 0c not in dict_keys([b'\x18', b'\x19', b' ', b'!', b'"', b'#'])
SUBARU_IMPREZA 2e not in dict_keys([b'\x18', b'\x19', b' ', b'!', b'"', b'#'])
SUBARU_IMPREZA 3f not in dict_keys([b'\x18', b'\x19', b' ', b'!', b'"', b'#'])
correct_year=False  platform=SUBARU_FORESTER                  year=2018  years=[2019, 2020, 2021]
correct_year=False  platform=SUBARU_FORESTER                  year=2018  years=[2019, 2020, 2021]
correct_year=True   platform=SUBARU_FORESTER                  year=2019  years=[2019, 2020, 2021]
correct_year=True   platform=SUBARU_FORESTER                  year=2019  years=[2019, 2020, 2021]
correct_year=True   platform=SUBARU_FORESTER                  year=2019  years=[2019, 2020, 2021]
correct_year=True   platform=SUBARU_FORESTER                  year=2020  years=[2019, 2020, 2021]
correct_year=True   platform=SUBARU_FORESTER                  year=2020  years=[2019, 2020, 2021]
correct_year=True   platform=SUBARU_OUTBACK                   year=2020  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_OUTBACK                   year=2020  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_OUTBACK                   year=2020  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_OUTBACK                   year=2020  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_OUTBACK                   year=2020  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_OUTBACK                   year=2020  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_OUTBACK                   year=2020  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_OUTBACK                   year=2020  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_OUTBACK                   year=2020  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_OUTBACK                   year=2022  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_OUTBACK                   year=2022  years=[2020, 2021, 2022]
correct_year=False  platform=SUBARU_FORESTER_HYBRID           year=2019  years=[2020]
correct_year=False  platform=SUBARU_CROSSTREK_HYBRID          year=2019  years=[2020]
correct_year=False  platform=SUBARU_CROSSTREK_HYBRID          year=2021  years=[2020]
correct_year=True   platform=SUBARU_ASCENT_2023               year=2023  years=[2023]
correct_year=True   platform=SUBARU_IMPREZA                   year=2019  years=[2017, 2018, 2019]
correct_year=True   platform=SUBARU_IMPREZA                   year=2019  years=[2017, 2018, 2019]
correct_year=True   platform=SUBARU_IMPREZA                   year=2018  years=[2017, 2018, 2019]
correct_year=True   platform=SUBARU_IMPREZA                   year=2019  years=[2017, 2018, 2019]
correct_year=True   platform=SUBARU_IMPREZA                   year=2019  years=[2017, 2018, 2019]
correct_year=True   platform=SUBARU_IMPREZA                   year=2019  years=[2017, 2018, 2019]
correct_year=False  platform=SUBARU_FORESTER_2022             year=2021  years=[2022, 2023, 2024]
correct_year=False  platform=SUBARU_FORESTER_2022             year=2021  years=[2022, 2023, 2024]
correct_year=True   platform=SUBARU_FORESTER_2022             year=2022  years=[2022, 2023, 2024]
correct_year=True   platform=SUBARU_FORESTER_2022             year=2022  years=[2022, 2023, 2024]
correct_year=True   platform=SUBARU_ASCENT                    year=2019  years=[2019, 2020, 2021]
correct_year=True   platform=SUBARU_ASCENT                    year=2021  years=[2019, 2020, 2021]
correct_year=True   platform=SUBARU_OUTBACK_2023              year=2023  years=[2023]
correct_year=True   platform=SUBARU_OUTBACK_2023              year=2023  years=[2023]
correct_year=False  platform=SUBARU_IMPREZA_2020              year=2019  years=[2020, 2021, 2022]
correct_year=False  platform=SUBARU_IMPREZA_2020              year=2019  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_IMPREZA_2020              year=2020  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_IMPREZA_2020              year=2021  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_IMPREZA_2020              year=2021  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_IMPREZA_2020              year=2021  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_IMPREZA_2020              year=2021  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_LEGACY                    year=2020  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_LEGACY                    year=2020  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_LEGACY                    year=2020  years=[2020, 2021, 2022]
correct_year=True   platform=SUBARU_LEGACY                    year=2020  years=[2020, 2021, 2022]
In [10]:
def test_platform_code(platform, platforms):
  platforms = [str(p) for p in platforms]
  in_possible_platforms = platform in platforms
  print(f"{in_possible_platforms=!s: <6} {platform=: <32} {platforms=}")

codes = get_codes(TEST_PLATFORMS, PLATFORM_CODES)
for platform, possible_platforms in codes:
  test_platform_code(platform, possible_platforms)
in_possible_platforms=True   platform=SUBARU_FORESTER                  platforms=['SUBARU_FORESTER', 'SUBARU_FORESTER_HYBRID', 'SUBARU_FORESTER_2022']
in_possible_platforms=True   platform=SUBARU_FORESTER                  platforms=['SUBARU_FORESTER', 'SUBARU_FORESTER_HYBRID', 'SUBARU_FORESTER_2022']
in_possible_platforms=True   platform=SUBARU_FORESTER                  platforms=['SUBARU_FORESTER', 'SUBARU_FORESTER_HYBRID', 'SUBARU_FORESTER_2022']
in_possible_platforms=True   platform=SUBARU_FORESTER                  platforms=['SUBARU_FORESTER', 'SUBARU_FORESTER_HYBRID', 'SUBARU_FORESTER_2022']
in_possible_platforms=True   platform=SUBARU_FORESTER                  platforms=['SUBARU_FORESTER', 'SUBARU_FORESTER_HYBRID', 'SUBARU_FORESTER_2022']
in_possible_platforms=True   platform=SUBARU_FORESTER                  platforms=['SUBARU_FORESTER', 'SUBARU_FORESTER_HYBRID', 'SUBARU_FORESTER_2022']
in_possible_platforms=True   platform=SUBARU_FORESTER                  platforms=['SUBARU_FORESTER', 'SUBARU_FORESTER_HYBRID', 'SUBARU_FORESTER_2022']
in_possible_platforms=True   platform=SUBARU_OUTBACK                   platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_OUTBACK                   platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_OUTBACK                   platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_OUTBACK                   platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_OUTBACK                   platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_OUTBACK                   platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_OUTBACK                   platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_OUTBACK                   platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_OUTBACK                   platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_OUTBACK                   platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_OUTBACK                   platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_FORESTER_HYBRID           platforms=['SUBARU_FORESTER', 'SUBARU_FORESTER_HYBRID', 'SUBARU_FORESTER_2022']
in_possible_platforms=True   platform=SUBARU_CROSSTREK_HYBRID          platforms=['SUBARU_IMPREZA', 'SUBARU_IMPREZA_2020', 'SUBARU_CROSSTREK_HYBRID']
in_possible_platforms=True   platform=SUBARU_CROSSTREK_HYBRID          platforms=['SUBARU_IMPREZA', 'SUBARU_IMPREZA_2020', 'SUBARU_CROSSTREK_HYBRID']
in_possible_platforms=True   platform=SUBARU_ASCENT_2023               platforms=['SUBARU_ASCENT', 'SUBARU_ASCENT_2023']
in_possible_platforms=True   platform=SUBARU_IMPREZA                   platforms=['SUBARU_IMPREZA']
in_possible_platforms=True   platform=SUBARU_IMPREZA                   platforms=['SUBARU_IMPREZA']
in_possible_platforms=True   platform=SUBARU_IMPREZA                   platforms=['SUBARU_IMPREZA']
in_possible_platforms=True   platform=SUBARU_IMPREZA                   platforms=['SUBARU_IMPREZA']
in_possible_platforms=True   platform=SUBARU_IMPREZA                   platforms=['SUBARU_IMPREZA']
in_possible_platforms=True   platform=SUBARU_IMPREZA                   platforms=['SUBARU_IMPREZA']
in_possible_platforms=True   platform=SUBARU_IMPREZA                   platforms=['SUBARU_IMPREZA']
in_possible_platforms=True   platform=SUBARU_IMPREZA                   platforms=['SUBARU_IMPREZA']
in_possible_platforms=True   platform=SUBARU_IMPREZA                   platforms=['SUBARU_IMPREZA', 'SUBARU_IMPREZA_2020', 'SUBARU_CROSSTREK_HYBRID']
in_possible_platforms=True   platform=SUBARU_IMPREZA                   platforms=['SUBARU_IMPREZA', 'SUBARU_IMPREZA_2020', 'SUBARU_CROSSTREK_HYBRID']
in_possible_platforms=True   platform=SUBARU_IMPREZA                   platforms=['SUBARU_IMPREZA', 'SUBARU_IMPREZA_2020', 'SUBARU_CROSSTREK_HYBRID']
in_possible_platforms=True   platform=SUBARU_IMPREZA                   platforms=['SUBARU_IMPREZA', 'SUBARU_IMPREZA_2020', 'SUBARU_CROSSTREK_HYBRID']
in_possible_platforms=True   platform=SUBARU_FORESTER_2022             platforms=['SUBARU_FORESTER', 'SUBARU_FORESTER_HYBRID', 'SUBARU_FORESTER_2022']
in_possible_platforms=True   platform=SUBARU_FORESTER_2022             platforms=['SUBARU_FORESTER', 'SUBARU_FORESTER_HYBRID', 'SUBARU_FORESTER_2022']
in_possible_platforms=True   platform=SUBARU_FORESTER_2022             platforms=['SUBARU_FORESTER', 'SUBARU_FORESTER_HYBRID', 'SUBARU_FORESTER_2022']
in_possible_platforms=True   platform=SUBARU_FORESTER_2022             platforms=['SUBARU_FORESTER', 'SUBARU_FORESTER_HYBRID', 'SUBARU_FORESTER_2022']
in_possible_platforms=True   platform=SUBARU_ASCENT                    platforms=['SUBARU_ASCENT', 'SUBARU_ASCENT_2023']
in_possible_platforms=True   platform=SUBARU_ASCENT                    platforms=['SUBARU_ASCENT', 'SUBARU_ASCENT_2023']
in_possible_platforms=True   platform=SUBARU_OUTBACK_2023              platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_OUTBACK_2023              platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_IMPREZA_2020              platforms=['SUBARU_IMPREZA', 'SUBARU_IMPREZA_2020', 'SUBARU_CROSSTREK_HYBRID']
in_possible_platforms=True   platform=SUBARU_IMPREZA_2020              platforms=['SUBARU_IMPREZA', 'SUBARU_IMPREZA_2020', 'SUBARU_CROSSTREK_HYBRID']
in_possible_platforms=True   platform=SUBARU_IMPREZA_2020              platforms=['SUBARU_IMPREZA', 'SUBARU_IMPREZA_2020', 'SUBARU_CROSSTREK_HYBRID']
in_possible_platforms=True   platform=SUBARU_IMPREZA_2020              platforms=['SUBARU_IMPREZA', 'SUBARU_IMPREZA_2020', 'SUBARU_CROSSTREK_HYBRID']
in_possible_platforms=True   platform=SUBARU_IMPREZA_2020              platforms=['SUBARU_IMPREZA', 'SUBARU_IMPREZA_2020', 'SUBARU_CROSSTREK_HYBRID']
in_possible_platforms=True   platform=SUBARU_IMPREZA_2020              platforms=['SUBARU_IMPREZA', 'SUBARU_IMPREZA_2020', 'SUBARU_CROSSTREK_HYBRID']
in_possible_platforms=True   platform=SUBARU_IMPREZA_2020              platforms=['SUBARU_IMPREZA', 'SUBARU_IMPREZA_2020', 'SUBARU_CROSSTREK_HYBRID']
in_possible_platforms=True   platform=SUBARU_LEGACY                    platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_LEGACY                    platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_LEGACY                    platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
in_possible_platforms=True   platform=SUBARU_LEGACY                    platforms=['SUBARU_OUTBACK', 'SUBARU_LEGACY', 'SUBARU_OUTBACK_2023']
In [ ]: