IQ.Pilot Release Commit @ a87e9e5
This commit is contained in:
@@ -209,6 +209,8 @@ struct CarState {
|
||||
lateralAvailable @61 :Bool; # lateral control is available even if cruise is faulted
|
||||
cruiseFaultLateralMode @62 :Bool; # cruise is faulted but lateral control is still active
|
||||
radarDisableFailed @66 :Bool;
|
||||
# Physical vehicle odometer in kilometers. Zero means unavailable on this platform.
|
||||
odometer @67 :Float64;
|
||||
|
||||
# cruise state
|
||||
cruiseState @10 :CruiseState;
|
||||
|
||||
@@ -8,6 +8,10 @@ from iqdbc.car.tesla.values import DBC, CANBUS, GEAR_MAP, STEER_THRESHOLD, Tesla
|
||||
|
||||
from iqdbc.iqpilot.car.tesla.carstate_ext import CarStateExt
|
||||
from iqdbc.iqpilot.car.tesla.values import TeslaFlagsIQ
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.system.proprietary_runtime._verified_import import import_verified_module
|
||||
|
||||
vehicle_state = import_verified_module("iqpilot_alc_private", "iqpilot_private.konn3kt.iqlvbs.vehicle_state")
|
||||
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
|
||||
@@ -27,6 +31,7 @@ class CarState(CarStateBase, CarStateExt):
|
||||
self.acc_state_last = 0
|
||||
self.das_control = None
|
||||
self.das_body_controls_dat = b""
|
||||
self._odometer_store = vehicle_state.VehicleOdometerStore(CP, Params())
|
||||
self.cruise_override = False
|
||||
|
||||
def update_summon_state(self, summon_state: str, cruise_enabled: bool):
|
||||
@@ -155,6 +160,8 @@ class CarState(CarStateBase, CarStateExt):
|
||||
self.das_body_controls_dat = bytes(can_parsers[Bus.cam].dat.get(0x3E9, b""))
|
||||
|
||||
CarStateExt.update(self, ret, ret_iq, can_parsers)
|
||||
if ret.odometer > 0.0:
|
||||
ret.odometer = self._odometer_store.record(ret.odometer) or 0.0
|
||||
|
||||
return ret, ret_iq
|
||||
|
||||
|
||||
@@ -59,7 +59,10 @@ class CarInterface(CarInterfaceBase):
|
||||
if candidate == CAR.TESLA_MODEL_X:
|
||||
stock_cp.dashcamOnly = False
|
||||
|
||||
if 0x3DF in fingerprint[1]:
|
||||
# Vehicle-bus messages can be slow enough to miss the initial capture window.
|
||||
# Accept either the established 0x3DF marker or the absolute odometer frame.
|
||||
vehicle_bus_seen = any(0x3DF in bus or 0x3B6 in bus for bus in fingerprint.values())
|
||||
if vehicle_bus_seen:
|
||||
ret.flags |= TeslaFlagsIQ.HAS_VEHICLE_BUS.value
|
||||
ret.iqSafetyFlags |= TeslaSafetyFlagsIQ.HAS_VEHICLE_BUS
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from iqdbc.car.tesla.teslacan import TeslaCAN
|
||||
from iqdbc.car.tesla.radar_interface import RADAR_START_ADDR
|
||||
from iqdbc.car.tesla.carcontroller import CarController
|
||||
from iqdbc.car.tesla.values import CAR
|
||||
from iqdbc.can import CANPacker, CANParser
|
||||
|
||||
|
||||
class TestTeslaFingerprint:
|
||||
@@ -31,6 +32,19 @@ class TestTeslaCan:
|
||||
def make_can_msg(self, name, bus, values):
|
||||
return name, bus, values
|
||||
|
||||
def test_vehicle_bus_odometer_decodes_kilometers(self):
|
||||
packer = CANPacker("tesla_model3_vehicle")
|
||||
parser = CANParser("tesla_model3_vehicle", [("ID3B6UI_odometer", 1)], 1)
|
||||
|
||||
message = packer.make_can_msg("ID3B6UI_odometer", 1, {
|
||||
"UI_odometer": 29150.377,
|
||||
"UI_odometerCounter": 1,
|
||||
"UI_odometerChecksum": 0,
|
||||
})
|
||||
parser.update([1_000_000_000, [message]])
|
||||
|
||||
assert parser.vl["ID3B6UI_odometer"]["UI_odometer"] == 29150.377
|
||||
|
||||
def test_longitudinal_command_does_not_reference_missing_jerk_attr(self):
|
||||
CP = CarInterface.get_non_essential_params(CAR.TESLA_MODEL_3)
|
||||
tesla_can = TeslaCAN(CP, self.DummyPacker())
|
||||
|
||||
@@ -15,6 +15,7 @@ from iqdbc.car.volkswagen.speed_limit_manager import SpeedLimitManager
|
||||
from openpilot.system.proprietary_runtime._verified_import import import_verified_module
|
||||
|
||||
iq_lvbs_alc = import_verified_module("iqpilot_alc_private", "iqpilot_private.konn3kt.iqlvbs.alc")
|
||||
vehicle_state = import_verified_module("iqpilot_alc_private", "iqpilot_private.konn3kt.iqlvbs.vehicle_state")
|
||||
|
||||
iqpilot_path = os.path.join(os.path.dirname(__file__), '..', '..', '..')
|
||||
sys.path.insert(0, iqpilot_path)
|
||||
@@ -100,8 +101,15 @@ class CarState(CarStateBase):
|
||||
self.cruise_main_switch = False
|
||||
self.motor3_stock = {}
|
||||
self.motor1_stock = {}
|
||||
self.motor1_frame = 0
|
||||
self.motor3_frame = 0
|
||||
self.motor1_frame = 0
|
||||
self._odometer_store = vehicle_state.VehicleOdometerStore(CP, self._params)
|
||||
|
||||
def _update_odometer(self, ret: structs.CarState, raw_km: float) -> None:
|
||||
"""Publish the cluster value while proprietary Konn3kt code owns persistence."""
|
||||
odometer_km = self._odometer_store.record(raw_km)
|
||||
if odometer_km is not None:
|
||||
ret.odometer = odometer_km
|
||||
|
||||
def _apply_iq_private_flags(self, ret_iq: structs.IQCarState) -> None:
|
||||
ret_iq.alcOverrideAlert = bool(self.alcOverrideAlert)
|
||||
@@ -285,6 +293,7 @@ class CarState(CarStateBase):
|
||||
|
||||
ret.fuelGauge = pt_cp.vl["Kombi_02"]["KBI_Inhalt_Tank"] / 55.0
|
||||
ret.fuelTankLevelL = pt_cp.vl["Kombi_02"]["KBI_Inhalt_Tank"] # raw liters for konn3kt
|
||||
self._update_odometer(ret, aux_cp.vl["Kombi_02"]["KBI_Kilometerstand"])
|
||||
|
||||
self.cruise_faulted = ret.accFaulted
|
||||
self._apply_iq_private_flags(ret_iq)
|
||||
@@ -400,6 +409,7 @@ class CarState(CarStateBase):
|
||||
psd_06_values = main_cp.vl["PSD_06"] if self.CP.flags & VolkswagenFlags.STOCK_PSD_PRESENT else {}
|
||||
psd_06_values = pt_cp.vl["PSD_06"] if not psd_06_values and self.CP.flags & VolkswagenFlags.STOCK_PSD_06_PRESENT else psd_06_values
|
||||
diagnose_01_values = pt_cp.vl["Diagnose_01"] if self.CP.flags & VolkswagenFlags.STOCK_DIAGNOSE_01_PRESENT else {}
|
||||
self._update_odometer(ret, pt_cp.vl["Diagnose_01"]["KBI_Kilometerstand"])
|
||||
|
||||
if self.enable_speed_limit_predicative and not self.enable_predicative_speed_limit:
|
||||
self.enable_predicative_speed_limit = True
|
||||
@@ -631,6 +641,8 @@ class CarState(CarStateBase):
|
||||
|
||||
ret.fuelGauge = 0 # pt_cp.vl["Kombi_1"]["Tankinhalt"] / 55.0
|
||||
ret.fuelTankLevelL = 0 # pt_cp.vl["Kombi_1"]["Tankinhalt"] # raw liters for konn3kt
|
||||
if aux_cp is not None:
|
||||
self._update_odometer(ret, aux_cp.vl["Kombi_3"]["Kilometerstand"])
|
||||
|
||||
if self.CP.flags & VolkswagenFlagsIQ.IQ_PQ_ACC_FTS_EPB:
|
||||
ret.cruiseState.standstill = self.CP.pcmCruise and bool(pt_cp.vl["Bremse_5"]["BR5_Stillstand"]) and ret.cruiseState.enabled
|
||||
@@ -706,6 +718,7 @@ class CarState(CarStateBase):
|
||||
|
||||
ret.fuelGauge = br_cp.vl["Kombi_02"]["KBI_Inhalt_Tank"] / 55.0
|
||||
ret.fuelTankLevelL = br_cp.vl["Kombi_02"]["KBI_Inhalt_Tank"] # raw liters for konn3kt
|
||||
self._update_odometer(ret, br_cp.vl["Kombi_02"]["KBI_Kilometerstand"])
|
||||
|
||||
ret.buttonEvents = self.create_button_events(pt_cp, self.CCP.BUTTONS)
|
||||
|
||||
@@ -794,8 +807,11 @@ class CarState(CarStateBase):
|
||||
]
|
||||
if CP.flags & VolkswagenFlags.MLB:
|
||||
pt_messages += [
|
||||
("Blinkmodi_01", math.nan) # From J519 BCM (is inactive when no lights active, 50Hz when active)
|
||||
("Blinkmodi_01", math.nan), # From J519 BCM (is inactive when no lights active, 50Hz when active)
|
||||
("Kombi_02", math.nan), # Auxiliary-bus cluster odometer
|
||||
]
|
||||
else:
|
||||
pt_messages += [("Kombi_02", math.nan)] # Auxiliary-bus cluster odometer
|
||||
if CP.flags & VolkswagenFlags.STOCK_HCA_PRESENT:
|
||||
cam_messages += [
|
||||
("HCA_01", 1), # From R242 Driver assistance camera, 50Hz if steering/1Hz if not
|
||||
@@ -809,7 +825,7 @@ class CarState(CarStateBase):
|
||||
|
||||
@staticmethod
|
||||
def get_can_parsers_pq(CP):
|
||||
aux_messages = []
|
||||
aux_messages = [("Kombi_3", math.nan)] # Bus 1 cluster odometer
|
||||
if CP.flags & VolkswagenFlagsIQ.IQ_PQ_ACC_FTS_EPB:
|
||||
aux_messages.append(("Motor_3", 0))
|
||||
return {
|
||||
@@ -826,6 +842,7 @@ class CarState(CarStateBase):
|
||||
# TA_01 lives on bus 0 (car ECU / OP-generated when long is active).
|
||||
# math.nan → ignore_alive=True so it never contributes to can_valid.
|
||||
("TA_01", math.nan),
|
||||
("Diagnose_01", math.nan), # Bus 0 cluster odometer
|
||||
]
|
||||
if CP.networkLocation == NetworkLocation.fwdCamera:
|
||||
pt_messages.append(("AWV_03", 1))
|
||||
|
||||
@@ -397,5 +397,10 @@ BO_ 826 ID33AUI_rangeSOC: 8 VehicleBus
|
||||
BO_ 306 ID132HVBattAmpVolt: 8 VehicleBus
|
||||
SG_ BattVoltage132 : 0|16@1+ (0.01,0) [0|655.35] "V" Receiver
|
||||
|
||||
BO_ 950 ID3B6UI_odometer: 8 VehicleBus
|
||||
SG_ UI_odometer : 0|32@1+ (0.001,0) [0|4294967.295] "km" Receiver
|
||||
SG_ UI_odometerCounter : 52|4@1+ (1,0) [0|15] "" Receiver
|
||||
SG_ UI_odometerChecksum : 56|8@1+ (1,0) [0|255] "" Receiver
|
||||
|
||||
BO_ 658 ID292BMS_SOC: 8 VehicleBus
|
||||
SG_ SOCUI292 : 10|10@1+ (0.1,0) [0|102.3] "%" Receiver
|
||||
|
||||
@@ -18,9 +18,18 @@ class CarStateExt:
|
||||
self.CP_IQ = CP_IQ
|
||||
|
||||
self.infotainment_3_finger_press = 0
|
||||
self.vehicle_bus_available = bool(CP_IQ.flags & TeslaFlagsIQ.HAS_VEHICLE_BUS)
|
||||
|
||||
def update(self, ret: structs.CarState, ret_iq: structs.IQCarState, can_parsers: dict[StrEnum, CANParser]) -> None:
|
||||
if self.CP_IQ.flags & TeslaFlagsIQ.HAS_VEHICLE_BUS:
|
||||
if Bus.adas in can_parsers:
|
||||
cp_adas = can_parsers[Bus.adas]
|
||||
|
||||
odometer_km = float(cp_adas.vl["ID3B6UI_odometer"].get("UI_odometer", 0.0))
|
||||
if 0.0 < odometer_km < 4294967.296:
|
||||
self.vehicle_bus_available = True
|
||||
ret.odometer = odometer_km
|
||||
|
||||
if self.vehicle_bus_available and Bus.adas in can_parsers:
|
||||
cp_adas = can_parsers[Bus.adas]
|
||||
|
||||
prev_infotainment_3_finger_press = self.infotainment_3_finger_press
|
||||
@@ -66,7 +75,9 @@ class CarStateExt:
|
||||
def get_parser(CP: structs.CarParams, CP_IQ: structs.IQCarParams) -> dict[StrEnum, CANParser]:
|
||||
messages = {}
|
||||
|
||||
if CP_IQ.flags & TeslaFlagsIQ.HAS_VEHICLE_BUS:
|
||||
if Bus.adas in DBC[CP.carFingerprint]:
|
||||
# Parse the absolute odometer even if the initial fingerprint missed a
|
||||
# slow vehicle-bus marker. Runtime data latches support safely.
|
||||
messages[Bus.adas] = CANParser(DBC[CP.carFingerprint][Bus.adas], [], CANBUS.vehicle)
|
||||
|
||||
return messages
|
||||
|
||||
Reference in New Issue
Block a user