Files
IQ.Pilot/iqdbc_repo/iqdbc/car/volkswagen/tests/test_volkswagen.py
2026-08-22 23:42:42 -05:00

130 lines
5.2 KiB
Python

import random
import re
from types import SimpleNamespace
import pytest
from iqdbc.car import structs
from iqdbc.car.volkswagen.carstate import CarState
from iqdbc.car.structs import CarParams
from iqdbc.car.volkswagen.values import CAR, FW_QUERY_CONFIG, WMI
from iqdbc.car.volkswagen.fingerprints import FW_VERSIONS
Ecu = CarParams.Ecu
CHASSIS_CODE_PATTERN = re.compile('[A-Z0-9]{2}')
# TODO: determine the unknown groups
SPARE_PART_FW_PATTERN = re.compile(b'\xf1\x87(?P<gateway>[0-9][0-9A-Z]{2})(?P<unknown>[0-9][0-9A-Z][0-9])(?P<unknown2>[0-9A-Z]{2}[0-9])([A-Z0-9]| )')
class TestVolkswagenPlatformConfigs:
def test_spare_part_fw_pattern(self, subtests):
# Relied on for determining if a FW is likely VW
for platform, ecus in FW_VERSIONS.items():
with subtests.test(platform=platform.value):
for fws in ecus.values():
for fw in fws:
assert SPARE_PART_FW_PATTERN.match(fw) is not None, f"Bad FW: {fw}"
def test_chassis_codes(self, subtests):
for platform in CAR:
with subtests.test(platform=platform.value):
assert len(platform.config.wmis) > 0, "WMIs not set"
assert len(platform.config.chassis_codes) > 0, "Chassis codes not set"
assert all(CHASSIS_CODE_PATTERN.match(cc) for cc in
platform.config.chassis_codes), "Bad chassis codes"
# No two platforms should share chassis codes
for comp in CAR:
if platform == comp:
continue
shared_chassis_codes = platform.config.chassis_codes & comp.config.chassis_codes
if len(shared_chassis_codes) == 0:
continue
# A shared chassis code is unambiguous when the VIN WMI separates the candidates.
if platform.config.wmis.isdisjoint(comp.config.wmis):
continue
platform_model_years = getattr(platform.config, "model_years", set())
comp_model_years = getattr(comp.config, "model_years", set())
if platform_model_years and comp_model_years and platform_model_years.isdisjoint(comp_model_years):
continue
assert set() == shared_chassis_codes, f"Shared chassis codes: {comp}"
def test_custom_fuzzy_fingerprinting(self, subtests):
all_radar_fw = list({fw for ecus in FW_VERSIONS.values() for fw in ecus.get((Ecu.fwdRadar, 0x757, None), [])})
for platform in CAR:
with subtests.test(platform=platform.name):
# Fuzzy matching keys off the radar ECU (CHECK_FUZZY_ECUS), so a platform that
# declares no radar ECU can never be VIN-matched and should never be expected to match.
platform_has_radar = (Ecu.fwdRadar, 0x757, None) in FW_VERSIONS.get(platform, {})
for wmi in WMI:
for chassis_code in platform.config.chassis_codes | {"00"}:
platform_model_years = getattr(platform.config, "model_years", set())
model_years = platform_model_years if platform_model_years else {"0"}
for model_year in model_years | {"0"}:
vin = ["0"] * 17
vin[0:3] = wmi
vin[6:8] = chassis_code
vin[9] = model_year
vin = "".join(vin)
# Check a few FW cases - expected, unexpected
for radar_fw in random.sample(all_radar_fw, 5) + [b'\xf1\x875Q0907572G \xf1\x890571', b'\xf1\x877H9907572AA\xf1\x890396']:
model_year_match = len(platform_model_years) == 0 or model_year in platform_model_years
should_match = ((wmi in platform.config.wmis and chassis_code in platform.config.chassis_codes and model_year_match) and
radar_fw in all_radar_fw and platform_has_radar)
live_fws = {(0x757, None): [radar_fw]}
matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(live_fws, vin, FW_VERSIONS)
expected_matches = {platform} if should_match else set()
assert expected_matches == matches, "Bad match"
@pytest.mark.parametrize("button_type", (
structs.CarState.ButtonEvent.Type.setCruise,
structs.CarState.ButtonEvent.Type.resumeCruise,
))
def test_button_enable_is_blocked_while_cruise_fault_lateral_mode_is_still_faulted(button_type):
state = object.__new__(CarState)
state.CP = SimpleNamespace(pcmCruise=False)
state.cruise_fault_lateral_active = True
state.cruise_faulted = True
button_events = [structs.CarState.ButtonEvent(pressed=False, type=button_type)]
assert not state.update_button_enable(button_events)
def test_button_enable_recovers_once_cruise_fault_clears():
state = object.__new__(CarState)
state.CP = SimpleNamespace(pcmCruise=False)
state.cruise_fault_lateral_active = True
state.cruise_faulted = False
button_events = [structs.CarState.ButtonEvent(
pressed=False,
type=structs.CarState.ButtonEvent.Type.setCruise,
)]
assert state.update_button_enable(button_events)
def test_pq_hca_ready_does_not_complete_eps_initialization():
state = object.__new__(CarState)
state.eps_init_complete = False
state.frame = 0
assert state.update_hca_state("READY", ready_confirms_init=False) == (True, False)
state.frame = 317
assert state.update_hca_state("FAULT", ready_confirms_init=False) == (True, False)
state.frame = 1001
assert state.update_hca_state("FAULT", ready_confirms_init=False) == (False, True)