IQ.Pilot Release Commit @ 95cce10

This commit is contained in:
IQ.Lvbs CI [bot]
2026-07-23 18:45:58 -05:00
parent e62376d197
commit 38b686ee2f
4 changed files with 180 additions and 186 deletions

View File

@@ -293,7 +293,7 @@ class CarState(CarStateBase):
ret.fuelGauge = pt_cp.vl["Kombi_02"]["KBI_Inhalt_Tank"] / 55.0 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 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._update_odometer(ret, pt_cp.vl["Kombi_02"]["KBI_Kilometerstand"])
self.cruise_faulted = ret.accFaulted self.cruise_faulted = ret.accFaulted
self._apply_iq_private_flags(ret_iq) self._apply_iq_private_flags(ret_iq)

View File

@@ -1,94 +1,72 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
Maintainer utility: pin a new pfeiferj/mapd release tag and refresh the checked-in
binary hash. Not used at runtime.
""" """
import argparse import argparse
import os import os
import re import re
import sys
from openpilot.iqpilot.iq_maps.vendor_mapd_installer import get_file_hash
from openpilot.common.basedir import BASEDIR from openpilot.common.basedir import BASEDIR
from openpilot.iqpilot.iq_maps import VENDOR_MAPD_PATH from openpilot.iqpilot.iq_maps import VENDOR_MAPD_PATH
from openpilot.iqpilot.iq_maps.vendor_mapd_installer import (
VENDOR_RELEASE_TAG,
get_file_hash,
)
MAPD_HASH_PATH = os.path.join(BASEDIR, "iqpilot", "iq_maps", "tests", "mapd_hash") _RELEASE_SYMBOL = "VENDOR_RELEASE_TAG"
MAPD_VERSION_PATH = os.path.join(BASEDIR, "iqpilot", "iq_maps", "vendor_mapd_installer.py") _INSTALLER_SRC = os.path.join(BASEDIR, "iqpilot", "iq_maps", "vendor_mapd_installer.py")
RELEASE_SYMBOL = "VENDOR_RELEASE_TAG" _HASH_FILE = os.path.join(BASEDIR, "iqpilot", "iq_maps", "tests", "mapd_hash")
_TAG_ASSIGN = re.compile(rf'^{_RELEASE_SYMBOL}\s*=\s*["\'][^"\']*["\']', re.MULTILINE)
def update_mapd_hash(): def rewrite_pinned_tag(new_tag: str) -> bool:
mapd_hash = get_file_hash(VENDOR_MAPD_PATH) with open(_INSTALLER_SRC) as f:
src = f.read()
with open(MAPD_HASH_PATH, "w") as f: patched, count = _TAG_ASSIGN.subn(f'{_RELEASE_SYMBOL} = "{new_tag}"', src, count=1)
f.write(mapd_hash) if count != 1:
print(f"could not locate the {_RELEASE_SYMBOL} assignment in {_INSTALLER_SRC}; nothing written")
return False
print(f"Generated and updated new mapd hash to {MAPD_HASH_PATH}") with open(_INSTALLER_SRC, "w") as f:
f.write(patched)
print(f"pinned {_RELEASE_SYMBOL} -> {new_tag}")
return True
def get_current_mapd_version(path: str) -> str: def refresh_hash_file() -> None:
print("[GET CURRENT MAPD VERSION]") digest = get_file_hash(VENDOR_MAPD_PATH)
with open(path) as f: with open(_HASH_FILE, "w") as f:
for line in f: f.write(digest)
if line.strip().startswith(RELEASE_SYMBOL): print(f"wrote binary hash {digest} -> {_HASH_FILE}")
match = re.search(rf'{RELEASE_SYMBOL}\s*=\s*[\'"]([^\'"]+)[\'"]', line)
if match:
ver = match.group(1)
print(f'Current mapd version: "{ver}"')
return ver
else:
print(f"[ERROR] {RELEASE_SYMBOL} line found but no quoted value detected.")
return ""
print(f"[ERROR] {RELEASE_SYMBOL} not found in file!")
return ""
def update_mapd_version(ver: str, path: str): def main() -> int:
print("[CHANGE CURRENT MAPD VERSION]") parser = argparse.ArgumentParser(description="Pin a new mapd release tag and refresh its hash")
parser.add_argument("--new_ver", type=str, help='e.g. --new_ver "v2.1.0"')
with open(path) as f:
lines = f.readlines()
found = False
new_lines = []
for line in lines:
if not found and line.startswith(f"{RELEASE_SYMBOL} ="):
new_lines.append(f'{RELEASE_SYMBOL} = "{ver}"\n')
found = True
new_lines.extend(lines[lines.index(line) + 1:])
break
else:
new_lines.append(line)
if not found:
print(f"[ERROR] {RELEASE_SYMBOL} line not found! Aborting without writing.")
return
with open(path, "w") as f:
f.writelines(new_lines)
print(f'New mapd version: "{ver}"')
print("[DONE]")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Update mapd version and hash")
parser.add_argument("--new_ver", type=str, help="New mapd version")
args = parser.parse_args() args = parser.parse_args()
if not args.new_ver: if not args.new_ver:
print("Warning: No new mapd version provided. Use --new_ver to specify") parser.print_help()
print("Example:") print(f'\ncurrently pinned: {VENDOR_RELEASE_TAG} (unchanged)')
print(" python iqpilot/iq_maps/update_vendor_version.py --new_ver \"v1.12.0\"") return 0
print("Current mapd version and hash will not be updated! (aborted)")
exit(0)
current_ver = get_current_mapd_version(MAPD_VERSION_PATH) target = args.new_ver.strip()
new_ver = f"{args.new_ver}" if target == VENDOR_RELEASE_TAG:
if current_ver == new_ver: reply = input(f"{target} is already the pinned tag — re-run anyway? (y/N): ").strip().lower()
print(f'Proposed mapd version: "{new_ver}"') if reply != "y":
confirm = input("Proposed mapd version is the same as the current mapd version. Confirm? (y/n): ").upper().strip() print("aborted; nothing changed")
if confirm != "Y": return 0
print("Current mapd version and hash will not be updated! (aborted)")
exit(0)
update_mapd_version(new_ver, MAPD_VERSION_PATH) if not rewrite_pinned_tag(target):
update_mapd_hash() return 1
refresh_hash_file()
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -2,16 +2,15 @@
""" """
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
Installs the `mapd` binary by Jacob Pfeifer (github.com/pfeiferj/mapd) — the binary is his work. Provisions the `mapd` routing binary authored by Jacob Pfeifer (github.com/pfeiferj/mapd).
The binary itself is his work; this module only fetches, verifies and stages it on-device.
""" """
import hashlib import hashlib
import logging import logging
import os import os
import stat import stat
import time import time
import traceback
from pathlib import Path from pathlib import Path
from urllib.request import urlopen
import requests import requests
@@ -29,125 +28,144 @@ VENDOR_RELEASE_URL = f"https://github.com/pfeiferj/mapd/releases/download/{VENDO
_VERSION_PARAM = "MapdVersion" _VERSION_PARAM = "MapdVersion"
_HASH_FILE = os.path.join(BASEDIR, "iqpilot", "iq_maps", "tests", "mapd_hash") _HASH_FILE = os.path.join(BASEDIR, "iqpilot", "iq_maps", "tests", "mapd_hash")
_DOWNLOAD_TIMEOUT_S = 60 _HTTP_TIMEOUT_S = 60
_MAX_DOWNLOAD_TRIES = 5 _FETCH_ATTEMPTS = 5
_NET_PROBE_ATTEMPTS = 10
_NET_PROBE_INTERVAL_S = 2
def get_file_hash(path: str) -> str: def get_file_hash(path: str) -> str:
"""Hex SHA-256 of a file's contents.""" """Hex SHA-256 digest of a file on disk."""
digest = hashlib.sha256()
with open(path, "rb") as handle: with open(path, "rb") as handle:
return hashlib.file_digest(handle, "sha256").hexdigest() for block in iter(lambda: handle.read(1 << 20), b""):
digest.update(block)
return digest.hexdigest()
def stamp_vendor_version(version: str, params: Params | None = None) -> None: def stamp_vendor_version(version: str, params: Params | None = None) -> None:
(params or Params()).put(_VERSION_PARAM, version) (params or Params()).put(_VERSION_PARAM, version)
def _pinned_hash() -> str:
try:
with open(_HASH_FILE) as f:
return f.read().strip()
except OSError:
return ""
class VendorMapdInstaller: class VendorMapdInstaller:
def __init__(self, spinner_ref: Spinner): def __init__(self, spinner_ref: Spinner):
self._spinner = spinner_ref self._spinner = spinner_ref
self._params = Params() self._params = Params()
# --- externally consumed surface -----------------------------------------
def get_installed_version(self) -> str: def get_installed_version(self) -> str:
return str(self._params.get(_VERSION_PARAM) or "") return str(self._params.get(_VERSION_PARAM) or "")
@staticmethod @staticmethod
def ensure_directories_exist() -> None: def ensure_directories_exist() -> None:
for d in (Paths.mapd_root(), VENDOR_MAPD_BIN_DIR): for directory in (Paths.mapd_root(), VENDOR_MAPD_BIN_DIR):
os.makedirs(d, exist_ok=True) os.makedirs(directory, exist_ok=True)
def download_needed(self) -> bool:
if not os.path.exists(VENDOR_MAPD_PATH):
return True
if self.get_installed_version() != VENDOR_RELEASE_TAG:
return True
pinned = _pinned_hash()
if not pinned:
return False
try:
return get_file_hash(VENDOR_MAPD_PATH) != pinned
except OSError:
return True
def check_and_download(self) -> None: def check_and_download(self) -> None:
if self.download_needed(): if not self._binary_up_to_date():
self.fetch() self._provision()
def fetch(self) -> None:
self.ensure_directories_exist()
if self._pull_binary():
stamp_vendor_version(VENDOR_RELEASE_TAG, self._params)
def _pull_binary(self) -> bool:
scratch = Path(f"{VENDOR_MAPD_PATH}.tmp")
for attempt in range(1, _MAX_DOWNLOAD_TRIES + 1):
try:
resp = requests.get(VENDOR_RELEASE_URL, stream=True, timeout=_DOWNLOAD_TIMEOUT_S)
resp.raise_for_status()
with open(scratch, "wb") as out:
out.write(resp.content)
out.flush()
os.fsync(out.fileno())
mode = stat.S_IMODE(os.lstat(scratch).st_mode)
os.chmod(scratch, mode | stat.S_IEXEC)
scratch.replace(VENDOR_MAPD_PATH)
return True
except requests.exceptions.RequestException as e:
self._spinner.update(f"mapd download failed ({e}); retry {attempt}/{_MAX_DOWNLOAD_TRIES}")
time.sleep(0.5)
scratch.unlink(missing_ok=True)
logging.error("mapd binary download failed after %d attempts", _MAX_DOWNLOAD_TRIES)
return False
def wait_for_internet_connection(self, return_on_failure: bool = False) -> bool:
attempts = 10
for i in range(attempts + 1):
self._spinner.update(f"Waiting for internet connection... [{i}/{attempts}]")
time.sleep(2)
try:
urlopen("https://sentry.io", timeout=10)
return True
except Exception as e: # noqa: BLE001
print(f"Wait for internet failed: {e}")
if return_on_failure and i == attempts:
return False
return False
def non_prebuilt_install(self) -> None: def non_prebuilt_install(self) -> None:
sm = messaging.SubMaster(["deviceState"]) if self._on_metered_link():
if sm["deviceState"].networkMetered: self._say("Metered connection detected — offline maps engine will not download here.")
self._spinner.update("Can't proceed with mapd install since network is metered!")
time.sleep(5) time.sleep(5)
return return
try: try:
self.ensure_directories_exist() self.ensure_directories_exist()
if not self.download_needed(): if self._binary_up_to_date():
self._spinner.update("Offline maps binary is ready.") self._say("Offline maps engine already present and current.")
time.sleep(0.1) time.sleep(0.1)
return return
if self.wait_for_internet_connection(return_on_failure=True): if self._block_until_online():
self._spinner.update(f"Downloading vendor mapd [{self.get_installed_version()}] => [{VENDOR_RELEASE_TAG}].") self._say(f"Retrieving offline maps engine [{self.get_installed_version() or 'none'}] -> [{VENDOR_RELEASE_TAG}]")
time.sleep(0.1) time.sleep(0.1)
self.check_and_download() self._provision()
self._spinner.close() self._spinner.close()
except Exception: # noqa: BLE001 except Exception as exc: # noqa: BLE001
for i in range(6): self._announce_failure(exc)
self._spinner.update("Failed to download OSM maps won't work until properly downloaded!"
f"Try again manually rebooting. Boot will continue in {5 - i}s...") # --- internal ------------------------------------------------------------
time.sleep(1) def _expected_hash(self) -> str:
sentry.init(sentry.SentryProject.SELFDRIVE) try:
traceback.print_exc() with open(_HASH_FILE) as f:
sentry.capture_exception() return f.read().strip()
except OSError:
return ""
def _binary_up_to_date(self) -> bool:
if not os.path.exists(VENDOR_MAPD_PATH):
return False
if self.get_installed_version() != VENDOR_RELEASE_TAG:
return False
reference = self._expected_hash()
if not reference:
return True
try:
return get_file_hash(VENDOR_MAPD_PATH) == reference
except OSError:
return False
def _provision(self) -> None:
self.ensure_directories_exist()
if self._retrieve_binary():
stamp_vendor_version(VENDOR_RELEASE_TAG, self._params)
def _retrieve_binary(self) -> bool:
staging = Path(f"{VENDOR_MAPD_PATH}.part")
last_error: Exception | None = None
for attempt in range(1, _FETCH_ATTEMPTS + 1):
try:
with requests.get(VENDOR_RELEASE_URL, stream=True, timeout=_HTTP_TIMEOUT_S) as resp:
resp.raise_for_status()
with open(staging, "wb") as out:
for chunk in resp.iter_content(chunk_size=1 << 16):
out.write(chunk)
out.flush()
os.fsync(out.fileno())
os.chmod(staging, os.lstat(staging).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
staging.replace(VENDOR_MAPD_PATH)
return True
except requests.exceptions.RequestException as exc:
last_error = exc
self._say(f"offline maps fetch attempt {attempt}/{_FETCH_ATTEMPTS} did not complete ({exc})")
time.sleep(0.5)
staging.unlink(missing_ok=True)
logging.error("offline maps engine could not be fetched after %d attempts: %s", _FETCH_ATTEMPTS, last_error)
return False
def _on_metered_link(self) -> bool:
sm = messaging.SubMaster(["deviceState"])
return bool(sm["deviceState"].networkMetered)
def _block_until_online(self) -> bool:
for i in range(1, _NET_PROBE_ATTEMPTS + 1):
self._say(f"Waiting for a usable network connection... [{i}/{_NET_PROBE_ATTEMPTS}]")
if self._link_reachable():
return True
time.sleep(_NET_PROBE_INTERVAL_S)
return False
@staticmethod
def _link_reachable() -> bool:
try:
requests.head(VENDOR_RELEASE_URL, timeout=10, allow_redirects=True)
return True
except requests.exceptions.RequestException as exc:
logging.debug("network probe failed: %s", exc)
return False
def _announce_failure(self, exc: Exception) -> None:
for remaining in range(5, 0, -1):
self._say(f"Offline maps engine unavailable; navigation stays online-only. Boot continues in {remaining}s...")
time.sleep(1)
logging.exception("vendor mapd install failed")
sentry.init(sentry.SentryProject.SELFDRIVE)
sentry.capture_exception(exc)
def _say(self, text: str) -> None:
self._spinner.update(text)
if __name__ == "__main__": if __name__ == "__main__":
@@ -155,9 +173,9 @@ if __name__ == "__main__":
installer = VendorMapdInstaller(spinner) installer = VendorMapdInstaller(spinner)
installer.ensure_directories_exist() installer.ensure_directories_exist()
if is_prebuilt(): if is_prebuilt():
spinner.update(f"[DEBUG] Prebuilt build; no vendor mapd install required. " spinner.update(f"[DEBUG] Prebuilt build; vendor mapd install skipped. "
f"VERSION: [{VENDOR_RELEASE_TAG}], Param [{installer.get_installed_version()}]") f"target [{VENDOR_RELEASE_TAG}], param [{installer.get_installed_version()}]")
stamp_vendor_version(VENDOR_RELEASE_TAG) stamp_vendor_version(VENDOR_RELEASE_TAG)
else: else:
spinner.update(f"Checking if vendor mapd is installed and valid. Prebuilt [{is_prebuilt()}]") spinner.update(f"Verifying vendor mapd install. prebuilt [{is_prebuilt()}]")
installer.non_prebuilt_install() installer.non_prebuilt_install()

View File

@@ -26,17 +26,15 @@ SpeedLimitSource = custom.IQPlan.SpeedLimit.Source
NavProvider = custom.IQNavState.LongitudinalProvider NavProvider = custom.IQNavState.LongitudinalProvider
NavLongitudinalState = custom.IQNavState.LongitudinalState NavLongitudinalState = custom.IQNavState.LongitudinalState
class LongitudinalPlannerIQ: class LongitudinalPlannerIQ:
def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams, mpc): def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams, mpc):
self.events_iq = IQEvents() self.events_iq = IQEvents()
self.iq_dynamic = IQDynamicController(CP, mpc) self.iq_dynamic = IQDynamicController(CP, mpc)
self.custom_stop_distance = CustomStopDistance() self.custom_stop_distance = CustomStopDistance()
self.slc = SLCVCruise() self.slimit = SLCVCruise()
self.generation = int(model_bundle.generation) if (model_bundle := get_active_bundle()) else None self.generation = int(model_bundle.generation) if (model_bundle := get_active_bundle()) else None
self.source = LongitudinalPlanSource.cruise self.source = LongitudinalPlanSource.cruise
self.e2e_alerts_helper = E2EAlertsHelper() self.iqmodeloutput = E2EAlertsHelper()
self.output_v_target = 0. self.output_v_target = 0.
self.output_a_target = 0. self.output_a_target = 0.
self.speed_limit_last = 0. self.speed_limit_last = 0.
@@ -84,17 +82,17 @@ class LongitudinalPlannerIQ:
else: else:
clocks = sm.get('clocks', None) if isinstance(sm, dict) else None clocks = sm.get('clocks', None) if isinstance(sm, dict) else None
time_validated = bool(getattr(clocks, 'timeValid', False)) time_validated = bool(getattr(clocks, 'timeValid', False))
slc_v_cruise = self.slc.update(slc_apply_enabled, now, time_validated, v_cruise, v_ego, sm) slc_v_cruise = self.slimit.update(slc_apply_enabled, now, time_validated, v_cruise, v_ego, sm)
self.iq_dynamic.set_slc_experimental_mode(self.slc.slc_experimental_mode) self.iq_dynamic.set_slc_experimental_mode(self.slimit.slc_experimental_mode)
self.iq_dynamic.update(sm) self.iq_dynamic.update(sm)
# Prefer confirmed controller output for UI/planner rendering. # Prefer confirmed controller output for UI/planner rendering.
# Fall back to active (policy-resolved) target/source when confirmed is unavailable. # Fall back to active (policy-resolved) target/source when confirmed is unavailable.
display_speed_limit = self.slc.slc_target if self.slc.slc_target > 0 else self.slc.slc_active_target display_speed_limit = self.slimit.slc_target if self.slimit.slc_target > 0 else self.slimit.slc_active_target
display_source = self.slc.slc_source if self.slc.slc_source != "None" else self.slc.slc_active_source display_source = self.slimit.slc_source if self.slimit.slc_source != "None" else self.slimit.slc_active_source
if display_speed_limit > 0: if display_speed_limit > 0:
self.speed_limit_last = display_speed_limit self.speed_limit_last = display_speed_limit
self.speed_limit_final_last = display_speed_limit + self.slc.slc_offset self.speed_limit_final_last = display_speed_limit + self.slimit.slc_offset
elif display_source == "None": elif display_source == "None":
self.speed_limit_last = 0.0 self.speed_limit_last = 0.0
self.speed_limit_final_last = 0.0 self.speed_limit_final_last = 0.0
@@ -120,8 +118,8 @@ class LongitudinalPlannerIQ:
self.output_v_target, self.output_a_target = targets[self.source] self.output_v_target, self.output_a_target = targets[self.source]
self.output_v_target = self._apply_force_stop(self.output_v_target, v_ego, sm, slc_apply_enabled) self.output_v_target = self._apply_force_stop(self.output_v_target, v_ego, sm, slc_apply_enabled)
# envelope shaping only in Assist mode: info/warn must never change the plan # envelope shaping only in Assist mode: info/warn must never change the plan
self._envelope_enabled = (slc_apply_enabled and bool(getattr(self.slc, "controller_enabled", False)) self._envelope_enabled = (slc_apply_enabled and bool(getattr(self.slimit, "controller_enabled", False))
and bool(getattr(self.slc, "mode_assist", False))) and bool(getattr(self.slimit, "mode_assist", False)))
return self.output_v_target, self.output_a_target return self.output_v_target, self.output_a_target
def cruise_envelope(self, v_target: float, v_ego: float, t_idxs) -> np.ndarray: def cruise_envelope(self, v_target: float, v_ego: float, t_idxs) -> np.ndarray:
@@ -131,12 +129,12 @@ class LongitudinalPlannerIQ:
env = np.full(len(t_idxs), max(float(v_target), 0.0)) env = np.full(len(t_idxs), max(float(v_target), 0.0))
if not getattr(self, "_envelope_enabled", False): if not getattr(self, "_envelope_enabled", False):
return env return env
slc = getattr(self.slc, "slc", None) slc = getattr(self.slimit, "slc", None)
next_limit = float(getattr(slc, "next_speed_limit", 0.0) or 0.0) next_limit = float(getattr(slc, "next_speed_limit", 0.0) or 0.0)
next_dist = float(getattr(slc, "next_speed_distance", 0.0) or 0.0) next_dist = float(getattr(slc, "next_speed_distance", 0.0) or 0.0)
if next_limit <= 0.0 or next_dist <= 0.0: if next_limit <= 0.0 or next_dist <= 0.0:
return env return env
next_target = max(next_limit + float(getattr(self.slc, "slc_offset", 0.0) or 0.0), 0.0) next_target = max(next_limit + float(getattr(self.slimit, "slc_offset", 0.0) or 0.0), 0.0)
if next_target >= env[0]: if next_target >= env[0]:
return env return env
travel = np.maximum(v_ego, 1.0) * np.asarray(t_idxs) travel = np.maximum(v_ego, 1.0) * np.asarray(t_idxs)
@@ -145,10 +143,10 @@ class LongitudinalPlannerIQ:
def update(self, sm: messaging.SubMaster) -> None: def update(self, sm: messaging.SubMaster) -> None:
self.events_iq.clear() self.events_iq.clear()
for event_name in getattr(self.slc, 'pending_events', []): for event_name in getattr(self.slimit, 'pending_events', []):
self.events_iq.add(event_name) self.events_iq.add(event_name)
self.custom_stop_distance.update() self.custom_stop_distance.update()
self.e2e_alerts_helper.update(sm, self.events_iq) self.iqmodeloutput.update(sm, self.events_iq)
if bool(getattr(sm["iqCarState"], "alcOverrideAlert", False)): if bool(getattr(sm["iqCarState"], "alcOverrideAlert", False)):
self.events_iq.add(custom.IQOnroadEvent.EventName.steeringOverrideReengageAlc) self.events_iq.add(custom.IQOnroadEvent.EventName.steeringOverrideReengageAlc)
@@ -213,8 +211,8 @@ class LongitudinalPlannerIQ:
# Speed Limit # Speed Limit
speedLimit = plan_msg.speedLimit speedLimit = plan_msg.speedLimit
resolver = speedLimit.resolver resolver = speedLimit.resolver
speed_limit = float(self.slc.slc_target if self.slc.slc_target > 0 else self.slc.slc_active_target) speed_limit = float(self.slimit.slc_target if self.slimit.slc_target > 0 else self.slimit.slc_active_target)
speed_limit_offset = float(self.slc.slc_offset) speed_limit_offset = float(self.slimit.slc_offset)
speed_limit_final = speed_limit + speed_limit_offset if speed_limit > 0 else 0. speed_limit_final = speed_limit + speed_limit_offset if speed_limit > 0 else 0.
speed_limit_valid = speed_limit > 0. speed_limit_valid = speed_limit > 0.
speed_limit_last_valid = self.speed_limit_last > 0. speed_limit_last_valid = self.speed_limit_last > 0.
@@ -230,26 +228,26 @@ class LongitudinalPlannerIQ:
resolver.source = self.speed_limit_source resolver.source = self.speed_limit_source
assist = speedLimit.assist assist = speedLimit.assist
slc_assist_state = self.slc.assist_state slc_assist_state = self.slimit.assist_state
assist.enabled = bool(self.slc.slc_target > 0 or self.slc.slc_unconfirmed > 0) assist.enabled = bool(self.slimit.slc_target > 0 or self.slimit.slc_unconfirmed > 0)
assist.active = self.source == LongitudinalPlanSource.speedLimitAssist and self.slc.slc_target > 0 assist.active = self.source == LongitudinalPlanSource.speedLimitAssist and self.slimit.slc_target > 0
if slc_assist_state is not None: if slc_assist_state is not None:
assist.state = slc_assist_state assist.state = slc_assist_state
elif not assist.enabled: elif not assist.enabled:
assist.state = SpeedLimitAssistState.disabled assist.state = SpeedLimitAssistState.disabled
elif self.slc.slc_unconfirmed > 0: elif self.slimit.slc_unconfirmed > 0:
assist.state = SpeedLimitAssistState.preActive assist.state = SpeedLimitAssistState.preActive
elif assist.active: elif assist.active:
assist.state = SpeedLimitAssistState.active assist.state = SpeedLimitAssistState.active
else: else:
assist.state = SpeedLimitAssistState.inactive assist.state = SpeedLimitAssistState.inactive
assist.vTarget = float(self.output_v_target if assist.active else 255.) assist.vTarget = float(self.output_v_target if assist.active else 255.)
assist.aTarget = float(self.slc.slc_a_target if assist.active else 0.) assist.aTarget = float(self.slimit.slc_a_target if assist.active else 0.)
# E2E Alerts # E2E Alerts
e2eAlerts = plan_msg.e2eAlerts e2eAlerts = plan_msg.e2eAlerts
e2eAlerts.greenLightAlert = self.e2e_alerts_helper.queue_alert e2eAlerts.greenLightAlert = self.iqmodeloutput.queue_alert
e2eAlerts.leadDepartAlert = self.e2e_alerts_helper.lead_alert e2eAlerts.leadDepartAlert = self.iqmodeloutput.lead_alert
valid = sm.all_checks(service_list=['carState', 'controlsState']) valid = sm.all_checks(service_list=['carState', 'controlsState'])