from collections import defaultdict , namedtuple
from dataclasses import dataclass , field
from enum import Enum , IntFlag , StrEnum
from cereal import car
from panda . python import uds
from opendbc . can . can_define import CANDefine
from openpilot . common . conversions import Conversions as CV
from openpilot . selfdrive . car import dbc_dict , CarSpecs , DbcDict , PlatformConfig , Platforms
from openpilot . selfdrive . car . docs_definitions import CarFootnote , CarHarness , CarDocs , CarParts , Column , \
Device
from openpilot . selfdrive . car . fw_query_definitions import EcuAddrSubAddr , FwQueryConfig , Request , p16
Ecu = car . CarParams . Ecu
NetworkLocation = car . CarParams . NetworkLocation
TransmissionType = car . CarParams . TransmissionType
GearShifter = car . CarState . GearShifter
Button = namedtuple ( ' Button ' , [ ' event_type ' , ' can_addr ' , ' can_msg ' , ' values ' ] )
class CarControllerParams :
STEER_STEP = 2 # HCA_01/HCA_1 message frequency 50Hz
ACC_CONTROL_STEP = 2 # ACC_06/ACC_07/ACC_System frequency 50Hz
# Documented lateral limits: 3.00 Nm max, rate of change 5.00 Nm/sec.
# MQB vs PQ maximums are shared, but rate-of-change limited differently
# based on safety requirements driven by lateral accel testing.
STEER_MAX = 300 # Max heading control assist torque 3.00 Nm
STEER_DRIVER_MULTIPLIER = 3 # weight driver torque heavily
STEER_DRIVER_FACTOR = 1 # from dbc
STEER_TIME_MAX = 360 # Max time that EPS allows uninterrupted HCA steering control
STEER_TIME_ALERT = STEER_TIME_MAX - 10 # If mitigation fails, time to soft disengage before EPS timer expires
STEER_TIME_STUCK_TORQUE = 1.9 # EPS limits same torque to 6 seconds, reset timer 3x within that period
DEFAULT_MIN_STEER_SPEED = 0.4 # m/s, newer EPS racks fault below this speed, don't show a low speed alert
ACCEL_MAX = 2.0 # 2.0 m/s max acceleration
ACCEL_MIN = - 3.5 # 3.5 m/s max deceleration
def __init__ ( self , CP ) :
can_define = CANDefine ( DBC [ CP . carFingerprint ] [ " pt " ] )
if CP . flags & VolkswagenFlags . PQ :
self . LDW_STEP = 5 # LDW_1 message frequency 20Hz
self . ACC_HUD_STEP = 4 # ACC_GRA_Anzeige frequency 25Hz
self . STEER_DRIVER_ALLOWANCE = 80 # Driver intervention threshold 0.8 Nm
self . STEER_DELTA_UP = 6 # Max HCA reached in 1.00s (STEER_MAX / (50Hz * 1.00))
self . STEER_DELTA_DOWN = 10 # Min HCA reached in 0.60s (STEER_MAX / (50Hz * 0.60))
if CP . transmissionType == TransmissionType . automatic :
self . shifter_values = can_define . dv [ " Getriebe_1 " ] [ " Waehlhebelposition__Getriebe_1_ " ]
self . hca_status_values = can_define . dv [ " Lenkhilfe_2 " ] [ " LH2_Sta_HCA " ]
self . BUTTONS = [
Button ( car . CarState . ButtonEvent . Type . setCruise , " GRA_Neu " , " GRA_Neu_Setzen " , [ 1 ] ) ,
Button ( car . CarState . ButtonEvent . Type . resumeCruise , " GRA_Neu " , " GRA_Recall " , [ 1 ] ) ,
Button ( car . CarState . ButtonEvent . Type . accelCruise , " GRA_Neu " , " GRA_Up_kurz " , [ 1 ] ) ,
Button ( car . CarState . ButtonEvent . Type . decelCruise , " GRA_Neu " , " GRA_Down_kurz " , [ 1 ] ) ,
Button ( car . CarState . ButtonEvent . Type . cancel , " GRA_Neu " , " GRA_Abbrechen " , [ 1 ] ) ,
Button ( car . CarState . ButtonEvent . Type . gapAdjustCruise , " GRA_Neu " , " GRA_Zeitluecke " , [ 1 ] ) ,
]
self . LDW_MESSAGES = {
" none " : 0 , # Nothing to display
" laneAssistUnavail " : 1 , # "Lane Assist currently not available."
" laneAssistUnavailSysError " : 2 , # "Lane Assist system error"
" laneAssistUnavailNoSensorView " : 3 , # "Lane Assist not available. No sensor view."
" laneAssistTakeOver " : 4 , # "Lane Assist: Please Take Over Steering"
" laneAssistDeactivTrailer " : 5 , # "Lane Assist: no function with trailer"
}
else :
self . LDW_STEP = 10 # LDW_02 message frequency 10Hz
self . ACC_HUD_STEP = 6 # ACC_02 message frequency 16Hz
self . STEER_DRIVER_ALLOWANCE = 80 # Driver intervention threshold 0.8 Nm
self . STEER_DELTA_UP = 4 # Max HCA reached in 1.50s (STEER_MAX / (50Hz * 1.50))
self . STEER_DELTA_DOWN = 10 # Min HCA reached in 0.60s (STEER_MAX / (50Hz * 0.60))
if CP . transmissionType == TransmissionType . automatic :
self . shifter_values = can_define . dv [ " Getriebe_11 " ] [ " GE_Fahrstufe " ]
elif CP . transmissionType == TransmissionType . direct :
self . shifter_values = can_define . dv [ " EV_Gearshift " ] [ " GearPosition " ]
self . hca_status_values = can_define . dv [ " LH_EPS_03 " ] [ " EPS_HCA_Status " ]
self . BUTTONS = [
Button ( car . CarState . ButtonEvent . Type . setCruise , " GRA_ACC_01 " , " GRA_Tip_Setzen " , [ 1 ] ) ,
Button ( car . CarState . ButtonEvent . Type . resumeCruise , " GRA_ACC_01 " , " GRA_Tip_Wiederaufnahme " , [ 1 ] ) ,
Button ( car . CarState . ButtonEvent . Type . accelCruise , " GRA_ACC_01 " , " GRA_Tip_Hoch " , [ 1 ] ) ,
Button ( car . CarState . ButtonEvent . Type . decelCruise , " GRA_ACC_01 " , " GRA_Tip_Runter " , [ 1 ] ) ,
Button ( car . CarState . ButtonEvent . Type . cancel , " GRA_ACC_01 " , " GRA_Abbrechen " , [ 1 ] ) ,
Button ( car . CarState . ButtonEvent . Type . gapAdjustCruise , " GRA_ACC_01 " , " GRA_Verstellung_Zeitluecke " , [ 1 ] ) ,
]
self . LDW_MESSAGES = {
" none " : 0 , # Nothing to display
" laneAssistUnavailChime " : 1 , # "Lane Assist currently not available." with chime
" laneAssistUnavailNoSensorChime " : 3 , # "Lane Assist not available. No sensor view." with chime
" laneAssistTakeOverUrgent " : 4 , # "Lane Assist: Please Take Over Steering" with urgent beep
" emergencyAssistUrgent " : 6 , # "Emergency Assist: Please Take Over Steering" with urgent beep
" laneAssistTakeOverChime " : 7 , # "Lane Assist: Please Take Over Steering" with chime
" laneAssistTakeOver " : 8 , # "Lane Assist: Please Take Over Steering" silent
" emergencyAssistChangingLanes " : 9 , # "Emergency Assist: Changing lanes..." with urgent beep
" laneAssistDeactivated " : 10 , # "Lane Assist deactivated." silent with persistent icon afterward
}
class CANBUS :
pt = 0
cam = 2
class WMI ( StrEnum ) :
VOLKSWAGEN_USA_SUV = " 1V2 "
VOLKSWAGEN_USA_CAR = " 1VW "
VOLKSWAGEN_MEXICO_SUV = " 3VV "
VOLKSWAGEN_MEXICO_CAR = " 3VW "
VOLKSWAGEN_ARGENTINA = " 8AW "
VOLKSWAGEN_BRASIL = " 9BW "
SAIC_VOLKSWAGEN = " LSV "
SKODA = " TMB "
SEAT = " VSS "
AUDI_EUROPE_MPV = " WA1 "
AUDI_GERMANY_CAR = " WAU "
MAN = " WMA "
AUDI_SPORT = " WUA "
VOLKSWAGEN_COMMERCIAL = " WV1 "
VOLKSWAGEN_COMMERCIAL_BUS_VAN = " WV2 "
VOLKSWAGEN_EUROPE_SUV = " WVG "
VOLKSWAGEN_EUROPE_CAR = " WVW "
VOLKSWAGEN_GROUP_RUS = " XW8 "
class VolkswagenFlags ( IntFlag ) :
# Detected flags
STOCK_HCA_PRESENT = 1
# Static flags
PQ = 2
@dataclass
class VolkswagenMQBPlatformConfig ( PlatformConfig ) :
dbc_dict : DbcDict = field ( default_factory = lambda : dbc_dict ( ' vw_mqb_2010 ' , None ) )
# Volkswagen uses the VIN WMI and chassis code to match in the absence of the comma power
# on camera-integrated cars, as we lose too many ECUs to reliably identify the vehicle
chassis_codes : set [ str ] = field ( default_factory = set )
wmis : set [ WMI ] = field ( default_factory = set )
@dataclass
class VolkswagenPQPlatformConfig ( VolkswagenMQBPlatformConfig ) :
dbc_dict : DbcDict = field ( default_factory = lambda : dbc_dict ( ' vw_golf_mk4 ' , None ) )
def init ( self ) :
self . flags | = VolkswagenFlags . PQ
@dataclass ( frozen = True , kw_only = True )
class VolkswagenCarSpecs ( CarSpecs ) :
centerToFrontRatio : float = 0.45
steerRatio : float = 15.6
minSteerSpeed : float = CarControllerParams . DEFAULT_MIN_STEER_SPEED
class Footnote ( Enum ) :
KAMIQ = CarFootnote (
" Not including the China market Kamiq, which is based on the (currently) unsupported PQ34 platform. " ,
Column . MODEL )
PASSAT = CarFootnote (
" Refers only to the MQB-based European B8 Passat, not the NMS Passat in the USA/China/Mideast markets. " ,
Column . MODEL )
SKODA_HEATED_WINDSHIELD = CarFootnote (
" Some Škoda vehicles are equipped with heated windshields, which are known " +
" to block GPS signal needed for some comma 3X functionality. " ,
Column . MODEL )
VW_EXP_LONG = CarFootnote (
" Only available for vehicles using a gateway (J533) harness. At this time, vehicles using a camera harness " +
" are limited to using stock ACC. " ,
Column . LONGITUDINAL )
VW_MQB_A0 = CarFootnote (
" Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot " +
" in software, but doesn ' t yet have a harness available from the comma store. " ,
Column . HARDWARE )
@dataclass
class VWCarDocs ( CarDocs ) :
package : str = " Adaptive Cruise Control (ACC) & Lane Assist "
car_parts : CarParts = field ( default_factory = CarParts . common ( [ CarHarness . vw_j533 ] ) )
def init_make ( self , CP : car . CarParams ) :
self . footnotes . append ( Footnote . VW_EXP_LONG )
if " SKODA " in CP . carFingerprint :
self . footnotes . append ( Footnote . SKODA_HEATED_WINDSHIELD )
if CP . carFingerprint in ( CAR . VOLKSWAGEN_CRAFTER_MK2 , CAR . VOLKSWAGEN_TRANSPORTER_T61 ) :
self . car_parts = CarParts ( [ Device . threex_angled_mount , CarHarness . vw_j533 ] )
if abs ( CP . minSteerSpeed - CarControllerParams . DEFAULT_MIN_STEER_SPEED ) < 1e-3 :
self . min_steer_speed = 0
# Check the 7th and 8th characters of the VIN before adding a new CAR. If the
# chassis code is already listed below, don't add a new CAR, just add to the
# FW_VERSIONS for that existing CAR.
class CAR ( Platforms ) :
config : VolkswagenMQBPlatformConfig | VolkswagenPQPlatformConfig
VOLKSWAGEN_ARTEON_MK1 = VolkswagenMQBPlatformConfig (
[
VWCarDocs ( " Volkswagen Arteon 2018-23 " , video_link = " https://youtu.be/FAomFKPFlDA " ) ,
VWCarDocs ( " Volkswagen Arteon R 2020-23 " , video_link = " https://youtu.be/FAomFKPFlDA " ) ,
VWCarDocs ( " Volkswagen Arteon eHybrid 2020-23 " , video_link = " https://youtu.be/FAomFKPFlDA " ) ,
VWCarDocs ( " Volkswagen Arteon Shooting Brake 2020-23 " , video_link = " https://youtu.be/FAomFKPFlDA " ) ,
VWCarDocs ( " Volkswagen CC 2018-22 " , video_link = " https://youtu.be/FAomFKPFlDA " ) ,
] ,
VolkswagenCarSpecs ( mass = 1733 , wheelbase = 2.84 ) ,
chassis_codes = { " AN " , " 3H " } ,
wmis = { WMI . VOLKSWAGEN_EUROPE_CAR } ,
)
VOLKSWAGEN_ATLAS_MK1 = VolkswagenMQBPlatformConfig (
[
VWCarDocs ( " Volkswagen Atlas 2018-23 " ) ,
VWCarDocs ( " Volkswagen Atlas Cross Sport 2020-22 " ) ,
VWCarDocs ( " Volkswagen Teramont 2018-22 " ) ,
VWCarDocs ( " Volkswagen Teramont Cross Sport 2021-22 " ) ,
VWCarDocs ( " Volkswagen Teramont X 2021-22 " ) ,
] ,
VolkswagenCarSpecs ( mass = 2011 , wheelbase = 2.98 ) ,
chassis_codes = { " CA " } ,
wmis = { WMI . VOLKSWAGEN_USA_SUV , WMI . VOLKSWAGEN_EUROPE_SUV } ,
)
VOLKSWAGEN_CADDY_MK3 = VolkswagenPQPlatformConfig (
[
VWCarDocs ( " Volkswagen Caddy 2019 " ) ,
VWCarDocs ( " Volkswagen Caddy Maxi 2019 " ) ,
] ,
VolkswagenCarSpecs ( mass = 1613 , wheelbase = 2.6 , minSteerSpeed = 21 * CV . KPH_TO_MS ) ,
chassis_codes = { " 2K " } ,
wmis = { WMI . VOLKSWAGEN_COMMERCIAL_BUS_VAN } ,
)
VOLKSWAGEN_CRAFTER_MK2 = VolkswagenMQBPlatformConfig (
[
VWCarDocs ( " Volkswagen Crafter 2017-24 " , video_link = " https://youtu.be/4100gLeabmo " ) ,
VWCarDocs ( " Volkswagen e-Crafter 2018-24 " , video_link = " https://youtu.be/4100gLeabmo " ) ,
VWCarDocs ( " Volkswagen Grand California 2019-24 " , video_link = " https://youtu.be/4100gLeabmo " ) ,
VWCarDocs ( " MAN TGE 2017-24 " , video_link = " https://youtu.be/4100gLeabmo " ) ,
VWCarDocs ( " MAN eTGE 2020-24 " , video_link = " https://youtu.be/4100gLeabmo " ) ,
] ,
VolkswagenCarSpecs ( mass = 2100 , wheelbase = 3.64 , minSteerSpeed = 50 * CV . KPH_TO_MS ) ,
chassis_codes = { " SY " , " SZ " , " UY " , " UZ " } ,
wmis = { WMI . VOLKSWAGEN_COMMERCIAL , WMI . MAN } ,
)
VOLKSWAGEN_GOLF_MK7 = VolkswagenMQBPlatformConfig (
[
VWCarDocs ( " Volkswagen e-Golf 2014-20 " ) ,
VWCarDocs ( " Volkswagen Golf 2015-20 " , auto_resume = False ) ,
VWCarDocs ( " Volkswagen Golf Alltrack 2015-19 " , auto_resume = False ) ,
VWCarDocs ( " Volkswagen Golf GTD 2015-20 " ) ,
VWCarDocs ( " Volkswagen Golf GTE 2015-20 " ) ,
VWCarDocs ( " Volkswagen Golf GTI 2015-21 " , auto_resume = False ) ,
VWCarDocs ( " Volkswagen Golf R 2015-19 " ) ,
VWCarDocs ( " Volkswagen Golf SportsVan 2015-20 " ) ,
] ,
VolkswagenCarSpecs ( mass = 1397 , wheelbase = 2.62 ) ,
chassis_codes = { " 5G " , " AU " , " BA " , " BE " } ,
wmis = { WMI . VOLKSWAGEN_MEXICO_CAR , WMI . VOLKSWAGEN_EUROPE_CAR } ,
)
VOLKSWAGEN_JETTA_MK7 = VolkswagenMQBPlatformConfig (
[
VWCarDocs ( " Volkswagen Jetta 2018-24 " ) ,
VWCarDocs ( " Volkswagen Jetta GLI 2021-24 " ) ,
] ,
VolkswagenCarSpecs ( mass = 1328 , wheelbase = 2.71 ) ,
chassis_codes = { " BU " } ,
wmis = { WMI . VOLKSWAGEN_MEXICO_CAR , WMI . VOLKSWAGEN_EUROPE_CAR } ,
)
VOLKSWAGEN_PASSAT_MK8 = VolkswagenMQBPlatformConfig (
[
VWCarDocs ( " Volkswagen Passat 2015-22 " , footnotes = [ Footnote . PASSAT ] ) ,
VWCarDocs ( " Volkswagen Passat Alltrack 2015-22 " ) ,
VWCarDocs ( " Volkswagen Passat GTE 2015-22 " ) ,
] ,
VolkswagenCarSpecs ( mass = 1551 , wheelbase = 2.79 ) ,
chassis_codes = { " 3C " , " 3G " } ,
wmis = { WMI . VOLKSWAGEN_EUROPE_CAR } ,
)
VOLKSWAGEN_PASSAT_NMS = VolkswagenPQPlatformConfig (
[ VWCarDocs ( " Volkswagen Passat NMS 2017-22 " ) ] ,
VolkswagenCarSpecs ( mass = 1503 , wheelbase = 2.80 , minSteerSpeed = 50 * CV . KPH_TO_MS , minEnableSpeed = 20 * CV . KPH_TO_MS ) ,
chassis_codes = { " A3 " } ,
wmis = { WMI . VOLKSWAGEN_USA_CAR } ,
)
VOLKSWAGEN_POLO_MK6 = VolkswagenMQBPlatformConfig (
[
VWCarDocs ( " Volkswagen Polo 2018-23 " , footnotes = [ Footnote . VW_MQB_A0 ] ) ,
VWCarDocs ( " Volkswagen Polo GTI 2018-23 " , footnotes = [ Footnote . VW_MQB_A0 ] ) ,
] ,
VolkswagenCarSpecs ( mass = 1230 , wheelbase = 2.55 ) ,
chassis_codes = { " AW " } ,
wmis = { WMI . VOLKSWAGEN_EUROPE_CAR } ,
)
VOLKSWAGEN_SHARAN_MK2 = VolkswagenPQPlatformConfig (
[
VWCarDocs ( " Volkswagen Sharan 2018-22 " ) ,
VWCarDocs ( " SEAT Alhambra 2018-20 " ) ,
] ,
VolkswagenCarSpecs ( mass = 1639 , wheelbase = 2.92 , minSteerSpeed = 50 * CV . KPH_TO_MS ) ,
chassis_codes = { " 7N " } ,
wmis = { WMI . VOLKSWAGEN_EUROPE_CAR } ,
)
VOLKSWAGEN_TAOS_MK1 = VolkswagenMQBPlatformConfig (
[ VWCarDocs ( " Volkswagen Taos 2022-23 " ) ] ,
VolkswagenCarSpecs ( mass = 1498 , wheelbase = 2.69 ) ,
chassis_codes = { " B2 " } ,
wmis = { WMI . VOLKSWAGEN_MEXICO_SUV , WMI . VOLKSWAGEN_ARGENTINA } ,
)
VOLKSWAGEN_TCROSS_MK1 = VolkswagenMQBPlatformConfig (
[ VWCarDocs ( " Volkswagen T-Cross 2021 " , footnotes = [ Footnote . VW_MQB_A0 ] ) ] ,
VolkswagenCarSpecs ( mass = 1150 , wheelbase = 2.60 ) ,
chassis_codes = { " C1 " } ,
wmis = { WMI . VOLKSWAGEN_EUROPE_SUV } ,
)
VOLKSWAGEN_TIGUAN_MK2 = VolkswagenMQBPlatformConfig (
[
VWCarDocs ( " Volkswagen Tiguan 2018-24 " ) ,
VWCarDocs ( " Volkswagen Tiguan eHybrid 2021-23 " ) ,
] ,
VolkswagenCarSpecs ( mass = 1715 , wheelbase = 2.74 ) ,
chassis_codes = { " 5N " , " AD " , " AX " , " BW " } ,
wmis = { WMI . VOLKSWAGEN_EUROPE_SUV , WMI . VOLKSWAGEN_MEXICO_SUV } ,
)
VOLKSWAGEN_TOURAN_MK2 = VolkswagenMQBPlatformConfig (
[ VWCarDocs ( " Volkswagen Touran 2016-23 " ) ] ,
VolkswagenCarSpecs ( mass = 1516 , wheelbase = 2.79 ) ,
chassis_codes = { " 1T " } ,
wmis = { WMI . VOLKSWAGEN_EUROPE_SUV } ,
)
VOLKSWAGEN_TRANSPORTER_T61 = VolkswagenMQBPlatformConfig (
[
VWCarDocs ( " Volkswagen Caravelle 2020 " ) ,
VWCarDocs ( " Volkswagen California 2021-23 " ) ,
] ,
VolkswagenCarSpecs ( mass = 1926 , wheelbase = 3.00 , minSteerSpeed = 14.0 ) ,
chassis_codes = { " 7H " , " 7L " } ,
wmis = { WMI . VOLKSWAGEN_COMMERCIAL_BUS_VAN } ,
)
VOLKSWAGEN_TROC_MK1 = VolkswagenMQBPlatformConfig (
[ VWCarDocs ( " Volkswagen T-Roc 2018-23 " ) ] ,
VolkswagenCarSpecs ( mass = 1413 , wheelbase = 2.63 ) ,
chassis_codes = { " A1 " } ,
wmis = { WMI . VOLKSWAGEN_EUROPE_SUV } ,
)
AUDI_A3_MK3 = VolkswagenMQBPlatformConfig (
[
VWCarDocs ( " Audi A3 2014-19 " ) ,
VWCarDocs ( " Audi A3 Sportback e-tron 2017-18 " ) ,
VWCarDocs ( " Audi RS3 2018 " ) ,
VWCarDocs ( " Audi S3 2015-17 " ) ,
] ,
VolkswagenCarSpecs ( mass = 1335 , wheelbase = 2.61 ) ,
chassis_codes = { " 8V " , " FF " } ,
wmis = { WMI . AUDI_GERMANY_CAR , WMI . AUDI_SPORT } ,
)
AUDI_Q2_MK1 = VolkswagenMQBPlatformConfig (
[ VWCarDocs ( " Audi Q2 2018 " ) ] ,
VolkswagenCarSpecs ( mass = 1205 , wheelbase = 2.61 ) ,
chassis_codes = { " GA " } ,
wmis = { WMI . AUDI_GERMANY_CAR } ,
)
AUDI_Q3_MK2 = VolkswagenMQBPlatformConfig (
[ VWCarDocs ( " Audi Q3 2019-23 " ) ] ,
VolkswagenCarSpecs ( mass = 1623 , wheelbase = 2.68 ) ,
chassis_codes = { " 8U " , " F3 " , " FS " } ,
wmis = { WMI . AUDI_EUROPE_MPV , WMI . AUDI_GERMANY_CAR } ,
)
SEAT_ATECA_MK1 = VolkswagenMQBPlatformConfig (
[
VWCarDocs ( " CUPRA Ateca 2018-23 " ) ,
VWCarDocs ( " SEAT Ateca 2016-23 " ) ,
VWCarDocs ( " SEAT Leon 2014-20 " ) ,
] ,
VolkswagenCarSpecs ( mass = 1300 , wheelbase = 2.64 ) ,
chassis_codes = { " 5F " } ,
wmis = { WMI . SEAT } ,
)
SKODA_FABIA_MK4 = VolkswagenMQBPlatformConfig (
[ VWCarDocs ( " Škoda Fabia 2022-23 " , footnotes = [ Footnote . VW_MQB_A0 ] ) ] ,
VolkswagenCarSpecs ( mass = 1266 , wheelbase = 2.56 ) ,
chassis_codes = { " PJ " } ,
wmis = { WMI . SKODA } ,
)
SKODA_KAMIQ_MK1 = VolkswagenMQBPlatformConfig (
[
VWCarDocs ( " Škoda Kamiq 2021-23 " , footnotes = [ Footnote . VW_MQB_A0 , Footnote . KAMIQ ] ) ,
VWCarDocs ( " Škoda Scala 2020-23 " , footnotes = [ Footnote . VW_MQB_A0 ] ) ,
] ,
VolkswagenCarSpecs ( mass = 1230 , wheelbase = 2.66 ) ,
chassis_codes = { " NW " } ,
wmis = { WMI . SKODA } ,
)
SKODA_KAROQ_MK1 = VolkswagenMQBPlatformConfig (
[ VWCarDocs ( " Škoda Karoq 2019-23 " ) ] ,
VolkswagenCarSpecs ( mass = 1278 , wheelbase = 2.66 ) ,
chassis_codes = { " NU " } ,
wmis = { WMI . SKODA } ,
)
SKODA_KODIAQ_MK1 = VolkswagenMQBPlatformConfig (
[ VWCarDocs ( " Škoda Kodiaq 2017-23 " ) ] ,
VolkswagenCarSpecs ( mass = 1569 , wheelbase = 2.79 ) ,
chassis_codes = { " NS " } ,
wmis = { WMI . SKODA , WMI . VOLKSWAGEN_GROUP_RUS } ,
)
SKODA_OCTAVIA_MK3 = VolkswagenMQBPlatformConfig (
[
VWCarDocs ( " Škoda Octavia 2015-19 " ) ,
VWCarDocs ( " Škoda Octavia RS 2016 " ) ,
VWCarDocs ( " Škoda Octavia Scout 2017-19 " ) ,
] ,
VolkswagenCarSpecs ( mass = 1388 , wheelbase = 2.68 ) ,
chassis_codes = { " NE " } ,
wmis = { WMI . SKODA } ,
)
SKODA_SUPERB_MK3 = VolkswagenMQBPlatformConfig (
[ VWCarDocs ( " Škoda Superb 2015-22 " ) ] ,
VolkswagenCarSpecs ( mass = 1505 , wheelbase = 2.84 ) ,
chassis_codes = { " 3V " , " NP " } ,
wmis = { WMI . SKODA } ,
)
def match_fw_to_car_fuzzy ( live_fw_versions , vin , offline_fw_versions ) - > set [ str ] :
candidates = set ( )
# Compile all FW versions for each ECU
all_ecu_versions : dict [ EcuAddrSubAddr , set [ str ] ] = defaultdict ( set )
for ecus in offline_fw_versions . values ( ) :
for ecu , versions in ecus . items ( ) :
all_ecu_versions [ ecu ] | = set ( versions )
# Check the WMI and chassis code to determine the platform
wmi = vin [ : 3 ]
chassis_code = vin [ 6 : 8 ]
for platform in CAR :
valid_ecus = set ( )
for ecu in offline_fw_versions [ platform ] :
addr = ecu [ 1 : ]
if ecu [ 0 ] not in CHECK_FUZZY_ECUS :
continue
# Sanity check that live FW is in the superset of all FW, Volkswagen ECU part numbers are commonly shared
found_versions = live_fw_versions . get ( addr , [ ] )
expected_versions = all_ecu_versions [ ecu ]
if not any ( found_version in expected_versions for found_version in found_versions ) :
break
valid_ecus . add ( ecu [ 0 ] )
if valid_ecus != CHECK_FUZZY_ECUS :
continue
if wmi in platform . config . wmis and chassis_code in platform . config . chassis_codes :
candidates . add ( platform )
return { str ( c ) for c in candidates }
# These ECUs are required to match to gain a VIN match
# TODO: do we want to check camera when we add its FW?
CHECK_FUZZY_ECUS = { Ecu . fwdRadar }
# All supported cars should return FW from the engine, srs, eps, and fwdRadar. Cars
# with a manual trans won't return transmission firmware, but all other cars will.
#
# The 0xF187 SW part number query should return in the form of N[NX][NX] NNN NNN [X[X]],
# where N=number, X=letter, and the trailing two letters are optional. Performance
# tuners sometimes tamper with that field (e.g. 8V0 9C0 BB0 1 from COBB/EQT). Tampered
# ECU SW part numbers are invalid for vehicle ID and compatibility checks. Try to have
# them repaired by the tuner before including them in openpilot.
VOLKSWAGEN_VERSION_REQUEST_MULTI = bytes ( [ uds . SERVICE_TYPE . READ_DATA_BY_IDENTIFIER ] ) + \
p16 ( uds . DATA_IDENTIFIER_TYPE . VEHICLE_MANUFACTURER_SPARE_PART_NUMBER ) + \
p16 ( uds . DATA_IDENTIFIER_TYPE . VEHICLE_MANUFACTURER_ECU_SOFTWARE_VERSION_NUMBER ) + \
p16 ( uds . DATA_IDENTIFIER_TYPE . APPLICATION_DATA_IDENTIFICATION )
VOLKSWAGEN_VERSION_RESPONSE = bytes ( [ uds . SERVICE_TYPE . READ_DATA_BY_IDENTIFIER + 0x40 ] )
VOLKSWAGEN_RX_OFFSET = 0x6a
FW_QUERY_CONFIG = FwQueryConfig (
requests = [ request for bus , obd_multiplexing in [ ( 1 , True ) , ( 1 , False ) , ( 0 , False ) ] for request in [
Request (
[ VOLKSWAGEN_VERSION_REQUEST_MULTI ] ,
[ VOLKSWAGEN_VERSION_RESPONSE ] ,
whitelist_ecus = [ Ecu . srs , Ecu . eps , Ecu . fwdRadar , Ecu . fwdCamera ] ,
rx_offset = VOLKSWAGEN_RX_OFFSET ,
bus = bus ,
obd_multiplexing = obd_multiplexing ,
) ,
Request (
[ VOLKSWAGEN_VERSION_REQUEST_MULTI ] ,
[ VOLKSWAGEN_VERSION_RESPONSE ] ,
whitelist_ecus = [ Ecu . engine , Ecu . transmission ] ,
bus = bus ,
obd_multiplexing = obd_multiplexing ,
) ,
] ] ,
non_essential_ecus = { Ecu . eps : list ( CAR ) } ,
extra_ecus = [ ( Ecu . fwdCamera , 0x74f , None ) ] ,
match_fw_to_car_fuzzy = match_fw_to_car_fuzzy ,
)
DBC = CAR . create_dbc_map ( )