From f73af2211d9bb087eac50a83615612cbee67ed6a Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Sat, 15 Aug 2026 11:22:14 -0500 Subject: [PATCH] The Saturday Threshold --- .../opendbc/car/fw_query_definitions.py | 1 + opendbc_repo/opendbc/car/fw_versions.py | 6 +++ .../opendbc/car/subaru/tests/test_subaru.py | 32 +++++++++++++- opendbc_repo/opendbc/car/subaru/values.py | 16 ++----- .../opendbc/car/tests/test_fw_fingerprint.py | 4 +- .../controls/lib/longitudinal_planner.py | 4 +- .../lib/longitudinal_vehicle_tunes.py | 9 ++++ .../controls/tests/test_starpilot_vcruise.py | 24 +++++++++++ selfdrive/ui/onroad/cameraview.py | 14 +++++- selfdrive/ui/tests/test_camera_frame_order.py | 6 +++ starpilot/controls/lib/starpilot_vcruise.py | 43 ++++++++++++++++--- system/ui/README.md | 1 + 12 files changed, 136 insertions(+), 24 deletions(-) diff --git a/opendbc_repo/opendbc/car/fw_query_definitions.py b/opendbc_repo/opendbc/car/fw_query_definitions.py index 5c48fed6a..a43f4bb2c 100644 --- a/opendbc_repo/opendbc/car/fw_query_definitions.py +++ b/opendbc_repo/opendbc/car/fw_query_definitions.py @@ -101,6 +101,7 @@ class Request: @dataclass class FwQueryConfig: requests: list[Request] + non_tester_present_ecus: list[Ecu] = field(default_factory=list) # TODO: make this automatic and remove hardcoded lists, or do fingerprinting with ecus # Overrides and removes from essential ecus for specific models and ecus (exact matching) non_essential_ecus: dict[Ecu, list[str]] = field(default_factory=dict) diff --git a/opendbc_repo/opendbc/car/fw_versions.py b/opendbc_repo/opendbc/car/fw_versions.py index 09d83b527..6e4b2aebf 100644 --- a/opendbc_repo/opendbc/car/fw_versions.py +++ b/opendbc_repo/opendbc/car/fw_versions.py @@ -181,6 +181,9 @@ def get_present_ecus(can_recv: CanRecvCallable, can_send: CanSendCallable, set_o continue for ecu_type, addr, sub_addr in config.get_all_ecus(VERSIONS[brand]): + if ecu_type in config.non_tester_present_ecus: + continue + # Only query ecus in whitelist if whitelist is not empty if len(r.whitelist_ecus) == 0 or ecu_type in r.whitelist_ecus: a = (addr, sub_addr, r.bus) @@ -216,6 +219,9 @@ def get_brand_ecu_matches(ecu_rx_addrs: set[EcuAddrBusType]) -> dict[str, list[b # Since we can't know what request an ecu responded to, add matches for all possible rx offsets for brand, config, r in REQUESTS: for ecu in config.get_all_ecus(VERSIONS[brand]): + if ecu[0] in config.non_tester_present_ecus: + continue + if len(r.whitelist_ecus) == 0 or ecu[0] in r.whitelist_ecus: brand_rx_addrs[brand].add((uds.get_rx_addr_for_tx_addr(ecu[1], r.rx_offset), ecu[2])) diff --git a/opendbc_repo/opendbc/car/subaru/tests/test_subaru.py b/opendbc_repo/opendbc/car/subaru/tests/test_subaru.py index bc9239454..bc80294a4 100644 --- a/opendbc_repo/opendbc/car/subaru/tests/test_subaru.py +++ b/opendbc_repo/opendbc/car/subaru/tests/test_subaru.py @@ -5,14 +5,16 @@ from types import SimpleNamespace import pytest from opendbc.can import CANPacker, CANParser -from opendbc.car import Bus, structs +from opendbc.car import Bus, fw_versions, structs +from opendbc.car.fw_query_definitions import StdQueries from opendbc.car.subaru import subarucan from opendbc.car.subaru.carcontroller import CarController from opendbc.car.subaru.carstate import CarState from opendbc.car.subaru.fingerprints import FW_VERSIONS from opendbc.car.fw_versions import match_fw_to_car from opendbc.car.subaru.interface import CarInterface -from opendbc.car.subaru.values import CAR, DBC, CanBus, SubaruFlags, SubaruSafetyFlags +from opendbc.car.subaru.values import CAR, DBC, FW_QUERY_CONFIG, SUBARU_ALT_VERSION_REQUEST, SUBARU_VERSION_REQUEST, CanBus, \ + SubaruFlags, SubaruSafetyFlags from opendbc.car.structs import CarParams @@ -66,6 +68,32 @@ def test_preglobal_sng_does_not_send_standstill_keepalive_without_manual_toggle( class TestSubaruFingerprint: + def test_eyesight_queries_do_not_change_diagnostic_state(self, monkeypatch): + camera_requests = [request for request in FW_QUERY_CONFIG.requests if CarParams.Ecu.fwdCamera in request.whitelist_ecus] + + assert CarParams.Ecu.fwdCamera in FW_QUERY_CONFIG.non_tester_present_ecus + assert {tuple(request.request) for request in camera_requests} == { + (SUBARU_VERSION_REQUEST,), + (SUBARU_ALT_VERSION_REQUEST,), + } + for request in camera_requests: + assert StdQueries.TESTER_PRESENT_REQUEST not in request.request + assert StdQueries.DEFAULT_DIAGNOSTIC_REQUEST not in request.request + + queried_ecus = set() + + def collect_queries(_can_recv, _can_send, queries, _responses, timeout): + queried_ecus.update(queries) + return set() + + monkeypatch.setattr(fw_versions, "REQUESTS", [("subaru", FW_QUERY_CONFIG, request) for request in FW_QUERY_CONFIG.requests]) + monkeypatch.setattr(fw_versions, "VERSIONS", {"subaru": FW_VERSIONS}) + monkeypatch.setattr(fw_versions, "get_ecu_addrs", collect_queries) + fw_versions.get_present_ecus(lambda **_kwargs: [], lambda _msgs: None, lambda _enabled: None) + + assert queried_ecus + assert all(address != 0x787 for address, _subaddress, _bus in queried_ecus) + def test_fw_version_format(self): for platform, fws_per_ecu in FW_VERSIONS.items(): for (ecu, _, _), fws in fws_per_ecu.items(): diff --git a/opendbc_repo/opendbc/car/subaru/values.py b/opendbc_repo/opendbc/car/subaru/values.py index bb23533d2..ea1192ad5 100644 --- a/opendbc_repo/opendbc/car/subaru/values.py +++ b/opendbc_repo/opendbc/car/subaru/values.py @@ -281,12 +281,10 @@ FW_QUERY_CONFIG = FwQueryConfig( Request( [StdQueries.TESTER_PRESENT_REQUEST, SUBARU_VERSION_REQUEST], [StdQueries.TESTER_PRESENT_RESPONSE, SUBARU_VERSION_RESPONSE], - whitelist_ecus=[Ecu.abs, Ecu.eps, Ecu.fwdCamera, Ecu.engine, Ecu.transmission], + whitelist_ecus=[Ecu.abs, Ecu.eps, Ecu.engine, Ecu.transmission], logging=True, ), # Non-OBD requests - # Some Eyesight modules fail on TESTER_PRESENT_REQUEST - # TODO: check if this resolves the fingerprinting issue for the 2023 Ascent and other new Subaru cars Request( [SUBARU_VERSION_REQUEST], [SUBARU_VERSION_RESPONSE], @@ -300,28 +298,22 @@ FW_QUERY_CONFIG = FwQueryConfig( bus=0, logging=True, ), - Request( - [StdQueries.DEFAULT_DIAGNOSTIC_REQUEST, StdQueries.TESTER_PRESENT_REQUEST, SUBARU_VERSION_REQUEST], - [StdQueries.DEFAULT_DIAGNOSTIC_RESPONSE, StdQueries.TESTER_PRESENT_RESPONSE, SUBARU_VERSION_RESPONSE], - whitelist_ecus=[Ecu.fwdCamera], - bus=0, - logging=True, - ), Request( [StdQueries.TESTER_PRESENT_REQUEST, SUBARU_VERSION_REQUEST], [StdQueries.TESTER_PRESENT_RESPONSE, SUBARU_VERSION_RESPONSE], - whitelist_ecus=[Ecu.abs, Ecu.eps, Ecu.fwdCamera, Ecu.engine, Ecu.transmission], + whitelist_ecus=[Ecu.abs, Ecu.eps, Ecu.engine, Ecu.transmission], bus=0, ), # GEN2 powertrain bus query Request( [StdQueries.TESTER_PRESENT_REQUEST, SUBARU_VERSION_REQUEST], [StdQueries.TESTER_PRESENT_RESPONSE, SUBARU_VERSION_RESPONSE], - whitelist_ecus=[Ecu.abs, Ecu.eps, Ecu.fwdCamera, Ecu.engine, Ecu.transmission], + whitelist_ecus=[Ecu.abs, Ecu.eps, Ecu.engine, Ecu.transmission], bus=1, obd_multiplexing=False, ), ], + non_tester_present_ecus=[Ecu.fwdCamera], # We don't get the EPS from non-OBD queries on GEN2 cars. Note that we still attempt to match when it exists non_essential_ecus={ Ecu.eps: list(CAR.with_flags(SubaruFlags.GLOBAL_GEN2)), diff --git a/opendbc_repo/opendbc/car/tests/test_fw_fingerprint.py b/opendbc_repo/opendbc/car/tests/test_fw_fingerprint.py index 2a8f6dd22..21c494219 100644 --- a/opendbc_repo/opendbc/car/tests/test_fw_fingerprint.py +++ b/opendbc_repo/opendbc/car/tests/test_fw_fingerprint.py @@ -265,7 +265,7 @@ class TestFwFingerprintTiming: print(f'get_vin {name} case, query time={self.total_time / self.N} seconds') def test_fw_query_timing(self, subtests, mocker): - total_ref_time = {1: 7.4, 2: 8.0} + total_ref_time = {1: 7.3, 2: 7.9} brand_ref_times = { 1: { 'gm': 1.0, @@ -276,7 +276,7 @@ class TestFwFingerprintTiming: 'hyundai': 0.65, 'mazda': 0.1, 'nissan': 0.8, - 'subaru': 0.65, + 'subaru': 0.55, 'tesla': 0.1, 'toyota': 0.7, 'volkswagen': 0.65, diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 08c2958b0..d38f8a04f 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -21,6 +21,7 @@ from openpilot.selfdrive.controls.lib.lead_follow_policy import is_nonurgent_dup from openpilot.selfdrive.controls.lib.longitudinal_vehicle_tunes import ( get_far_follow_output_slew_rates, get_follow_prebrake_min_headway, + get_force_stop_handoff_distance, is_gm_silverado_early_follow_lead, is_toyota_rav4_tss2_post_departure_tune, get_toyota_sienna_post_departure_restop_cap, @@ -2177,7 +2178,8 @@ class LongitudinalPlanner: # the line parks us short. Below that the existing v_cruise=0 path finishes the stop, # since forcingStopLength is decaying to zero and the obstacle would land behind us. force_stop_x = None - if sm['starpilotPlan'].forcingStop and sm['starpilotPlan'].forcingStopLength > STOP_DISTANCE: + force_stop_handoff_m = get_force_stop_handoff_distance(self.CP.carFingerprint) + if sm['starpilotPlan'].forcingStop and sm['starpilotPlan'].forcingStopLength > force_stop_handoff_m: force_stop_x = float(sm['starpilotPlan'].forcingStopLength) + STOP_DISTANCE self.mpc.update(sm['radarState'], v_cruise, x, v, a, j, diff --git a/selfdrive/controls/lib/longitudinal_vehicle_tunes.py b/selfdrive/controls/lib/longitudinal_vehicle_tunes.py index c83db3bc4..80471ed8d 100644 --- a/selfdrive/controls/lib/longitudinal_vehicle_tunes.py +++ b/selfdrive/controls/lib/longitudinal_vehicle_tunes.py @@ -18,6 +18,8 @@ TOYOTA_SIENNA_POST_DEPARTURE_RESTOP_MIN_MODEL_PROB = 0.95 TOYOTA_SIENNA_POST_DEPARTURE_RESTOP_MAX_LATERAL_OFFSET = 1.75 TOYOTA_SIENNA_POST_DEPARTURE_RESTOP_MIN_BRAKE = 0.18 TOYOTA_SIENNA_POST_DEPARTURE_RESTOP_MAX_BRAKE = 0.32 +TOYOTA_CAMRY_TSS2_FORCE_STOP_HANDOFF_M = 4.5 +DEFAULT_FORCE_STOP_HANDOFF_M = 6.0 def is_toyota_rav4_tss2_post_departure_tune(CP): @@ -109,3 +111,10 @@ def get_toyota_sienna_post_departure_restop_cap(CP, lead, v_ego, accel_min, TOYOTA_SIENNA_POST_DEPARTURE_RESTOP_MAX_BRAKE, )) return brake_floor if accel_min >= 0.0 else max(float(accel_min), brake_floor) + + +def get_force_stop_handoff_distance(car_fingerprint): + """Return the distance at which force-stop control hands off to MPC.""" + if str(car_fingerprint) == "TOYOTA_CAMRY_TSS2": + return TOYOTA_CAMRY_TSS2_FORCE_STOP_HANDOFF_M + return DEFAULT_FORCE_STOP_HANDOFF_M diff --git a/selfdrive/controls/tests/test_starpilot_vcruise.py b/selfdrive/controls/tests/test_starpilot_vcruise.py index 8aadc430a..cab80192c 100644 --- a/selfdrive/controls/tests/test_starpilot_vcruise.py +++ b/selfdrive/controls/tests/test_starpilot_vcruise.py @@ -13,6 +13,7 @@ from openpilot.starpilot.controls.lib.starpilot_vcruise import ( get_lead_veto_distance, get_slc_lead_drop_relaxed_target, ) +from openpilot.selfdrive.controls.lib.longitudinal_vehicle_tunes import get_force_stop_handoff_distance from types import SimpleNamespace @@ -116,6 +117,11 @@ def test_elantra_gets_lead_veto_margin_before_force_stop(): assert get_lead_veto_distance(SimpleNamespace(carFingerprint="OTHER_CAR")) == pytest.approx(75.0) +def test_camry_tss2_uses_closer_force_stop_handoff(): + assert get_force_stop_handoff_distance("TOYOTA_CAMRY_TSS2") == pytest.approx(4.5) + assert get_force_stop_handoff_distance("TOYOTA_RAV4_TSS2") == pytest.approx(6.0) + + def test_curve_speed_controller_holds_target_through_brief_detector_dropout(): planner, vcruise = make_vcruise() sm = make_sm(standstill=False) @@ -478,6 +484,24 @@ def test_force_stop_stays_committed_while_moving_even_if_scene_opens(): assert vcruise.forcing_stop +def test_force_stop_releases_after_cem_light_clears_while_moving(): + planner, vcruise = make_vcruise(red_light=True, raw_model_stopped=False, forcing_stop=True) + sm = make_sm(standstill=False) + toggles = make_toggles() + + update_vcruise(vcruise, sm, toggles, now=0.0, v_ego=3.0) + assert vcruise.force_stop_from_light + + planner.starpilot_cem.stop_light_detected = False + update_vcruise(vcruise, sm, toggles, now=0.25, v_ego=3.0) + assert vcruise.forcing_stop + + result = update_vcruise(vcruise, sm, toggles, now=0.75, v_ego=3.0) + assert result == pytest.approx(20.0) + assert not vcruise.forcing_stop + assert not vcruise.force_stop_from_light + + def test_force_stop_turn_scene_veto_blocks_new_activation(): _, vcruise = make_vcruise(red_light=False, raw_model_stopped=False, forcing_stop=False) sm = make_sm(standstill=False) diff --git a/selfdrive/ui/onroad/cameraview.py b/selfdrive/ui/onroad/cameraview.py index b1e7a871d..ac5c52ffa 100644 --- a/selfdrive/ui/onroad/cameraview.py +++ b/selfdrive/ui/onroad/cameraview.py @@ -6,7 +6,7 @@ import pyray as rl from msgq.visionipc import VisionIpcClient, VisionStreamType, VisionBuf from openpilot.common.swaglog import cloudlog -from openpilot.system.hardware import PC, TICI +from openpilot.system.hardware import HARDWARE, PC, TICI from openpilot.system.ui.lib.application import gui_app from openpilot.system.ui.lib.egl import ( init_egl, is_egl_initialized, finish_gl, create_egl_image, destroy_egl_image, @@ -17,7 +17,17 @@ from openpilot.selfdrive.ui.ui_state import ui_state CONNECTION_RETRY_INTERVAL = 0.2 # seconds between connection attempts STREAM_DISCOVERY_REFRESH_INTERVAL = 0.5 # seconds between nonblocking stream advertisements -MICI_FORCE_TEXTURE_CAMERA = os.getenv("MICI_FORCE_TEXTURE_CAMERA", "0") == "1" + + +def _default_force_texture_camera(device_type: str) -> bool: + return device_type == "mici" + + +DEVICE_TYPE = HARDWARE.get_device_type() +MICI_FORCE_TEXTURE_CAMERA = os.getenv( + "MICI_FORCE_TEXTURE_CAMERA", + "1" if _default_force_texture_camera(DEVICE_TYPE) else "0", +) == "1" # One stale frame can be normal ring-buffer reuse; repeated consecutive regressions demote EGL. EGL_REGRESSIVE_FRAME_FALLBACK_THRESHOLD = 3 diff --git a/selfdrive/ui/tests/test_camera_frame_order.py b/selfdrive/ui/tests/test_camera_frame_order.py index e4217ff3b..0e91cb094 100644 --- a/selfdrive/ui/tests/test_camera_frame_order.py +++ b/selfdrive/ui/tests/test_camera_frame_order.py @@ -30,6 +30,12 @@ def test_mici_uses_shared_camera_view(): assert not big_cameraview.CameraView._use_upstream_engaged_color +def test_c4_defaults_to_ui_owned_camera_textures(): + assert big_cameraview._default_force_texture_camera("mici") + assert not big_cameraview._default_force_texture_camera("tici") + assert not big_cameraview._default_force_texture_camera("tizi") + + def test_pending_switch_is_cancelled_when_requested_stream_is_current(): view = _camera_view() view._stream_type = big_cameraview.VisionStreamType.VISION_STREAM_ROAD diff --git a/starpilot/controls/lib/starpilot_vcruise.py b/starpilot/controls/lib/starpilot_vcruise.py index 1fdf422dc..e92d4b442 100644 --- a/starpilot/controls/lib/starpilot_vcruise.py +++ b/starpilot/controls/lib/starpilot_vcruise.py @@ -8,12 +8,14 @@ from openpilot.common.realtime import DT_MDL from openpilot.starpilot.common.starpilot_variables import CITY_SPEED_LIMIT, CRUISING_SPEED from openpilot.starpilot.controls.lib.curve_speed_controller import CurveSpeedController, is_manual_speed_control from openpilot.starpilot.controls.lib.speed_limit_controller import SpeedLimitController +from openpilot.selfdrive.controls.lib.longitudinal_vehicle_tunes import get_force_stop_handoff_distance CSC_MIN_SPEED = CITY_SPEED_LIMIT * CV.MPH_TO_MS CSC_CURVE_RELEASE_HOLD_TIME = 0.75 OVERRIDE_FORCE_STOP_TIMER = 10 STANDSTILL_FORCE_STOP_CLEAR_TIME = 0.75 STANDSTILL_FORCE_STOP_LIGHT_HOLD_TIME = 5.0 +FORCE_STOP_LIGHT_CLEAR_TIME = 0.5 SLC_LEAD_DROP_RELAXATION_MIN_SPEED = 20.0 * CV.MPH_TO_MS SLC_LEAD_DROP_RELAXATION_MIN_DISTANCE = 30.0 SLC_LEAD_DROP_RELAXATION_MIN_HEADWAY = 1.2 @@ -48,7 +50,6 @@ LEAD_VETO_M = 75.0 # m — lead proximity that vetoes Force Stop (kept of LEAD_VETO_M_OVERRIDES = { "HYUNDAI_ELANTRA_2021": 90.0, } -MPC_HANDOFF_M = 6.0 # m — below this, command 0 and let MPC finish the stop FORCE_STOP_APPROACH_DECEL = 0.65 # m/s^2 — speed ceiling before commit. LOWER = more early # braking; don't go under FORCE_STOP_MODEL_APPROACH_DECEL ADAS_MAX_MS = 17.88 # 40 mph — cross-street ADAS guard @@ -166,6 +167,8 @@ class StarPilotVCruise: self.standstill_force_stop_clear_since = 0.0 self.standstill_force_stop_started_at = None self.standstill_force_stop_reason = None + self.force_stop_from_light = False + self.force_stop_light_clear_since = None self.controls_enabled_previously = False # Kinematic distance estimator. Same attribute also published as # starpilotPlan.forcingStopLength, so the existing reader keeps working. @@ -314,6 +317,9 @@ class StarPilotVCruise: self._applied_slc_control_target = 0.0 long_control_active = sm["carControl"].longActive + force_stop_handoff_m = get_force_stop_handoff_distance( + getattr(starpilot_toggles, "car_model", "") + ) raw_stop_seen = bool( self.starpilot_planner.starpilot_cem.stop_light_detected @@ -393,6 +399,13 @@ class StarPilotVCruise: force_stop_active = cem_path or dash_path + if cem_path: + self.force_stop_from_light = True + self.force_stop_light_clear_since = None + elif not self.forcing_stop: + self.force_stop_from_light = False + self.force_stop_light_clear_since = None + # Latch on first dash frame so the CEM pin can fire and we don't release on # transient dashboard dropouts. Cleared in the no-force-stop branch below. if dash_path: @@ -463,6 +476,26 @@ class StarPilotVCruise: force_stop_enabled |= self.forcing_stop and not sm["carState"].standstill force_stop_enabled |= self.standstill_force_stop_hold + light_stop_cleared = ( + self.forcing_stop and + self.force_stop_from_light and + not sm["carState"].standstill and + not stop_light_detected and + not raw_model_stopped and + not dash_active + ) + if light_stop_cleared: + if self.force_stop_light_clear_since is None: + self.force_stop_light_clear_since = now + elif self._elapsed_seconds(now, self.force_stop_light_clear_since) >= FORCE_STOP_LIGHT_CLEAR_TIME: + self.forcing_stop = False + self.force_stop_from_light = False + self.force_stop_light_clear_since = None + self.force_stop_timer = 0.0 + force_stop_enabled = False + else: + self.force_stop_light_clear_since = None + if self.forcing_stop and standstill and not force_stop_enabled and self.standstill_force_stop_reason != "sign": self.override_force_stop_timer = OVERRIDE_FORCE_STOP_TIMER @@ -583,11 +616,11 @@ class StarPilotVCruise: # Kinematic profile with user offset. Positive offset shifts the perceived # line further down the road -> car rolls further before commanding 0. effective_d = self.tracked_model_length + offset_m - if effective_d <= MPC_HANDOFF_M: + if effective_d <= force_stop_handoff_m: v_target = 0.0 else: approach_decel = FORCE_STOP_DASH_APPROACH_DECEL if dash_active else FORCE_STOP_MODEL_APPROACH_DECEL - v_target = math.sqrt(2.0 * approach_decel * (effective_d - MPC_HANDOFF_M)) + v_target = math.sqrt(2.0 * approach_decel * (effective_d - force_stop_handoff_m)) v_cruise = min(v_target, v_cruise) @@ -644,8 +677,8 @@ class StarPilotVCruise: if adjacent_stop_d is not None: approach_d = min(approach_d, adjacent_stop_d) approach_d += offset_m - if approach_d > MPC_HANDOFF_M: - targets.append(math.sqrt(2.0 * FORCE_STOP_APPROACH_DECEL * (approach_d - MPC_HANDOFF_M))) + if approach_d > force_stop_handoff_m: + targets.append(math.sqrt(2.0 * FORCE_STOP_APPROACH_DECEL * (approach_d - force_stop_handoff_m))) v_cruise = min(targets) diff --git a/system/ui/README.md b/system/ui/README.md index 15594930d..5323dd6ce 100644 --- a/system/ui/README.md +++ b/system/ui/README.md @@ -12,6 +12,7 @@ Quick start: Set `BURN_IN_PREVENTION=0` to disable it or tune it with `BURN_IN_SHIFT_PIXELS`, `BURN_IN_SHIFT_INTERVAL`, and `BURN_IN_SHIFT_TRANSITION_SECONDS`. TICI/TIZI shift the completed frame through the offscreen presentation path; MICI uses direct shifting by default. Setting `WHITE_LUMINANCE_CAP` below `1.0` also enables the offscreen presentation path. +* the C4 UI uses copied camera textures by default to avoid sampling camerad's reusable EGL buffers; set `MICI_FORCE_TEXTURE_CAMERA=0` to re-enable EGL for diagnostics * set `MICI_FORCE_RENDER_TEXTURE=1` to force the C4 UI through the offscreen presentation path for diagnostics * set `GRID=50` to show a 50-pixel alignment grid overlay * set `MAGIC_DEBUG=1` to show every dropped frames (only on device)