From e93d6dd227aebab35096c73475bb2e4edf049b78 Mon Sep 17 00:00:00 2001 From: Rick Lan Date: Thu, 18 Jun 2026 14:08:53 +0800 Subject: [PATCH] MG: add ZS (ICE) support --- opendbc_repo/opendbc/car/car.capnp | 1 + opendbc_repo/opendbc/car/docs_definitions.py | 1 + opendbc_repo/opendbc/car/mg/__init__.py | 0 opendbc_repo/opendbc/car/mg/carcontroller.py | 38 ++ opendbc_repo/opendbc/car/mg/carstate.py | 83 +++++ opendbc_repo/opendbc/car/mg/fingerprints.py | 16 + opendbc_repo/opendbc/car/mg/interface.py | 36 ++ opendbc_repo/opendbc/car/mg/mgcan.py | 29 ++ opendbc_repo/opendbc/car/mg/values.py | 82 +++++ opendbc_repo/opendbc/car/tests/routes.py | 4 + .../opendbc/car/torque_data/override.toml | 3 + opendbc_repo/opendbc/car/values.py | 3 +- opendbc_repo/opendbc/dbc/mg.dbc | 332 ++++++++++++++++++ opendbc_repo/opendbc/safety/declarations.h | 1 + opendbc_repo/opendbc/safety/modes/mg.h | 134 +++++++ opendbc_repo/opendbc/safety/safety.h | 2 + .../opendbc/safety/tests/test_alka.py | 91 +++++ opendbc_repo/opendbc/safety/tests/test_mg.py | 84 +++++ 18 files changed, 939 insertions(+), 1 deletion(-) create mode 100644 opendbc_repo/opendbc/car/mg/__init__.py create mode 100644 opendbc_repo/opendbc/car/mg/carcontroller.py create mode 100644 opendbc_repo/opendbc/car/mg/carstate.py create mode 100644 opendbc_repo/opendbc/car/mg/fingerprints.py create mode 100644 opendbc_repo/opendbc/car/mg/interface.py create mode 100644 opendbc_repo/opendbc/car/mg/mgcan.py create mode 100644 opendbc_repo/opendbc/car/mg/values.py create mode 100644 opendbc_repo/opendbc/dbc/mg.dbc create mode 100644 opendbc_repo/opendbc/safety/modes/mg.h create mode 100644 opendbc_repo/opendbc/safety/tests/test_mg.py diff --git a/opendbc_repo/opendbc/car/car.capnp b/opendbc_repo/opendbc/car/car.capnp index d2b8d758a..40ad082a1 100644 --- a/opendbc_repo/opendbc/car/car.capnp +++ b/opendbc_repo/opendbc/car/car.capnp @@ -635,6 +635,7 @@ struct CarParams { fcaGiorgio @32; rivian @33; volkswagenMeb @34; + mg @35; } enum SteerControlType { diff --git a/opendbc_repo/opendbc/car/docs_definitions.py b/opendbc_repo/opendbc/car/docs_definitions.py index 2f14a3b6a..aad4f7827 100644 --- a/opendbc_repo/opendbc/car/docs_definitions.py +++ b/opendbc_repo/opendbc/car/docs_definitions.py @@ -144,6 +144,7 @@ class CarHarness(EnumBase): tesla_a = BaseCarHarness("Tesla A connector", parts=[Accessory.harness_box, Cable.long_obdc_cable]) tesla_b = BaseCarHarness("Tesla B connector", parts=[Accessory.harness_box, Cable.long_obdc_cable]) psa_a = BaseCarHarness("PSA A connector", parts=[Accessory.harness_box, Cable.long_obdc_cable]) + mg_a = BaseCarHarness("MG A connector") class Device(EnumBase): diff --git a/opendbc_repo/opendbc/car/mg/__init__.py b/opendbc_repo/opendbc/car/mg/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/opendbc_repo/opendbc/car/mg/carcontroller.py b/opendbc_repo/opendbc/car/mg/carcontroller.py new file mode 100644 index 000000000..a9b20b130 --- /dev/null +++ b/opendbc_repo/opendbc/car/mg/carcontroller.py @@ -0,0 +1,38 @@ +from opendbc.can.packer import CANPacker +from opendbc.car import Bus +from opendbc.car.lateral import apply_driver_steer_torque_limits +from opendbc.car.interfaces import CarControllerBase +from opendbc.car.mg import mgcan +from opendbc.car.mg.values import CarControllerParams + + +class CarController(CarControllerBase): + def __init__(self, dbc_names, CP): + super().__init__(dbc_names, CP) + self.packer = CANPacker(dbc_names[Bus.pt]) + + self.apply_torque_last = 0 + + def update(self, CC, CS, now_nanos): + actuators = CC.actuators + + can_sends = [] + + # steering command + if self.frame % CarControllerParams.STEER_STEP == 0: + if CC.latActive: + # calculate steer and also set limits due to driver torque + new_torque = int(round(actuators.torque * CarControllerParams.STEER_MAX)) + apply_torque = apply_driver_steer_torque_limits(new_torque, self.apply_torque_last, CS.out.steeringTorque, CarControllerParams) + else: + apply_torque = 0 + + can_sends.append(mgcan.create_lka_steering(self.packer, (self.frame // CarControllerParams.STEER_STEP) % 16, apply_torque, CC.latActive)) + self.apply_torque_last = apply_torque + + new_actuators = actuators.as_builder() + new_actuators.torque = self.apply_torque_last / CarControllerParams.STEER_MAX + new_actuators.torqueOutputCan = self.apply_torque_last + + self.frame += 1 + return new_actuators, can_sends diff --git a/opendbc_repo/opendbc/car/mg/carstate.py b/opendbc_repo/opendbc/car/mg/carstate.py new file mode 100644 index 000000000..b4b8c5dc8 --- /dev/null +++ b/opendbc_repo/opendbc/car/mg/carstate.py @@ -0,0 +1,83 @@ +from opendbc.can.parser import CANParser +from opendbc.car import Bus, structs +from opendbc.car.interfaces import CarStateBase +from opendbc.car.mg.values import DBC, GEAR_MAP +from opendbc.car.common.conversions import Conversions as CV + +GearShifter = structs.CarState.GearShifter + + +class CarState(CarStateBase): + def __init__(self, CP): + super().__init__(CP) + + def update(self, can_parsers) -> structs.CarState: + cp = can_parsers[Bus.pt] + cp_cam = can_parsers[Bus.cam] + ret = structs.CarState() + + # Vehicle speed + ret.vEgoRaw = cp.vl["SCS_HSC2_FrP19"]["VehSpdAvgHSC2"] * CV.KPH_TO_MS + ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw) + ret.standstill = ret.vEgoRaw < 0.01 + + # Gas pedal + ret.gasPressed = cp.vl["Tester_HSC2_ECM_FrP00"]["AccelActuPosHSC2"] > 0 + + # Brake pedal + ret.brake = 0 + ret.brakePressed = cp.vl["SCS_HSC2_FrP09"]["BrkPdlDrvrAppdPrsHSC2"] > 0 + + # Steering wheel + ret.steeringAngleDeg = cp.vl["SAS_HSC2_FrP00"]["StrgWhlAngHSC2"] + ret.steeringRateDeg = cp.vl["SAS_HSC2_FrP00"]["StrgWhlAngGrdHSC2"] + ret.steeringTorque = cp.vl["EPS_HSC2_FrP03"]["DrvrStrgDlvrdToqHSC2"] + ret.steeringTorqueEps = cp.vl["EPS_HSC2_FrP03"]["ChLKARespToqHSC2"] + ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > 1.0, 5) + + ret.steerFaultTemporary = cp_cam.vl["FVCM_HSC2_FrP02"]["LDWSysFltStsHSC2"] != 0 # TODO: validate + + # Cruise state + ret.cruiseState.available = cp.vl["RADAR_HSC2_FrP00"]["ACCSysSts_RadarHSC2"] != 0 # main on (any non-Off state) + ret.cruiseState.enabled = cp.vl["RADAR_HSC2_FrP00"]["ACCSysSts_RadarHSC2"] in (2, 3) # Active, Override + ret.cruiseState.standstill = cp.vl["RADAR_HSC2_FrP00"]["ACCSysSts_RadarHSC2"] in (5, 6) # Standstill Active / Wait + ret.cruiseState.speed = cp.vl["RADAR_HSC2_FrP02"]["ACCDrvrSelTrgtSpd_RadarHSC2"] * CV.KPH_TO_MS + + ret.accFaulted = cp_cam.vl["FVCM_HSC2_FrP02"]["TJAICASysFltStsHSC2"] != 0 # TODO: validate + + # Gear + ret.gearShifter = GEAR_MAP.get(int(cp.vl["GW_HSC2_ECM_FrP04"]["TrShftLvrPos_h1HSC2"]), GearShifter.unknown) + + # Doors + ret.doorOpen = any([cp.vl["GW_HSC2_BCM_FrP04"]["DrvrDoorOpenSts_H1_Safety"], + cp.vl["GW_HSC2_BCM_FrP04"]["FrtPsngDoorOpenSts_H1_Safety"]]) + + # Blinkers + ret.leftBlinker = bool(cp.vl["GW_HSC2_BCM_FrP04"]["BlinkerLeft"]) + ret.rightBlinker = bool(cp.vl["GW_HSC2_BCM_FrP04"]["BlinkerRight"]) + + # Seatbelt + ret.seatbeltUnlatched = cp.vl["GW_HSC2_SDM_FrP00"]["DrvrSbltAtcHSC2"] != 1 + + # Blindspot + ret.leftBlindspot = cp.vl["RDA_HSC1_P02"]["LBSDAndLCAWrnng_HS"] > 0 + ret.rightBlindspot = cp.vl["RDA_HSC1_P02"]["RBSDAndLCAWrnng_HS"] > 0 + + # FCW + ret.stockFcw = cp.vl["RADAR_HSC2_FrP02"]["FCWrnngSts_RadarHSC2"] != 0 + + # AEB + ret.stockAeb = cp.vl["RADAR_HSC2_FrP02"]["AEBMsgReqHSC2"] != 0 + + # dp - ALKA: lane keep available whenever the ACC main switch is on + self.lkas_on = ret.cruiseState.available + + return ret + + @staticmethod + def get_can_parsers(CP): + return { + Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 0), + Bus.radar: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 1), + Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 2), + } diff --git a/opendbc_repo/opendbc/car/mg/fingerprints.py b/opendbc_repo/opendbc/car/mg/fingerprints.py new file mode 100644 index 000000000..e3ee93517 --- /dev/null +++ b/opendbc_repo/opendbc/car/mg/fingerprints.py @@ -0,0 +1,16 @@ +# FW query is disabled for MG for now (see values.py): the MG ZS has no captured +# FW versions yet and no CAN fingerprint, so it is identified by forced car +# selection only. Leaving FW_VERSIONS undefined keeps MG out of the FW-query path +# (get_interface_attr uses ignore_none). Restore once we can query FW on the MG ZS: +# +# from opendbc.car.structs import CarParams +# from opendbc.car.mg.values import CAR +# +# Ecu = CarParams.Ecu +# +# FW_VERSIONS = { +# CAR.MG_ZS: { +# # populate via tools/car_porting/auto_fingerprint.py once a route with FW +# # query enabled is captured on the 2025 MG ZS +# }, +# } diff --git a/opendbc_repo/opendbc/car/mg/interface.py b/opendbc_repo/opendbc/car/mg/interface.py new file mode 100644 index 000000000..1225d3570 --- /dev/null +++ b/opendbc_repo/opendbc/car/mg/interface.py @@ -0,0 +1,36 @@ +from opendbc.car import get_safety_config, structs +from opendbc.car.interfaces import CarInterfaceBase +from opendbc.car.mg.carcontroller import CarController +from opendbc.car.mg.carstate import CarState +from opendbc.car.mg.values import CAR, MgSafetyFlags + + +class CarInterface(CarInterfaceBase): + CarState = CarState + CarController = CarController + + @staticmethod + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: + ret.brand = "mg" + + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.mg)] + + if candidate == CAR.MG_ZS: + ret.safetyConfigs[0].safetyParam |= MgSafetyFlags.NON_EV.value + + ret.steerActuatorDelay = 0.3 + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + + ret.steerControlType = structs.CarParams.SteerControlType.torque + ret.radarUnavailable = True + + ret.alphaLongitudinalAvailable = False + if alpha_long: + ret.openpilotLongitudinalControl = True + ret.safetyConfigs[0].safetyParam |= MgSafetyFlags.LONG_CONTROL.value + + ret.longitudinalActuatorDelay = 0.35 + ret.vEgoStopping = 0.25 + ret.stopAccel = 0 + + return ret diff --git a/opendbc_repo/opendbc/car/mg/mgcan.py b/opendbc_repo/opendbc/car/mg/mgcan.py new file mode 100644 index 000000000..18894d3c7 --- /dev/null +++ b/opendbc_repo/opendbc/car/mg/mgcan.py @@ -0,0 +1,29 @@ +def calc_checksum(values): + lka_req_toq = values['LKAReqToqHSC2'] + 1024 + lka_req_toq_sts = values['LKAReqToqStsHSC2'] + lka_req_toq_v = values['LKAReqToqVHSC2'] + lka_alv_rc = values['LKAAlvRCHSC2'] + + combined = ((lka_req_toq << 1) | (lka_req_toq_sts << 12) | lka_req_toq_v) & 0x3FFF + with_counter = (combined + lka_alv_rc) & 0x3FFF + checksum = ((~with_counter) + 1) & 0x3FFF + + return checksum + + +def create_lka_steering(packer, counter, apply_torque, active): + + values = { + "LKAReqToqHSC2": apply_torque, + "LKAReqToqVHSC2": 0, + "LKAAlvRCHSC2": counter, + "LDWLKAVbnLvlReqHSC2": 0, # TODO: vibration level? + "LKASysStsHSC2": 0, + "LKAReqToqStsHSC2": active, + "LKASysFltStsHSC2": 0, + "LKADrvrTkovReqHSC2": 0, + "LKAReqToqPVHSC2": 0 + } + + values["LKAReqToqPVHSC2"] = calc_checksum(values) + return packer.make_can_msg("FVCM_HSC2_FrP03", 0, values) diff --git a/opendbc_repo/opendbc/car/mg/values.py b/opendbc_repo/opendbc/car/mg/values.py new file mode 100644 index 000000000..16523bbb3 --- /dev/null +++ b/opendbc_repo/opendbc/car/mg/values.py @@ -0,0 +1,82 @@ +from dataclasses import dataclass, field +from enum import IntFlag + +from opendbc.car import Bus, CarSpecs, DbcDict, PlatformConfig, Platforms, structs +from opendbc.car.docs_definitions import CarHarness, CarDocs, CarParts +# FW query disabled for MG for now (see below) - restore when we can query FW on the MG ZS +# from opendbc.car import uds +# from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16 + + +@dataclass +class MgCarDocs(CarDocs): + package: str = "All" + car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.mg_a])) + + +@dataclass +class MgPlatformConfig(PlatformConfig): + dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: 'mg', Bus.radar: 'mg'}) + + +class CAR(Platforms): + MG_ZS = MgPlatformConfig( + [ + MgCarDocs("MG ZS 2025"), + ], + CarSpecs(mass=1295., wheelbase=2.58, steerRatio=15.8), + ) + + +# FW query is disabled for MG for now: the MG ZS has no captured FW versions yet +# and no CAN fingerprint, so it is identified by forced car selection only. +# Defining FW_QUERY_CONFIG would put MG in the FW-query path with zero ECUs, which +# crashes fingerprinting and fails the fingerprint tests. Restore this (and +# FW_VERSIONS in fingerprints.py) once we figure out how to query FW on the MG ZS. +# +# MG_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ +# p16(0xf1a0) +# MG_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) +# +# FW_QUERY_CONFIG = FwQueryConfig( +# requests=[ +# Request( +# [StdQueries.TESTER_PRESENT_REQUEST, StdQueries.MANUFACTURER_ECU_HARDWARE_NUMBER_REQUEST], +# [StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.MANUFACTURER_ECU_HARDWARE_NUMBER_RESPONSE], +# bus=1, +# ), +# ], +# ) + +GEAR_MAP = { + 0: structs.CarState.GearShifter.unknown, + 1: structs.CarState.GearShifter.park, + 2: structs.CarState.GearShifter.reverse, + 3: structs.CarState.GearShifter.neutral, + 4: structs.CarState.GearShifter.drive, +} + + +class CarControllerParams: + STEER_STEP = 2 # FVCM_HSC2_FrP03 message frequency 50Hz + STEER_MAX = 300 + STEER_DELTA_UP = 10 # torque increase per refresh + STEER_DELTA_DOWN = 15 # torque decrease per refresh + STEER_DRIVER_ALLOWANCE = 100 # allowed driver torque before start limiting + STEER_DRIVER_MULTIPLIER = 2 # weight driver torque + STEER_DRIVER_FACTOR = 100 + + ACCEL_MIN = -3.5 # m/s^2 + ACCEL_MAX = 2.0 # m/s^2 + + def __init__(self, CP): + pass + + +class MgSafetyFlags(IntFlag): + LONG_CONTROL = 1 + ALT_BRAKE = 2 + NON_EV = 4 + + +DBC = CAR.create_dbc_map() diff --git a/opendbc_repo/opendbc/car/tests/routes.py b/opendbc_repo/opendbc/car/tests/routes.py index ca8a21ffa..0f9f9ab84 100644 --- a/opendbc_repo/opendbc/car/tests/routes.py +++ b/opendbc_repo/opendbc/car/tests/routes.py @@ -16,6 +16,7 @@ from opendbc.car.values import Platform from opendbc.car.volkswagen.values import CAR as VOLKSWAGEN from opendbc.car.body.values import CAR as COMMA from opendbc.car.psa.values import CAR as PSA +from opendbc.car.mg.values import CAR as MG # FIXME: add routes for these cars non_tested_cars = [ @@ -34,6 +35,9 @@ non_tested_cars = [ TOYOTA.TOYOTA_COROLLA, TOYOTA.TOYOTA_RAV4H, + # MG: no verified routes in this repo yet + MG.MG_ZS, + ] diff --git a/opendbc_repo/opendbc/car/torque_data/override.toml b/opendbc_repo/opendbc/car/torque_data/override.toml index f6bab7603..15b85e057 100644 --- a/opendbc_repo/opendbc/car/torque_data/override.toml +++ b/opendbc_repo/opendbc/car/torque_data/override.toml @@ -108,3 +108,6 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] # Manually checked "HONDA_CIVIC_2022" = [2.5, 1.2, 0.15] "HONDA_HRV_3G" = [2.5, 1.2, 0.2] + +# MG (guess) +"MG_ZS" = [1.2, 2.5, 0.18] diff --git a/opendbc_repo/opendbc/car/values.py b/opendbc_repo/opendbc/car/values.py index f606249a4..2ec22151b 100644 --- a/opendbc_repo/opendbc/car/values.py +++ b/opendbc_repo/opendbc/car/values.py @@ -6,6 +6,7 @@ from opendbc.car.gm.values import CAR as GM from opendbc.car.honda.values import CAR as HONDA from opendbc.car.hyundai.values import CAR as HYUNDAI from opendbc.car.mazda.values import CAR as MAZDA +from opendbc.car.mg.values import CAR as MG from opendbc.car.mock.values import CAR as MOCK from opendbc.car.nissan.values import CAR as NISSAN from opendbc.car.psa.values import CAR as PSA @@ -15,7 +16,7 @@ from opendbc.car.tesla.values import CAR as TESLA from opendbc.car.toyota.values import CAR as TOYOTA from opendbc.car.volkswagen.values import CAR as VOLKSWAGEN -Platform = BODY | CHRYSLER | FORD | GM | HONDA | HYUNDAI | MAZDA | MOCK | NISSAN | PSA | RIVIAN | SUBARU | TESLA | TOYOTA | VOLKSWAGEN +Platform = BODY | CHRYSLER | FORD | GM | HONDA | HYUNDAI | MAZDA | MG | MOCK | NISSAN | PSA | RIVIAN | SUBARU | TESLA | TOYOTA | VOLKSWAGEN BRANDS = get_args(Platform) PLATFORMS: dict[str, Platform] = {str(platform): platform for brand in BRANDS for platform in brand} diff --git a/opendbc_repo/opendbc/dbc/mg.dbc b/opendbc_repo/opendbc/dbc/mg.dbc new file mode 100644 index 000000000..3ef9bbc4c --- /dev/null +++ b/opendbc_repo/opendbc/dbc/mg.dbc @@ -0,0 +1,332 @@ +VERSION "HSCAN2" + + +NS_ : + NS_DESC_ + CM_ + BA_DEF_ + BA_ + VAL_ + CAT_DEF_ + CAT_ + FILTER + BA_DEF_DEF_ + EV_DATA_ + ENVVAR_DATA_ + SGTYPE_ + SGTYPE_VAL_ + BA_DEF_SGTYPE_ + BA_SGTYPE_ + SIG_TYPE_REF_ + VAL_TABLE_ + SIG_GROUP_ + SIG_VALTYPE_ + SIGTYPE_VALTYPE_ + BO_TX_BU_ + BA_DEF_REL_ + BA_REL_ + BA_DEF_DEF_REL_ + BU_SG_REL_ + BU_EV_REL_ + BU_BO_REL_ + SG_MUL_VAL_ + +BS_: + +BU_: FVCM GW Diagnostics EPS SCSABS Tester + +BO_ 175 GW_HSC2_HCU_FrP00: 8 GW + SG_ EPTAccelActuPosHSC2 : 7|8@0+ (0.392157,0) [0|100] "%" FVCM + SG_ EPTAccelActuPosVHSC2 : 43|1@0+ (1,0) [0|1] "" FVCM + SG_ EPTBrkPdlDscrtInptStsHSC2 : 31|1@0+ (1,0) [0|1] "" FVCM + SG_ EPTBrkPdlDscrtInptStsVHSC2 : 16|1@0+ (1,0) [0|1] "" FVCM + SG_ EPTStCmdOn_h1HSC2 : 17|1@0+ (1,0) [0|1] "" FVCM + +BO_ 201 Tester_HSC2_ECM_FrP00: 8 Tester + SG_ AccelActuPosHSC2 : 39|8@0+ (0.392157,0) [0|100] "%" FVCM + SG_ AccelActuPosVHSC2 : 31|1@0+ (1,0) [0|1] "" FVCM + +BO_ 251 GW_HSC2_ECM_FrP27: 8 GW + SG_ ACCStsHSC2 : 2|1@0+ (1,0) [0|1] "" XXX + SG_ SpdAstMdECMHSC2 : 52|2@0+ (1,0) [0|3] "" FVCM + SG_ SpdAstSysStsECMHSC2 : 18|3@0+ (1,0) [0|7] "" FVCM + SG_ SpdAstSysTrgtSpdHSC2 : 30|15@0+ (0.015625,0) [0|511.984] "" FVCM + SG_ TrgtSpdSrcStsHSC2 : 23|2@0+ (1,0) [0|3] "" FVCM + +BO_ 355 GW_HSC2_SDM_FrP00: 8 GW + SG_ AirbagDplHSC2 : 11|1@0+ (1,0) [0|1] "" FVCM + SG_ AirbagDplInvsnHSC2 : 10|1@0+ (1,0) [0|1] "" FVCM + SG_ DrvrSbltAtcHSC2 : 12|1@0+ (1,0) [0|1] "" FVCM + SG_ DrvrSbltAtcVHSC2 : 13|1@0+ (1,0) [0|1] "" FVCM + SG_ SDMRCHSC2 : 1|2@0+ (1,0) [0|3] "" FVCM + +BO_ 359 FVCM_HSC2_FrP02: 8 FVCM + SG_ AutoMainBeamLghtReqHSC2 : 15|2@0+ (1,0) [0|3] "" GW + SG_ DistSinceTrgtCamrHSC2 : 7|8@0+ (8.235,-100) [-100|1999.92] "m" GW + SG_ FVCMCalPrgsReqHSC2 : 36|3@0+ (1,0) [0|7] "" GW + SG_ HandOffStrgWhlDetnStaHSC2 : 44|2@0+ (1,0) [0|3] "" GW + SG_ HandOffStrgWhlDetnStaVHSC2 : 45|1@0+ (1,0) [0|1] "" GW + SG_ LDWLKADspCmdHSC2 : 50|3@0+ (1,0) [0|7] "" GW + SG_ LDWLKAHapticWrnngDspCmdHSC2 : 63|2@0+ (1,0) [0|3] "" GW + SG_ LDWLKALVsulznReqHSC2 : 53|3@0+ (1,0) [0|7] "" GW + SG_ LDWLKARVsulznReqHSC2 : 42|3@0+ (1,0) [0|7] "" GW + SG_ LDWSysFltStsHSC2 : 39|3@0+ (1,0) [0|7] "" GW + SG_ SpdAstReqStsCamrHSC2 : 13|2@0+ (1,0) [0|3] "" GW + SG_ TJAICADspCmdHSC2 : 55|2@0+ (1,0) [0|3] "" GW + SG_ TJAICASysFltStsHSC2 : 61|3@0+ (1,0) [0|7] "" GW,EPS + SG_ TJAICASysStsHSC2 : 58|3@0+ (1,0) [0|7] "" GW,EPS + SG_ TrgtSpdReqCamrHSC2 : 22|15@0+ (0.015625,0) [0|511.984] "" GW + +BO_ 404 GW_HSC2_ECM_FrP04: 8 GW + SG_ TrEstdGearHSC2 : 3|4@0+ (1,0) [0|15] "" FVCM + SG_ TrEstdGearVHSC2 : 4|1@0+ (1,0) [0|1] "" FVCM + SG_ TrShftLvrPosV_h1HSC2 : 28|1@0+ (1,0) [0|1] "" FVCM + SG_ TrShftLvrPos_h1HSC2 : 27|4@0+ (1,0) [0|15] "" FVCM + +BO_ 438 EHBS_HSC2_FrP00: 8 EHBS + SG_ BrkPdlAppdChksmHSC2 : 63|8@0+ (1,0) [0|255] "" FVCM + SG_ IbstrDiagMdAHSC2 : 55|1@0+ (1,0) [0|1] "" FVCM + SG_ RnotPrsStsHSC2 : 53|2@0+ (1,0) [0|3] "" FVCM + SG_ HydBstrCmpstnReqHSC2 : 54|1@0+ (1,0) [0|1] "" FVCM + SG_ BrkPdlAppdRCHSC2 : 51|4@0+ (1,0) [0|15] "" FVCM + SG_ RnotPrsHSC2 : 47|8@0+ (1,0) [0|250] "bar" FVCM + SG_ BrkPdlAppdHSC2 : 10|1@0+ (1,0) [0|1] "" FVCM + SG_ BrkPdlAppdVHSC2 : 9|2@0+ (1,0) [0|3] "" FVCM + +BO_ 485 SAS_HSC2_FrP00: 8 EPS + SG_ StrgWhlAngHSC2 : 15|16@0+ (0.0625,-2048) [-2048|2047.88] "degree" FVCM + SG_ StrgWhlAngAlvRCHSC2 : 31|4@0+ (1,0) [0|15] "" FVCM + SG_ StrgWhlAngExtdPVHSC2 : 47|16@0+ (1,0) [0|65535] "" FVCM + SG_ StrgWhlAngGrdHSC2 : 27|12@0+ (1,-2048) [-2048|2046] "degree/s" FVCM + SG_ StrgWhlAngSnsrCalStsHSC2 : 6|2@0+ (1,0) [0|3] "" FVCM + SG_ StrgWhlAngSnsrChksmHSC2 : 63|8@0+ (1,0) [0|255] "" FVCM + SG_ StrgWhlAngSnsrFltHSC2 : 0|1@0+ (1,0) [0|1] "" FVCM + SG_ StrgWhlAngSnsrInidHSC2 : 2|1@0+ (1,0) [0|1] "" FVCM + SG_ StrgWhlAngSnsrMultCapbHSC2 : 1|1@0+ (1,0) [0|1] "" FVCM + SG_ StrgWhlAngVHSC2 : 7|1@0+ (1,0) [0|1] "" FVCM + +BO_ 481 GW_HSC2_FrP04: 7 GW + SG_ CCSwStsSwDataIntgty_h2HSC2 : 1|2@0+ (1,0) [0|3] "" FDR + SG_ CCSwStsSpdDecSwA_h2HSC2 : 2|1@0+ (1,0) [0|1] "" FDR + SG_ CCSwStsSpdIncSwA_h2HSC2 : 3|1@0+ (1,0) [0|1] "" FDR + SG_ CCSwStsSetSwA_h2HSC2 : 4|1@0+ (1,0) [0|1] "" FDR + SG_ CCSwStsRsmSwA_h2HSC2 : 5|1@0+ (1,0) [0|1] "" FDR + SG_ CCSwStsOnSwA_h2HSC2 : 6|1@0+ (1,0) [0|1] "" FDR + SG_ CCSwStsCanclSwA_h2HSC2 : 7|1@0+ (1,0) [0|1] "" FDR + SG_ CCSwStsPV_h2HSC2 : 15|8@0+ (1,0) [0|255] "" FDR + SG_ CCSwStsAlvRC_h2HSC2 : 17|2@0+ (1,0) [0|3] "" FDR + SG_ CCSwStsDistDecSwA_h2HSC2 : 18|1@0+ (1,0) [0|1] "" FDR + SG_ CCSwStsDistIncSwA_h2HSC2 : 19|1@0+ (1,0) [0|1] "" FDR + +BO_ 492 EPS_HSC2_FrP03: 8 EPS + SG_ ChLKAAlvRCHSC2 : 7|4@0+ (1,0) [0|15] "" FVCM + SG_ ChLKACtrlStsHSC2 : 54|3@0+ (1,0) [0|7] "" FVCM + SG_ ChLKARespToqHSC2 : 2|11@0+ (0.01,-10.24) [-10.24|10.23] "Nm" FVCM + SG_ ChLKARespToqPVHSC2 : 22|15@0+ (1,0) [0|32767] "" FVCM + SG_ ChLKARespToqVHSC2 : 3|1@0+ (1,0) [0|1] "" FVCM + SG_ DrvrStrgDlvrdToqHSC2 : 34|11@0+ (0.01,-10.24) [-10.24|10.23] "Nm" FVCM + SG_ DrvrStrgDlvrdToqVHSC2 : 55|1@0+ (1,0) [0|1] "" FVCM + +BO_ 509 FVCM_HSC2_FrP03: 8 FVCM + SG_ LDWLKAVbnLvlReqHSC2 : 23|2@0+ (1,0) [0|3] "" GW,EPS + SG_ LKAAlvRCHSC2 : 7|4@0+ (1,0) [0|15] "" EPS + SG_ LKADrvrTkovReqHSC2 : 46|1@0+ (1,0) [0|1] "" GW,EPS + SG_ LKAReqToqHSC2 : 2|11@0+ (1,-1024) [-1024|1023] "Nm" EPS + SG_ LKAReqToqPVHSC2 : 21|14@0+ (1,0) [0|16383] "" EPS + SG_ LKAReqToqStsHSC2 : 36|2@0+ (1,0) [0|3] "" EPS + SG_ LKAReqToqVHSC2 : 3|1@0+ (1,0) [0|1] "" EPS + SG_ LKASysFltStsHSC2 : 39|3@0+ (1,0) [0|7] "" GW,EPS + SG_ LKASysStsHSC2 : 34|3@0+ (1,0) [0|7] "" GW,EPS + +BO_ 516 RDA_HSC1_P02: 8 RDA + SG_ LBSDAndLCAWrnng_HS : 7|2@0+ (1,0) [0|3] "" FVCM + SG_ RBSDAndLCAWrnng_HS : 5|2@0+ (1,0) [0|3] "" FVCM + SG_ RDASysSta_HS : 23|5@0+ (1,0) [0|31] "" FVCM + +BO_ 532 SCS_HSC2_FrP09: 6 SCSABS + SG_ BrkPdlDrvrAppdPrsHSC2 : 15|8@0+ (75,0) [0|19125] "kPa" FVCM + SG_ BrkPdlDrvrAppdPrsAlvRCHSC2 : 2|2@0+ (1,0) [0|3] "" FVCM + SG_ BrkPdlDrvrAppdPrsVHSC2 : 0|1@0+ (1,0) [0|1] "" FVCM + +BO_ 572 SCS_HSC2_FrP19: 8 SCSABS + SG_ VehSpdAvgHSC2 : 22|15@0+ (0.015625,0) [0|511.984] "km/h" FVCM,FDR + SG_ VehSpdAvgAlvRCHSC2 : 39|4@0+ (1,0) [0|15] "" FVCM,FDR + SG_ VehSpdAvgPVHSC2 : 7|16@0+ (1,0) [0|65535] "" FVCM,FDR + SG_ VehSpdAvgVHSC2 : 23|1@0+ (1,0) [0|1] "" FVCM,FDR + +BO_ 578 RADAR_HSC2_FrP00: 8 FDR + SG_ ACCAccReqValHSC2 : 2|11@0+ (0.005,-7.22) [-7.22|3.015] "" SCSABS + SG_ ACCSysAlvRlngCtr_SCSHSC2 : 6|4@0+ (1,0) [0|15] "" SCSABS + SG_ ACCMinBrkReqStsHSC2 : 7|1@0+ (1,0) [0|1] "" SCSABS + SG_ ACCAccReqValTolMaxHSC2 : 22|7@0+ (0.025,0) [0|3.175] "" SCSABS + SG_ ACCReqBrkPrfrdHSC2 : 23|1@0+ (1,0) [0|1] "" SCSABS + SG_ ACCAccReqStsHSC2 : 29|2@0+ (1,0) [0|3] "" GW,SCSABS + SG_ ACCGoReqHSC2 : 30|1@0+ (1,0) [0|1] "" SCSABS + SG_ ACCSysFltSts_SCSHSC2 : 42|3@0+ (1,0) [0|7] "" SCSABS + SG_ ACCSysSts_RadarHSC2 : 45|3@0+ (1,0) [0|7] "" GW,SCSABS + SG_ ChACCShtdwnMdHSC2 : 47|2@0+ (1,0) [0|3] "" SCSABS + SG_ ACCAccReqValTolMinHSC2 : 54|7@0+ (0.025,0) [0|3.175] "" SCSABS + SG_ ACCSdslReq_RadarHSC2 : 55|1@0+ (1,0) [0|1] "" SCSABS + SG_ ACCSysChksm_SCSHSC2 : 63|8@0+ (1,0) [0|255] "" SCSABS + +BO_ 582 RADAR_HSC2_FrP02: 8 FDR + SG_ ACCDrvrSelTrgtSpd_RadarHSC2 : 6|15@0+ (0.015625,0) [0|511.984] "" GW + SG_ ACCObjDet_RadarHSC2 : 7|1@0+ (1,0) [0|1] "" GW + SG_ AEBMsgReqHSC2 : 19|4@0+ (1,0) [0|15] "" GW + SG_ ACCMsgReqHSC2 : 23|4@0+ (1,0) [0|15] "" GW + SG_ ACCDetObjDistLvl_RadarHSC2 : 26|3@0+ (1,0) [0|7] "" GW + SG_ ACCDrvrSeldTrgtDistLvl_RadarHSC2 : 29|3@0+ (1,0) [0|7] "" GW + SG_ ACCSysCanclReq_RadarHSC2 : 31|2@0+ (1,0) [0|3] "" GW + SG_ RdrCalPrgsReqHSC2 : 34|3@0+ (1,0) [0|7] "" GW + SG_ ACCGoNotfr_RadarHSC2 : 35|1@0+ (1,0) [0|1] "" GW + SG_ ACCSysFltSts_RadarHSC2 : 38|3@0+ (1,0) [0|7] "" GW + SG_ ACCDrvrTkovReqHSC2 : 39|1@0+ (1,0) [0|1] "" GW + SG_ FCWSysFltSts_RadarHSC2 : 42|3@0+ (1,0) [0|7] "" GW + SG_ FCWSnstvtLvl_RadarHSC2 : 45|3@0+ (1,0) [0|7] "" GW + SG_ AEBPedtrnDspCmdHSC2 : 47|2@0+ (1,0) [0|3] "" GW + SG_ FCWrnngSts_RadarHSC2 : 51|3@0+ (1,0) [0|7] "" GW + SG_ FCWDspCmd_RadarHSC2 : 53|2@0+ (1,0) [0|3] "" GW + SG_ AEBDspCmd_RadarHSC2 : 55|2@0+ (1,0) [0|3] "" GW + +BO_ 588 SCS_HSC2_FrP22: 8 SCSABS + SG_ BrkDiscTemStsHSC2 : 6|1@0+ (1,0) [0|1] "" FDR + SG_ BrkPdlDrvrAppdPrsAlvRC_RadarHSC2 : 13|2@0+ (1,0) [0|3] "" FDR + SG_ BrkPdlDrvrAppdPrsV_RadarHSC2 : 7|1@0+ (1,0) [0|1] "" FDR + SG_ BrkPdlDrvrAppdPrs_RadarHSC2 : 23|8@0+ (75,0) [0|19125] "kPa" FDR + SG_ LDrvnWhlRotlDircnHSC2 : 15|2@0+ (1,0) [0|3] "" FDR,FVCM + SG_ RDrvnWhlRotlDircnHSC2 : 2|2@0+ (1,0) [0|3] "" FDR,FVCM + SG_ WhlBrkPrsStsHSC2 : 5|1@0+ (1,0) [0|1] "" FDR + SG_ WhlGndVelDrvnChksm_RadarHSC2 : 63|8@0+ (1,0) [0|255] "" FDR + SG_ WhlGndVelDrvnRC_RadarHSC2 : 11|4@0+ (1,0) [0|15] "" FDR + SG_ WhlGndVelLDrvnV_RadarHSC2 : 3|1@0+ (1,0) [0|1] "" FDR + SG_ WhlGndVelLDrvn_RadarHSC2 : 45|14@0+ (0.03125,0) [0|511.969] "km/h" FDR + SG_ WhlGndVelRDrvnV_RadarHSC2 : 4|1@0+ (1,0) [0|1] "" FDR + SG_ WhlGndVelRDrvn_RadarHSC2 : 29|14@0+ (0.03125,0) [0|511.969] "km/h" FDR + +BO_ 593 SCS_HSC2_FrP24: 8 SCSABS + SG_ ChACCAccReqRespHSC2 : 5|3@0+ (1,0) [0|7] "" FDR + SG_ ChACCAEBAlvRlngCtr_RadarHSC2 : 20|4@0+ (1,0) [0|15] "" FDR + SG_ ChACCAEBBrkJerkReqRespHSC2 : 10|3@0+ (1,0) [0|7] "" FDR + SG_ ChACCAEBChksm_RadarHSC2 : 63|8@0+ (1,0) [0|255] "" FDR + SG_ ChACCReqFlrStsHSC2 : 15|2@0+ (1,0) [0|3] "" FDR + SG_ ChAEBDclReqRespHSC2 : 23|3@0+ (1,0) [0|7] "" FDR + SG_ ChAEBHydBrkAstReqRespHSC2 : 2|3@0+ (1,0) [0|7] "" FDR + SG_ ChAEBPrflReqRespHSC2 : 13|3@0+ (1,0) [0|7] "" FDR + SG_ VehSdslStsHSC2 : 7|2@0+ (1,0) [0|3] "" FDR + SG_ VehTrgtLongtAccHSC2 : 31|8@0+ (0.05,-7) [-7|5.75] "" FDR + +BO_ 851 SCS_HSC2_FrP15: 8 SCSABS + SG_ VehSpdAvgDrvnHSC2 : 6|15@0+ (0.015625,0) [0|511.984] "km/h" FVCM + SG_ VehSpdAvgDrvnVHSC2 : 7|1@0+ (1,0) [0|1] "" FVCM + SG_ VehSpdAvgNonDrvnHSC2 : 38|15@0+ (0.015625,0) [0|511.984] "km/h" FVCM + SG_ VehSpdAvgNonDrvnVHSC2 : 39|1@0+ (1,0) [0|1] "" FVCM + +BO_ 1130 GW_HSC2_BCM_FrP04: 8 GW + SG_ BlinkerBulbLeft : 37|1@0+ (1,0) [0|1] "" XXX + SG_ BlinkerBulbRight : 38|1@0+ (1,0) [0|1] "" XXX + SG_ BlinkerLeft : 59|1@0+ (1,0) [0|1] "" XXX + SG_ BlinkerRight : 60|1@0+ (1,0) [0|1] "" XXX + SG_ DipdBeamLghtOnHSC2 : 13|1@0+ (1,0) [0|1] "" FVCM + SG_ DircnIndLampSwStsHSC2 : 3|2@0+ (1,0) [0|3] "" FVCM + SG_ DspMeasSysHSC2 : 44|1@0+ (1,0) [0|1] "" FVCM + SG_ FrtFogLghtOnHSC2 : 14|1@0+ (1,0) [0|1] "" FVCM + SG_ FrtWiperParkPosAHSC2 : 52|1@0+ (1,0) [0|1] "" FVCM + SG_ FrtWshrPumpAHSC2 : 55|1@0+ (1,0) [0|1] "" FVCM + SG_ LDircnIndLghtFHSC2 : 10|1@0+ (1,0) [0|1] "" FVCM + SG_ LDircnIOHSC2 : 11|1@0+ (1,0) [0|1] "" FVCM + SG_ MainBeamLghtOnHSC2 : 15|1@0+ (1,0) [0|1] "" FVCM + SG_ RDircnIndLghtFHSC2 : 48|1@0+ (1,0) [0|1] "" FVCM + SG_ RDircnIOHSC2 : 9|1@0+ (1,0) [0|1] "" FVCM + SG_ RrFogLghtOnHSC2 : 8|1@0+ (1,0) [0|1] "" FVCM + SG_ VehSideLghtStsHSC2 : 57|2@0+ (1,0) [0|3] "" FVCM + SG_ DrvrDoorOpenSts_H1_Safety : 47|2@0+ (1,0) [0|3] "" xxx + SG_ FrtPsngDoorOpenSts_H1_Safety : 43|2@0+ (1,0) [0|3] "" xxx + SG_ RRDoorOpenSts_Safety : 41|2@0+ (1,0) [0|3] "" xxx + +VAL_ 355 AirbagDplInvsnHSC2 1 "No Airbag Deployed" 0 "Airbag Deployed"; +VAL_ 355 AirbagDplHSC2 1 "True" 0 "False"; +VAL_ 355 DrvrSbltAtcHSC2 1 "True" 0 "False"; +VAL_ 355 DrvrSbltAtcVHSC2 1 "Invalid" 0 "Valid"; +VAL_ 404 TrEstdGearHSC2 15 "Park Gear" 14 "Reverse Gear" 13 "Neutral Gear" 8 "Eighth Gear" 7 "Seventh Gear" 6 "Sixth Gear" 5 "Fifth Gear" 4 "Fourth Gear" 3 "Third Gear" 2 "Second Gear" 1 "First Gear" 0 "Not Supported"; +VAL_ 404 TrEstdGearVHSC2 1 "Invalid" 0 "Valid"; +VAL_ 404 TrShftLvrPos_h1HSC2 15 "Lever Position Unknown" 11 "Forward Range H" 10 "Forward Range G" 9 "Forward Range F" 8 "Forward Range E" 7 "Forward Range D" 6 "Forward Range C" 5 "Forward Range B" 4 "Forward Range A" 3 "Neutral Range" 2 "Reverse Range" 1 "Park Range" 0 "Between Ranges"; +VAL_ 404 TrShftLvrPosV_h1HSC2 1 "Invalid" 0 "Valid"; +VAL_ 438 RnotPrsStsHSC2 2 "Faulty" 1 "Normal" 0 "Init" ; +VAL_ 438 HydBstrCmpstnReqHSC2 1 "HBC active" 0 "HBC inactive" ; +VAL_ 438 BrkPdlAppdHSC2 1 "brake pedal applied" 0 "brake pedal not applied" ; +VAL_ 438 BrkPdlAppdVHSC2 2 "Faulty" 1 "Normal" 0 "Init" ; +VAL_ 481 CCSwStsSwDataIntgty_h2HSC2 3 "Illegal Range" 2 "Failure Detected" 1 "Data Invalid" 0 "Data Valid"; +VAL_ 481 CCSwStsSpdDecSwA_h2HSC2 1 "True" 0 "False"; +VAL_ 481 CCSwStsSpdIncSwA_h2HSC2 1 "True" 0 "False"; +VAL_ 481 CCSwStsSetSwA_h2HSC2 1 "True" 0 "False"; +VAL_ 481 CCSwStsRsmSwA_h2HSC2 1 "True" 0 "False"; +VAL_ 481 CCSwStsOnSwA_h2HSC2 1 "True" 0 "False"; +VAL_ 481 CCSwStsCanclSwA_h2HSC2 1 "True" 0 "False"; +VAL_ 481 CCSwStsDistDecSwA_h2HSC2 1 "True" 0 "False"; +VAL_ 481 CCSwStsDistIncSwA_h2HSC2 1 "True" 0 "False"; +VAL_ 509 LKAReqToqVHSC2 1 "Invalid" 0 "Valid"; +VAL_ 509 LDWLKAVbnLvlReqHSC2 3 "Level 3" 2 "Level 2" 1 "Level 1" 0 "no request"; +VAL_ 509 LKASysStsHSC2 3 "Override" 2 "Active" 1 "Stand by" 0 "Off"; +VAL_ 509 LKAReqToqStsHSC2 3 "reserved" 2 "reserved" 1 "torque request" 0 "no request"; +VAL_ 509 LKASysFltStsHSC2 3 "service required" 2 "system temporary unavailable" 1 "performance degradation" 0 "no error"; +VAL_ 509 LKADrvrTkovReqHSC2 1 "True" 0 "False"; +VAL_ 578 ACCMinBrkReqStsHSC2 1 "no demand" 0 "demand"; +VAL_ 578 ACCReqBrkPrfrdHSC2 1 "no demand" 0 "demand"; +VAL_ 578 ACCAccReqStsHSC2 1 "ACC Acceleration Request" 0 "No Request"; +VAL_ 578 ACCGoReqHSC2 1 "Request" 0 "No Request"; +VAL_ 578 ACCSysFltSts_SCSHSC2 7 "Reserved" 6 "Reserved" 5 "Reserved" 4 "Reserved" 3 "Service Required" 2 "System Temporary Unvailable" 1 "Performance Degradation" 0 "No Error"; +VAL_ 578 ACCSysSts_RadarHSC2 7 "Reserved" 6 "Standstill Wait" 5 "Standstill Active" 4 "Brake Only" 3 "Override" 2 "Active" 1 "Stand By" 0 "Off"; +VAL_ 578 ChACCShtdwnMdHSC2 3 "immediate off" 2 "initial" 1 "fast off" 0 "soft off"; +VAL_ 578 ACCSdslReq_RadarHSC2 1 "request" 0 "no request"; +VAL_ 582 ACCObjDet_RadarHSC2 1 "TRUE" 0 "FALSE"; +VAL_ 582 AEBMsgReqHSC2 7 "reserved" 6 "Radar Error" 5 "AEB is switched off" 4 "AEB is switched on" 3 "AEB is in error mode" 2 "Active" 1 "unable to active AEB" 0 "No display"; +VAL_ 582 ACCMsgReqHSC2 15 "Reserved" 14 "Reserved" 13 "Reserved" 12 "Reserved" 11 "Reserved" 10 "Reserved" 9 "Radar Error" 8 "depress acceleration pedal or press resume switch to go" 7 "Driver Takeover Request" 6 "ACC is switched off" 5 "ACC is switched on" 4 "ACC is in error mode" 3 "Active" 2 "ACC is cancelled" 1 "unable to active ACC" 0 "No display"; +VAL_ 582 ACCDetObjDistLvl_RadarHSC2 7 "reserved" 6 "reserved" 5 "distance level5" 4 "distance level4" 3 "distance level3" 2 "distance level2" 1 "distance level1" 0 "no gap set"; +VAL_ 582 ACCDrvrSeldTrgtDistLvl_RadarHSC2 7 "reserved" 6 "reserved" 5 "distance level5" 4 "distance level4" 3 "distance level3" 2 "distance level2" 1 "distance level1" 0 "no gap set"; +VAL_ 582 ACCSysCanclReq_RadarHSC2 3 "Reserved" 2 "ACC Condition Dissatisfy" 1 "Manual Cancel" 0 "No Cancel"; +VAL_ 582 RdrCalPrgsReqHSC2 5 "calibration failure" 4 "Calibration Finished, need Adjust" 3 "Calibration Finished, Succesful" 2 "Calibration in progress" 1 "Calibration Started" 0 "no request"; +VAL_ 582 ACCGoNotfr_RadarHSC2 1 "TRUE" 0 "FALSE"; +VAL_ 582 ACCSysFltSts_RadarHSC2 7 "Reserved" 6 "Reserved" 5 "Reserved" 4 "Reserved" 3 "Service Required" 2 "System Temporary Unvailable" 1 "Performance Degradation" 0 "No Error"; +VAL_ 582 ACCDrvrTkovReqHSC2 1 "True" 0 "False"; +VAL_ 582 FCWSysFltSts_RadarHSC2 7 "Reserved" 6 "Reserved" 5 "Reserved" 4 "Reserved" 3 "Service required" 2 "System temporary unvailable" 1 "Performance degradation" 0 "No error"; +VAL_ 582 FCWSnstvtLvl_RadarHSC2 7 "reserved" 6 "reserved" 5 "reserved" 4 "reserved" 3 "level3" 2 "level2" 1 "level1" 0 "Unavailable"; +VAL_ 582 AEBPedtrnDspCmdHSC2 3 "reserved" 2 "on" 1 "off" 0 "unavailable"; +VAL_ 582 FCWrnngSts_RadarHSC2 7 "reserved" 6 "reserved" 5 "reserved" 4 "reserved" 3 "level 3" 2 "level 2" 1 "level 1" 0 "no request"; +VAL_ 582 FCWDspCmd_RadarHSC2 3 "reserved" 2 "on" 1 "off" 0 "unavailable"; +VAL_ 582 AEBDspCmd_RadarHSC2 3 "reserved" 2 "on" 1 "off" 0 "unavailable"; +VAL_ 588 BrkDiscTemStsHSC2 1 "Temperature too high" 0 "Not high" ; +VAL_ 588 BrkPdlDrvrAppdPrsV_RadarHSC2 1 "Invalid" 0 "Valid" ; +VAL_ 588 LDrvnWhlRotlDircnHSC2 3 "Initial/Invalid" 2 "Backward" 1 "Forward" 0 "Unknown" ; +VAL_ 588 RDrvnWhlRotlDircnHSC2 3 "Initial/Invalid" 2 "Backward" 1 "Forward" 0 "Unknown" ; +VAL_ 588 WhlBrkPrsStsHSC2 1 "No brake force" 0 "Exist brake force" ; +VAL_ 588 WhlGndVelLDrvnV_RadarHSC2 1 "Invalid" 0 "Valid" ; +VAL_ 588 WhlGndVelRDrvnV_RadarHSC2 1 "Invalid" 0 "Valid" ; +VAL_ 593 ChACCAccReqRespHSC2 7 "reserved" 6 "reserved" 4 "pre-condition not satisfied" 3 "control not allowed for error" 2 "lost arbitration" 1 "request honored" 0 "no request" ; +VAL_ 593 ChACCAEBBrkJerkReqRespHSC2 7 "reserve" 6 "reserve" 4 "pre-condition not satisfied" 3 "control not allowed for error" 2 "lost arbitration" 1 "request honored" 0 "no request" ; +VAL_ 593 ChACCReqFlrStsHSC2 3 "not defined" 2 "irreversible error" 1 "reversible error" 0 "No error" ; +VAL_ 593 ChAEBDclReqRespHSC2 7 "reserved" 6 "reserved" 4 "pre-condition not satisfied" 3 "control not allowed for error" 2 "lost arbitration" 1 "request honored" 0 "no request" ; +VAL_ 593 ChAEBHydBrkAstReqRespHSC2 7 "reserve" 6 "reserve" 4 "pre-condition not satisfied" 3 "control not allowed for error" 2 "lost arbitration" 1 "request honored" 0 "no request" ; +VAL_ 593 ChAEBPrflReqRespHSC2 7 "reserve" 6 "reserve" 4 "pre-condition not satisfied" 3 "control not allowed for error" 2 "lost arbitration" 1 "request honored" 0 "no request" ; +VAL_ 593 VehSdslStsHSC2 3 "reserved" 2 "invalid (short unavailability, max 3s)" 1 "standstill" 0 "not standstill" ; +VAL_ 851 VehSpdAvgDrvnVHSC2 1 "Invalid" 0 "Valid" ; +VAL_ 851 VehSpdAvgNonDrvnVHSC2 1 "Invalid" 0 "Valid" ; +VAL_ 1130 BntOpenStsHSC2 3 "Reserved" 2 "Bonnet Switch Disconnect" 1 "Bonnet Open" 0 "Bonnet Closed" ; +VAL_ 1130 DipdBeamLghtOnHSC2 1 "True" 0 "False" ; +VAL_ 1130 DircnIndLampSwStsHSC2 3 "reserve" 2 "Right on" 1 "Left on" 0 "off" ; +VAL_ 1130 DrvrDoorOpenStsHSC2 3 "Driver Door Full Open" 2 "Driver Door Ajar" 1 "Driver Door Open(For latch switch can't detect door ajar status)" 0 "Driver Door Closed" ; +VAL_ 1130 DspMeasSysHSC2 1 "mph" 0 "kph" ; +VAL_ 1130 FrtFogLghtOnHSC2 1 "True" 0 "False" ; +VAL_ 1130 FrtPsngDoorOpenStsHSC2 3 "Front Passenger Door Full Open" 2 "Front Passenger Door Ajar" 1 "Front Passenger Open(latch switch cann¡®t detect door ajar statu" 0 "Front Passenger Door Closed" ; +VAL_ 1130 FrtWiperParkPosAHSC2 1 "True" 0 "False" ; +VAL_ 1130 FrtWshrPumpAHSC2 1 "True" 0 "False" ; +VAL_ 1130 KeyDetIndxHSC2 7 "error" 6 "key 6 is detected" 5 "key 5 is detected" 4 "key 4 is detected" 3 "key 3 is detected" 2 "key 2 is detected" 1 "key 1 is detected" 0 "non key is detected" ; +VAL_ 1130 LDircnIndLghtFHSC2 1 "True" 0 "False" ; +VAL_ 1130 LDircnIOHSC2 1 "True" 0 "False" ; +VAL_ 1130 LdspcOpenStsHSC2 3 "Reserved" 2 "Reserved" 1 "Load Space Open" 0 "Load Space Closed" ; +VAL_ 1130 MainBeamLghtOnHSC2 1 "True" 0 "False" ; +VAL_ 1130 RDircnIndLghtFHSC2 1 "True" 0 "False" ; +VAL_ 1130 RDircnIOHSC2 1 "True" 0 "False" ; +VAL_ 1130 RLDoorOpenStsHSC2 3 "Rear Left Door Full Open" 2 "Rear Left Door Ajar" 1 "Rear Left Door Open(latch switch cann't detect door ajar status" 0 "Rear Left Door Closed" ; +VAL_ 1130 RRDoorOpenStsHSC2 3 "Rear Right Door Full Open" 2 "Rear Right Door Ajar" 1 "Rear Right Door Open(latch switch cann't detect door ajar status" 0 "Rear Right Door Closed" ; +VAL_ 1130 RrFogLghtOnHSC2 1 "True" 0 "False" ; +VAL_ 1130 VehSideLghtStsHSC2 3 "All side light and license plate light on" 2 "Right side light on only" 1 "Left side light on only" 0 "No side light on " ; diff --git a/opendbc_repo/opendbc/safety/declarations.h b/opendbc_repo/opendbc/safety/declarations.h index 802b66c99..69be1baeb 100644 --- a/opendbc_repo/opendbc/safety/declarations.h +++ b/opendbc_repo/opendbc/safety/declarations.h @@ -34,6 +34,7 @@ #define SAFETY_PSA 31U #define SAFETY_RIVIAN 33U #define SAFETY_VOLKSWAGEN_MEB 34U +#define SAFETY_MG 35U #define GET_BIT(msg, b) ((bool)!!(((msg)->data[((b) / 8U)] >> ((b) % 8U)) & 0x1U)) #define GET_FLAG(value, mask) (((value) & (mask)) == (mask)) diff --git a/opendbc_repo/opendbc/safety/modes/mg.h b/opendbc_repo/opendbc/safety/modes/mg.h new file mode 100644 index 000000000..eed1eecb3 --- /dev/null +++ b/opendbc_repo/opendbc/safety/modes/mg.h @@ -0,0 +1,134 @@ +#pragma once + +#include "opendbc/safety/declarations.h" + +static bool mg_zs_ev_brake = false; +static bool mg_non_ev = false; + +static void mg_rx_hook(const CANPacket_t *msg) { + if (msg->bus == 0U) { + // Vehicle speed + if (msg->addr == 0x23cU) { + float speed = (((msg->data[2] & 0x7FU) << 8) | msg->data[3]) * 0.015625; + vehicle_moving = speed > 0.0; + UPDATE_VEHICLE_SPEED(speed * KPH_TO_MS); + } + + // Gas pressed + if (mg_non_ev) { + if (msg->addr == 0xc9U) { + gas_pressed = msg->data[4] != 0U; + } + } else { + if (msg->addr == 0xafU) { + gas_pressed = msg->data[0] != 0U; + } + } + + // Driver torque + if (msg->addr == 0x1ecU) { + int torque_driver_new = (((msg->data[4] & 0x7U) << 8) | msg->data[5]) - 1024U; + update_sample(&torque_driver, torque_driver_new); + } + + // Brake pressed + if (mg_non_ev) { + if (msg->addr == 0x214U) { + brake_pressed = msg->data[1] != 0U; + } + } else if (mg_zs_ev_brake) { + if (msg->addr == 0xafU) { + brake_pressed = GET_BIT(msg, 31U); + } + } else { + if (msg->addr == 0x1b6U) { + brake_pressed = GET_BIT(msg, 10U); + } + } + + // Cruise state + if (msg->addr == 0x242U) { + int cruise_state = (msg->data[5] & 0x38U) >> 3; + bool cruise_engaged = (cruise_state == 2) || // Active + (cruise_state == 3); // Override + pcm_cruise_check(cruise_engaged); + + // dp - ALKA: ACC main on (any non-Off state) enables lane keep without engagement + if (alka_allowed && ((alternative_experience & ALT_EXP_ALKA) != 0)) { + lkas_on = cruise_state != 0; + } + } + } +} + +static bool mg_tx_hook(const CANPacket_t *msg) { + const TorqueSteeringLimits MG_STEERING_LIMITS = { + .max_torque = 300, + .max_rate_up = 10, + .max_rate_down = 15, + .max_rt_delta = 125, + .driver_torque_multiplier = 2, + .driver_torque_allowance = 100, + .type = TorqueDriverLimited, + }; + + bool tx = true; + bool violation = false; + + // Steering control + if (msg->addr == 0x1fdU) { + int desired_torque = (((msg->data[0] & 0x7U) << 8) | msg->data[1]) - 1024U; + bool steer_req = GET_BIT(msg, 35U); + + violation |= steer_torque_cmd_checks(desired_torque, steer_req, MG_STEERING_LIMITS); + } + + if (violation) { + tx = false; + } + + return tx; +} + +#define MG_COMMON_RX_CHECKS \ + {.msg = {{0x23c, 0, 8, .frequency = 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, /* SCS_HSC2_FrP19 */ \ + {.msg = {{0x1ec, 0, 8, .frequency = 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, /* EPS_HSC2_FrP03 */ \ + {.msg = {{0x242, 0, 8, .frequency = 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, /* RADAR_HSC2_FrP00 */ + +static safety_config mg_init(uint16_t param) { + alka_allowed = true; // dp - ALKA enabled for MG + + static const CanMsg MG_TX_MSGS[] = {{0x1fd, 0, 8, .check_relay = true}}; + + static RxCheck mg_rx_checks[] = { + MG_COMMON_RX_CHECKS + {.msg = {{0xaf, 0, 8, .frequency = 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // GW_HSC2_HCU_FrP00 (gas pedal) + {.msg = {{0x1b6, 0, 8, .frequency = 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // EHBS_HSC2_FrP00 (brake pedal) + }; + + static RxCheck mg_rx_checks_non_ev[] = { + MG_COMMON_RX_CHECKS + {.msg = {{0xc9, 0, 8, .frequency = 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // Tester_HSC2_ECM_FrP00 (gas pedal) + {.msg = {{0x214, 0, 6, .frequency = 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // SCS_HSC2_FrP09 (brake pressure) + }; + + const uint16_t MG_PARAM_ALT_BRAKE = 2; + const uint16_t MG_PARAM_NON_EV = 4; + mg_zs_ev_brake = GET_FLAG(param, MG_PARAM_ALT_BRAKE); + mg_non_ev = GET_FLAG(param, MG_PARAM_NON_EV); + + safety_config ret; + SET_TX_MSGS(MG_TX_MSGS, ret); + if (mg_non_ev) { + SET_RX_CHECKS(mg_rx_checks_non_ev, ret); + } else { + SET_RX_CHECKS(mg_rx_checks, ret); + } + return ret; +} + +const safety_hooks mg_hooks = { + .init = mg_init, + .rx = mg_rx_hook, + .tx = mg_tx_hook, +}; diff --git a/opendbc_repo/opendbc/safety/safety.h b/opendbc_repo/opendbc/safety/safety.h index 411d8d5c0..5e7922c81 100644 --- a/opendbc_repo/opendbc/safety/safety.h +++ b/opendbc_repo/opendbc/safety/safety.h @@ -27,6 +27,7 @@ #include "opendbc/safety/modes/elm327.h" #include "opendbc/safety/modes/body.h" #include "opendbc/safety/modes/psa.h" +#include "opendbc/safety/modes/mg.h" #ifdef CANFD #include "opendbc/safety/modes/hyundai_canfd.h" @@ -459,6 +460,7 @@ int set_safety_hooks(uint16_t mode, uint16_t param) { {SAFETY_BODY, &body_hooks}, {SAFETY_FORD, &ford_hooks}, {SAFETY_RIVIAN, &rivian_hooks}, + {SAFETY_MG, &mg_hooks}, {SAFETY_TESLA, &tesla_hooks}, #ifdef CANFD {SAFETY_HYUNDAI_CANFD, &hyundai_canfd_hooks}, diff --git a/opendbc_repo/opendbc/safety/tests/test_alka.py b/opendbc_repo/opendbc/safety/tests/test_alka.py index 98d9f1cd1..c08c0f35a 100644 --- a/opendbc_repo/opendbc/safety/tests/test_alka.py +++ b/opendbc_repo/opendbc/safety/tests/test_alka.py @@ -858,5 +858,96 @@ class TestALKALatControlAllowed(unittest.TestCase): f"alka_flag={alka_flag}, lkas_on={lkas_on}, vehicle_moving={vehicle_moving}") +class TestALKAMG(TestALKABase): + """Test ALKA functionality for MG (MG ZS).""" + + def setUp(self): + self.packer = CANPackerSafety("mg") + self.safety = libsafety_py.libsafety + self.safety.set_safety_hooks(CarParams.SafetyModel.mg, 4) # NON_EV (MG ZS) + self.safety.init_tests() + self.safety.set_alternative_experience(ALTERNATIVE_EXPERIENCE.ALKA) + + def _speed_msg(self, speed): + values = {"VehSpdAvgHSC2": speed * 3.6} + return self.packer.make_can_msg_safety("SCS_HSC2_FrP19", 0, values) + + def _set_vehicle_moving(self, moving: bool): + speed = 10.0 if moving else 0.0 + for _ in range(6): + self._rx(self._speed_msg(speed)) + + def _torque_cmd_msg(self, torque, steer_req=1): + values = {"LKAReqToqHSC2": torque, "LKAReqToqStsHSC2": steer_req} + return self.packer.make_can_msg_safety("FVCM_HSC2_FrP03", 0, values) + + def _torque_driver_msg(self, torque): + values = {"DrvrStrgDlvrdToqHSC2": torque} + return self.packer.make_can_msg_safety("EPS_HSC2_FrP03", 0, values) + + def _acc_main_msg(self, main_on): + # ACCSysSts: 0 = Off, 1 = Stand By (main on); any non-zero = main on + values = {"ACCSysSts_RadarHSC2": 1 if main_on else 0} + return self.packer.make_can_msg_safety("RADAR_HSC2_FrP00", 0, values) + + def _set_prev_torque(self, t): + self.safety.set_desired_torque_last(t) + self.safety.set_rt_torque_last(t) + + def test_alka_allowed_for_mg(self): + """alka_allowed is set in MG safety init.""" + self.assertTrue(self.safety.get_alka_allowed()) + + def test_alka_lkas_on_from_acc_main(self): + """lkas_on tracks the ACC main state (any non-Off ACCSysSts).""" + self._rx(self._acc_main_msg(0)) + self.assertFalse(self.safety.get_lkas_on()) + + self._rx(self._acc_main_msg(1)) + self.assertTrue(self.safety.get_lkas_on()) + + self._rx(self._acc_main_msg(0)) + self.assertFalse(self.safety.get_lkas_on()) + + def test_alka_lat_control_allowed_conditions(self): + """lat_control_allowed requires ALKA flag + lkas_on + vehicle_moving.""" + self._reset_safety_hooks() + self.safety.set_controls_allowed(False) + + # No ALKA flag -> follows controls_allowed (False) + self.safety.set_alternative_experience(ALTERNATIVE_EXPERIENCE.DEFAULT) + self._rx(self._acc_main_msg(1)) + self._set_vehicle_moving(True) + self.assertFalse(self.safety.get_lat_control_allowed()) + + # ALKA flag but not moving + self.safety.set_alternative_experience(ALTERNATIVE_EXPERIENCE.ALKA) + self._set_vehicle_moving(False) + self.assertFalse(self.safety.get_lat_control_allowed()) + + # Moving but main off (lkas_on false) + self._set_vehicle_moving(True) + self._rx(self._acc_main_msg(0)) + self.assertFalse(self.safety.get_lat_control_allowed()) + + # All conditions met + self._rx(self._acc_main_msg(1)) + self._set_vehicle_moving(True) + self.assertTrue(self.safety.get_lat_control_allowed()) + + def test_alka_allows_steering_without_controls_allowed(self): + """Torque TX is allowed via ALKA even when controls_allowed=False.""" + self._reset_safety_hooks() + self.safety.set_alternative_experience(ALTERNATIVE_EXPERIENCE.ALKA) + self._rx(self._acc_main_msg(1)) + self._set_vehicle_moving(True) + self.safety.set_controls_allowed(False) + + self._set_prev_torque(0) + for _ in range(6): + self._rx(self._torque_driver_msg(0)) + self.assertTrue(self._tx(self._torque_cmd_msg(10, steer_req=1))) + + if __name__ == "__main__": unittest.main() diff --git a/opendbc_repo/opendbc/safety/tests/test_mg.py b/opendbc_repo/opendbc/safety/tests/test_mg.py new file mode 100644 index 000000000..85cce1c2b --- /dev/null +++ b/opendbc_repo/opendbc/safety/tests/test_mg.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +import unittest + +from opendbc.car.structs import CarParams +from opendbc.safety.tests.libsafety import libsafety_py +import opendbc.safety.tests.common as common +from opendbc.safety.tests.common import CANPackerSafety + + +class TestMGSafety(common.CarSafetyTest, common.DriverTorqueSteeringSafetyTest): + + TX_MSGS = [[0x1fd, 0], ] + RELAY_MALFUNCTION_ADDRS = {0: (0x1fd,)} + FWD_BLACKLISTED_ADDRS = {2: [0x1fd,]} + + MAX_RATE_UP = 10 + MAX_RATE_DOWN = 15 + MAX_TORQUE_LOOKUP = [0], [300] + MAX_RT_DELTA = 125 + + DRIVER_TORQUE_ALLOWANCE = 100 + DRIVER_TORQUE_FACTOR = 2 + + def setUp(self): + self.packer = CANPackerSafety("mg") + self.safety = libsafety_py.libsafety + self.safety.set_safety_hooks(CarParams.SafetyModel.mg, 0) + self.safety.init_tests() + + def _torque_cmd_msg(self, torque, steer_req=1): + values = {"LKAReqToqHSC2": torque, "LKAReqToqStsHSC2": steer_req} + return self.packer.make_can_msg_safety("FVCM_HSC2_FrP03", 0, values) + + def _speed_msg(self, speed): + values = {"VehSpdAvgHSC2": speed * 3.6} + return self.packer.make_can_msg_safety("SCS_HSC2_FrP19", 0, values) + + def _torque_driver_msg(self, torque): + values = {"DrvrStrgDlvrdToqHSC2": torque * 0.01} + return self.packer.make_can_msg_safety("EPS_HSC2_FrP03", 0, values) + + def _user_brake_msg(self, brake): + values = {"BrkPdlAppdHSC2": 1 if brake else 0} + return self.packer.make_can_msg_safety("EHBS_HSC2_FrP00", 0, values) + + def _user_gas_msg(self, gas): + values = {"EPTAccelActuPosHSC2": 100 if gas else 0} + return self.packer.make_can_msg_safety("GW_HSC2_HCU_FrP00", 0, values) + + def _pcm_status_msg(self, enable): + values = {"ACCSysSts_RadarHSC2": 2 if enable else 1} + return self.packer.make_can_msg_safety("RADAR_HSC2_FrP00", 0, values) + + +class TestMGAltBrakeSafety(TestMGSafety): + def setUp(self): + self.packer = CANPackerSafety("mg") + self.safety = libsafety_py.libsafety + self.safety.set_safety_hooks(CarParams.SafetyModel.mg, 2) + self.safety.init_tests() + + def _user_brake_msg(self, brake): + values = {"EPTBrkPdlDscrtInptStsHSC2": 1 if brake else 0} + return self.packer.make_can_msg_safety("GW_HSC2_HCU_FrP00", 0, values) + + +class TestMGNonEvSafety(TestMGSafety): + def setUp(self): + self.packer = CANPackerSafety("mg") + self.safety = libsafety_py.libsafety + self.safety.set_safety_hooks(CarParams.SafetyModel.mg, 4) + self.safety.init_tests() + + def _user_brake_msg(self, brake): + values = {"BrkPdlDrvrAppdPrsHSC2": 150 if brake else 0} + return self.packer.make_can_msg_safety("SCS_HSC2_FrP09", 0, values) + + def _user_gas_msg(self, gas): + values = {"AccelActuPosHSC2": 50 if gas else 0} + return self.packer.make_can_msg_safety("Tester_HSC2_ECM_FrP00", 0, values) + + +if __name__ == "__main__": + unittest.main()