mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-10-28 00:53:45 +08:00
Restore MQB fixed and second-Panda lateral ownership
This commit is contained in:
@@ -15,6 +15,9 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
@staticmethod
|
||||
def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
|
||||
CAN = CanBus(fingerprint=fingerprint)
|
||||
if CAN.pt == 4:
|
||||
fingerprint = {bus: fingerprint.get(CAN.pt + bus, {}) for bus in range(4)}
|
||||
ret.brand = "volkswagen"
|
||||
ret.radarUnavailable = Bus.radar not in DBC[candidate]
|
||||
|
||||
@@ -142,7 +145,6 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.stopAccel = -0.55
|
||||
ret.autoResumeSng = ret.minEnableSpeed == -1
|
||||
|
||||
CAN = CanBus(fingerprint=fingerprint)
|
||||
if CAN.pt >= 4:
|
||||
safety_configs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
|
||||
ret.safetyConfigs = safety_configs
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""Exact MQB stock-ACC capability; direct drive/system-long remain ordinary."""
|
||||
"""Exact MQB stock-ACC capability; direct drive remains ordinary."""
|
||||
from opendbc.car import Bus, structs
|
||||
from opendbc.car.volkswagen.values import CAR, DBC, VolkswagenFlags
|
||||
|
||||
@@ -10,20 +10,33 @@ MQB_CARS = frozenset(car for car in CAR if DBC[car].get(Bus.pt) == "vw_mqb" and
|
||||
KNOWN_FLAGS = int(VolkswagenFlags.STOCK_HCA_PRESENT | VolkswagenFlags.KOMBI_PRESENT | VolkswagenFlags.HAS_BSM)
|
||||
|
||||
|
||||
def safety_config(cp):
|
||||
"""One owner, optionally preceded by one quiet noOutput board."""
|
||||
try:
|
||||
configs = cp.safetyConfigs
|
||||
if len(configs) == 1:
|
||||
return configs[0]
|
||||
if (len(configs) == 2 and configs[0].safetyModel == structs.CarParams.SafetyModel.noOutput and
|
||||
configs[0].safetyParam == 0):
|
||||
return configs[1]
|
||||
except (AttributeError, TypeError, ValueError, OverflowError, IndexError):
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
def _qualified(cp, *, marked_only=False, longitudinal=False):
|
||||
if (cp is None or cp.brand != "volkswagen" or cp.carFingerprint not in MQB_CARS or
|
||||
cp.passive or cp.notCar or cp.dashcamOnly or cp.flags & ~KNOWN_FLAGS or
|
||||
cp.steerControlType != structs.CarParams.SteerControlType.torque or
|
||||
cp.transmissionType not in (structs.CarParams.TransmissionType.automatic, structs.CarParams.TransmissionType.manual) or
|
||||
cp.networkLocation not in (structs.CarParams.NetworkLocation.gateway, structs.CarParams.NetworkLocation.fwdCamera) or
|
||||
cp.fingerprintSource == structs.CarParams.FingerprintSource.fixed or
|
||||
bool(cp.openpilotLongitudinalControl) != longitudinal or bool(cp.pcmCruise) == longitudinal or len(cp.safetyConfigs) != 1 or
|
||||
bool(cp.openpilotLongitudinalControl) != longitudinal or bool(cp.pcmCruise) == longitudinal or
|
||||
(longitudinal and (cp.networkLocation != structs.CarParams.NetworkLocation.gateway or not cp.alphaLongitudinalAvailable))):
|
||||
return False
|
||||
word = AOL_WORD | (MANUAL_WORD if cp.transmissionType == structs.CarParams.TransmissionType.manual else 0)
|
||||
word |= int(longitudinal)
|
||||
safety = cp.safetyConfigs[0]
|
||||
return (safety.safetyModel == structs.CarParams.SafetyModel.volkswagen and
|
||||
safety = safety_config(cp)
|
||||
return (safety is not None and safety.safetyModel == structs.CarParams.SafetyModel.volkswagen and
|
||||
(cp.alternativeExperience == 32 and safety.safetyParam == word or
|
||||
not marked_only and cp.alternativeExperience == 0 and safety.safetyParam == int(longitudinal)))
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ from openpilot.starpilot.aol.vehicle import policy_for
|
||||
|
||||
@pytest.mark.parametrize('manual', (False, True))
|
||||
@pytest.mark.parametrize('gateway,alpha', ((False, False), (True, False), (True, True)))
|
||||
def test_normal_golf_discovery_and_card_stock_aol_owner(manual, gateway, alpha):
|
||||
def test_normal_golf_discovery_and_card_stock_aol_owner(manual, gateway, alpha, offset=0, fixed=False):
|
||||
fixture = {'kind': 'EXPLICIT_SYNTHETIC_FULL_ECU_DISCOVERY_INPUT_FROM_REUSED_INVENTORY_NOT_ROUTE_OR_PHYSICAL',
|
||||
'identity': 'VOLKSWAGEN_GOLF_MK7',
|
||||
'vin': 'WVWZZZAUZGW000000',
|
||||
@@ -47,15 +47,15 @@ def test_normal_golf_discovery_and_card_stock_aol_owner(manual, gateway, alpha):
|
||||
'origin': 'Synthetic ECU bytes from configuration-matrix.json; actual matcher must verify uniqueness.'}
|
||||
fw = [structs.CarParams.CarFw(ecu=getattr(structs.CarParams.Ecu, r['ecu']),
|
||||
address=r['address'], subAddress=r['subAddress'] or 0, fwVersion=bytes.fromhex(r['fwVersion']),
|
||||
brand='volkswagen', bus=0) for r in fixture['firmware']]
|
||||
brand='volkswagen', bus=offset) for r in fixture['firmware']]
|
||||
exact, candidates = match_fw_to_car(fw, fixture['vin'], log=False)
|
||||
assert exact and candidates == {CAR.VOLKSWAGEN_GOLF_MK7}, (exact, candidates)
|
||||
packer = CANPacker('vw_mqb')
|
||||
incoming = [packer.make_can_msg('GRA_ACC_01', 0, {'GRA_Hauptschalter': 1})]
|
||||
incoming = [packer.make_can_msg('GRA_ACC_01', offset, {'GRA_Hauptschalter': 1})]
|
||||
if not manual:
|
||||
incoming.append(packer.make_can_msg('Getriebe_11', 0, {}))
|
||||
incoming.append(packer.make_can_msg('Getriebe_11', offset, {}))
|
||||
if gateway:
|
||||
incoming.append(packer.make_can_msg('ESP_21', 1, {}))
|
||||
incoming.append(packer.make_can_msg('ESP_21', offset + 1, {}))
|
||||
frames = [CanData(address=address, dat=data, src=bus) for address, data, bus in incoming]
|
||||
|
||||
def receive(wait_for_one=False):
|
||||
@@ -77,10 +77,12 @@ def test_normal_golf_discovery_and_card_stock_aol_owner(manual, gateway, alpha):
|
||||
mock.patch.object(car_helpers, 'get_present_ecus', return_value=set()),
|
||||
mock.patch.object(car_helpers, 'get_fw_versions_ordered', return_value=fw)):
|
||||
# Normal public get_car: do NOT stub fingerprint, match_fw_to_car or candidate selection.
|
||||
ci = car_helpers.get_car(receive, lambda *args, **kwargs: None, lambda _: None, alpha, False)
|
||||
ci = car_helpers.get_car(receive, lambda *args, **kwargs: None, lambda _: None, alpha, False,
|
||||
forced_candidate=CAR.VOLKSWAGEN_GOLF_MK7 if fixed else None)
|
||||
cp = ci.CP
|
||||
assert cp.carFingerprint == CAR.VOLKSWAGEN_GOLF_MK7
|
||||
assert cp.fingerprintSource == structs.CarParams.FingerprintSource.fw and not cp.fuzzyFingerprint
|
||||
assert cp.fingerprintSource == (structs.CarParams.FingerprintSource.fixed if fixed else
|
||||
structs.CarParams.FingerprintSource.fw) and not cp.fuzzyFingerprint
|
||||
assert cp.carVin == fixture['vin'] and len(cp.carFw) == len(fw)
|
||||
assert cp.transmissionType == (structs.CarParams.TransmissionType.manual if manual else
|
||||
structs.CarParams.TransmissionType.automatic)
|
||||
@@ -92,7 +94,11 @@ def test_normal_golf_discovery_and_card_stock_aol_owner(manual, gateway, alpha):
|
||||
card = Car(CI=ci, RI=ci.RadarInterface(cp))
|
||||
try:
|
||||
assert card.aol_qualified and card.aol_card_intent is not None
|
||||
assert card.CP.safetyConfigs[0].safetyParam == ((24 if manual else 8) | int(alpha))
|
||||
assert card.CP.safetyConfigs[-1].safetyParam == ((24 if manual else 8) | int(alpha))
|
||||
assert len(card.CP.safetyConfigs) == (2 if offset else 1)
|
||||
if offset:
|
||||
assert card.CP.safetyConfigs[0].safetyModel == structs.CarParams.SafetyModel.noOutput
|
||||
assert card.CP.safetyConfigs[0].safetyParam == 0
|
||||
assert card.CP.alternativeExperience == 32
|
||||
with structs.CarParams.from_bytes(params.get('CarParams')) as published:
|
||||
assert published.to_dict() == card.CP.to_dict()
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
"""New fixed and owner-slot discovery contexts; real matcher and public get_car."""
|
||||
import pytest
|
||||
from opendbc.car.volkswagen.tests import test_mqb_aol_discovery as discovery
|
||||
|
||||
|
||||
@pytest.mark.parametrize('manual', (False, True))
|
||||
@pytest.mark.parametrize('gateway,alpha', ((False, False), (True, False), (True, True)))
|
||||
@pytest.mark.parametrize('offset,fixed', ((0, True), (4, False), (4, True)))
|
||||
def test_topology_fixed_discovery(manual, gateway, alpha, offset, fixed):
|
||||
discovery.test_normal_golf_discovery_and_card_stock_aol_owner(manual, gateway, alpha, offset, fixed)
|
||||
@@ -40,7 +40,8 @@ from opendbc.car.honda.stock_aol import (
|
||||
qualified as qualified_honda_stock_aol, native_observation as honda_native_observation,
|
||||
temporary_restriction as honda_temporary_restriction,
|
||||
)
|
||||
from opendbc.car.volkswagen.stock_aol import native_observation as volkswagen_native_observation
|
||||
from opendbc.car.volkswagen.stock_aol import (native_observation as volkswagen_native_observation,
|
||||
safety_config as volkswagen_aol_safety_config)
|
||||
from openpilot.starpilot.car.volkswagen.aol import (qualified as qualified_volkswagen_aol,
|
||||
temporary_restriction as volkswagen_temporary_restriction)
|
||||
from openpilot.starpilot.car.rivian.aol import retained_brake_lateral_intent as rivian_brake_intent_retained
|
||||
@@ -386,7 +387,8 @@ class Car:
|
||||
self.aol_sequence = 0
|
||||
self.aol_process_fault_context = AolProcessFaultContext() if self.aol_replay else None
|
||||
if self.aol_qualified:
|
||||
config = hyundai_aol_safety_config(self.CP) if self.CP.brand == 'hyundai' else self.CP.safetyConfigs[0]
|
||||
config = (volkswagen_aol_safety_config(self.CP) if self.CP.brand == 'volkswagen' else
|
||||
(hyundai_aol_safety_config(self.CP) if self.CP.brand == 'hyundai' else self.CP.safetyConfigs[0]))
|
||||
if config is None:
|
||||
raise RuntimeError('AOL requires the exact vehicle safety configuration')
|
||||
config.safetyParam |= aol_policy.safety_param_addition
|
||||
|
||||
@@ -130,11 +130,13 @@ def test_mqb_full_engagement_brake_reverse_drive_actual_callers(gearbox, alpha,
|
||||
for prime in range(-110, 0):
|
||||
ambient_update((10_000_000_000 + prime * 10_000_000) / 1e9, [])
|
||||
card.slc_producer_session = 'authority-card'
|
||||
class Publisher:
|
||||
class Publisher(messaging.PubMaster):
|
||||
def __init__(self):
|
||||
self.messages = {}
|
||||
def send(self, service, message):
|
||||
self.messages[service] = messaging.log_from_bytes(message.to_bytes())
|
||||
def send(self, s, dat):
|
||||
if not isinstance(dat, bytes):
|
||||
dat = dat.to_bytes()
|
||||
self.messages[s] = messaging.log_from_bytes(dat)
|
||||
card.pm = Publisher()
|
||||
native = libsafety_py.libsafety
|
||||
cleanup.callback(native.init_tests)
|
||||
@@ -180,7 +182,7 @@ def test_mqb_full_engagement_brake_reverse_drive_actual_callers(gearbox, alpha,
|
||||
if isinstance(name, str) and name in dbc.name_to_msg:
|
||||
if tick < 3 and name in ('TSK_06', 'LH_EPS_03'):
|
||||
continue # Real startup may receive other CAN sources before cruise and EPS.
|
||||
fields = dict(overrides.get(name, {}))
|
||||
fields: dict[str, float] = dict(overrides.get(name, {}))
|
||||
if 'COUNTER' in dbc.name_to_msg[name].sigs:
|
||||
fields['COUNTER'] = tick % 16
|
||||
incoming.append(packer.make_can_msg(name, parser.bus, fields))
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
"""New topology/fixed contexts through the existing actual caller harness.
|
||||
|
||||
Requires source-matched native preloading; no compiler or native permission stub.
|
||||
"""
|
||||
import pytest
|
||||
from openpilot.starpilot.aol.tests import test_mqb_actual_callers as callers
|
||||
|
||||
|
||||
@pytest.mark.parametrize('gearbox', ('automatic', 'manual'))
|
||||
@pytest.mark.parametrize('alpha', (False, True))
|
||||
@pytest.mark.parametrize('offset,fixed', ((0, True), (4, False), (4, True)))
|
||||
@pytest.mark.parametrize('engage_on_set', (False, True))
|
||||
def test_topology_fixed_actual_callers(gearbox, alpha, offset, fixed, engage_on_set):
|
||||
callers.test_mqb_full_engagement_brake_reverse_drive_actual_callers(gearbox, alpha, offset, fixed, engage_on_set)
|
||||
@@ -0,0 +1,66 @@
|
||||
"""Family CP and ordered native inventory contracts for the new topology contexts."""
|
||||
from dataclasses import replace
|
||||
from types import SimpleNamespace
|
||||
import pytest
|
||||
from opendbc.car import gen_empty_fingerprint, structs
|
||||
from opendbc.car.volkswagen.interface import CarInterface
|
||||
from opendbc.car.volkswagen.stock_aol import MQB_CARS, safety_config
|
||||
from openpilot.starpilot.aol.runtime import native_inventory_matches_cp
|
||||
from openpilot.starpilot.aol.vehicle import policy_for, native_matches_cp
|
||||
from openpilot.starpilot.aol.wire import PandaSlot
|
||||
from openpilot.starpilot.car.volkswagen.aol import qualified
|
||||
|
||||
|
||||
def params(identity, manual, alpha, offset, fixed):
|
||||
fp = gen_empty_fingerprint()
|
||||
if not manual:
|
||||
fp[offset][0xAD] = 8
|
||||
fp[offset + 1][0xFD] = 8
|
||||
cp = CarInterface.get_params(identity, fp, [], alpha, False, False)
|
||||
cp.fingerprintSource = structs.CarParams.FingerprintSource.fixed if fixed else structs.CarParams.FingerprintSource.fw
|
||||
return cp
|
||||
|
||||
|
||||
@pytest.mark.parametrize('identity', sorted(MQB_CARS))
|
||||
@pytest.mark.parametrize('manual', (False, True))
|
||||
@pytest.mark.parametrize('alpha', (False, True))
|
||||
@pytest.mark.parametrize('offset,fixed', ((0, True), (4, False), (4, True)))
|
||||
def test_exact_family_identity_topology_and_owner(identity, manual, alpha, offset, fixed):
|
||||
cp = params(identity, manual, alpha, offset, fixed)
|
||||
policy = policy_for(cp)
|
||||
assert policy.intent_supported
|
||||
owner = safety_config(cp)
|
||||
assert owner is not None and owner.safetyModel == structs.CarParams.SafetyModel.volkswagen
|
||||
owner.safetyParam |= policy.safety_param_addition
|
||||
cp.alternativeExperience |= policy.alternative_experience_addition
|
||||
word = (24 if manual else 8) | int(alpha)
|
||||
assert qualified(cp, marked_only=True) and native_matches_cp(cp, 15, word)
|
||||
assert cp.pcmCruise != alpha and cp.openpilotLongitudinalControl == alpha
|
||||
if offset:
|
||||
assert cp.safetyConfigs[0].safetyModel == structs.CarParams.SafetyModel.noOutput
|
||||
assert cp.safetyConfigs[0].safetyParam == 0
|
||||
assert not native_matches_cp(cp, 15, word ^ 16)
|
||||
assert not native_matches_cp(cp, 34, word)
|
||||
|
||||
|
||||
def test_exact_ordered_inventory_denies_incoherent_or_active_prefix():
|
||||
cp = params(sorted(MQB_CARS)[0], False, False, 4, True)
|
||||
policy = policy_for(cp)
|
||||
safety_config(cp).safetyParam |= policy.safety_param_addition
|
||||
cp.alternativeExperience = 32
|
||||
quiet = PandaSlot(0, 'quiet', int(structs.CarParams.SafetyModel.noOutput), 0, 32, False, False, False, 0)
|
||||
active = PandaSlot(1, 'owner', 15, 8, 32, True, False, False, 0)
|
||||
def receipt(slots, serial='owner', stamp=123):
|
||||
return SimpleNamespace(pandaInventory=slots, pandaSerial=serial, sourcePandaStatesMonoTime=stamp,
|
||||
safetyModel=15, safetyParam=8)
|
||||
assert native_inventory_matches_cp(receipt((quiet, active)), cp)
|
||||
for slots in ((active, quiet), (quiet,), (quiet, active, active),
|
||||
(replace(quiet, controlsAllowed=True), active),
|
||||
(replace(quiet, safetyParam=8), active),
|
||||
(replace(quiet, hardwareSerial='owner'), active),
|
||||
(quiet, replace(active, heartbeatLost=True)),
|
||||
(quiet, replace(active, safetyRxChecksInvalid=True))):
|
||||
assert not native_inventory_matches_cp(receipt(slots), cp)
|
||||
assert not native_inventory_matches_cp(receipt((quiet, active), serial='quiet'), cp)
|
||||
assert not native_inventory_matches_cp(receipt((quiet, active), stamp=0), cp)
|
||||
assert not native_inventory_matches_cp(receipt((), stamp=0), cp)
|
||||
@@ -110,7 +110,7 @@ def test_gateway_long_profile_rejects_changed_identity_bus_and_safety_context(ma
|
||||
changes = (
|
||||
('passive', True), ('notCar', True), ('dashcamOnly', True), ('flags', 1 << 20),
|
||||
('networkLocation', structs.CarParams.NetworkLocation.fwdCamera),
|
||||
('fingerprintSource', structs.CarParams.FingerprintSource.fixed),
|
||||
('brand', 'toyota'),
|
||||
('transmissionType', structs.CarParams.TransmissionType.direct),
|
||||
('steerControlType', structs.CarParams.SteerControlType.angle),
|
||||
('openpilotLongitudinalControl', False), ('pcmCruise', True),
|
||||
@@ -126,7 +126,8 @@ def test_gateway_long_profile_rejects_changed_identity_bus_and_safety_context(ma
|
||||
altered.safetyConfigs[0].safetyParam = word
|
||||
assert not long_qualified(altered)
|
||||
altered = structs.CarParams(**cp.to_dict())
|
||||
altered.safetyConfigs = [structs.CarParams.SafetyConfig(safetyModel=structs.CarParams.SafetyModel.noOutput), *altered.safetyConfigs]
|
||||
altered.safetyConfigs = [structs.CarParams.SafetyConfig(safetyModel=structs.CarParams.SafetyModel.noOutput, safetyParam=1),
|
||||
*altered.safetyConfigs]
|
||||
assert not long_qualified(altered)
|
||||
altered = structs.CarParams(**cp.to_dict())
|
||||
altered.safetyConfigs[0].safetyModel = structs.CarParams.SafetyModel.volkswagenMeb
|
||||
|
||||
@@ -86,6 +86,10 @@ def native_matches_cp(CP, model: int, param: int) -> bool:
|
||||
config = honda.aol_safety_config(CP)
|
||||
return bool(config is not None and honda.native_accepts_cp(CP, model, param) and
|
||||
model == int(config.safetyModel.raw) and param == int(config.safetyParam))
|
||||
if CP.brand == 'volkswagen':
|
||||
config = volkswagen.aol_safety_config(CP)
|
||||
return bool(config is not None and volkswagen.native_accepts_cp(CP, model, param) and
|
||||
model == int(config.safetyModel.raw) and param == int(config.safetyParam))
|
||||
return bool(any(port.native_accepts_cp(CP, model, param) for port in _PORTS.values()) and
|
||||
model == int(CP.safetyConfigs[0].safetyModel.raw) and
|
||||
param == int(CP.safetyConfigs[-1].safetyParam))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from opendbc.car import structs
|
||||
from opendbc.car.volkswagen.stock_aol import qualified as stock_qualified, AOL_WORD, MANUAL_WORD, AOL_WORDS
|
||||
from opendbc.car.volkswagen.stock_aol import qualified as stock_qualified, safety_config as aol_safety_config, AOL_WORD, MANUAL_WORD, AOL_WORDS
|
||||
from opendbc.car.volkswagen.long_aol import qualified as long_qualified, WORDS as LONG_WORDS
|
||||
from openpilot.starpilot.aol.intent import AolCardIntent, AOL_TOGGLE, ButtonType
|
||||
from openpilot.starpilot.aol.policy import AolVehiclePolicy
|
||||
@@ -31,7 +31,7 @@ def native_profile_supported(model, param):
|
||||
|
||||
|
||||
def native_accepts_cp(cp, model, param):
|
||||
return qualified(cp, marked_only=True) and native_profile_supported(model, param) and param == cp.safetyConfigs[0].safetyParam
|
||||
return qualified(cp, marked_only=True) and native_profile_supported(model, param) and param == aol_safety_config(cp).safetyParam
|
||||
|
||||
|
||||
def native_latch_rejected(cp, native):
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
{"protected_inventory_sha256": "f40dda21dcd3a36f88cb8ea563fac27b023c7766257dcf2d36027eacb2c668d4", "schema_version": 1}
|
||||
{"protected_inventory_sha256": "7ad958f6080cde1c5e80081ee1cd24927df9a703189143fcb8d15c8918cc5564", "schema_version": 1}
|
||||
|
||||
@@ -71,6 +71,9 @@ AOL_LIFECYCLE_TARGETS = (
|
||||
"openpilot/starpilot/aol/tests/test_volkswagen.py",
|
||||
"openpilot/starpilot/aol/tests/test_volkswagen_saved_intent.py",
|
||||
"openpilot/starpilot/aol/tests/test_mqb_actual_callers.py",
|
||||
"openpilot/starpilot/aol/tests/test_mqb_topology_callers.py",
|
||||
"openpilot/starpilot/aol/tests/test_mqb_topology_contract.py",
|
||||
"opendbc_repo/opendbc/car/volkswagen/tests/test_mqb_topology_discovery.py",
|
||||
"opendbc_repo/opendbc/car/volkswagen/tests/test_mqb_aol_discovery.py",
|
||||
"opendbc_repo/opendbc/safety/tests/test_volkswagen_stock_aol.py",
|
||||
"opendbc_repo/opendbc/safety/tests/test_volkswagen_engagement_arm.py",
|
||||
|
||||
Reference in New Issue
Block a user