diff --git a/common/libcommon.a b/common/libcommon.a index 019c4ed7..55d26bdb 100644 Binary files a/common/libcommon.a and b/common/libcommon.a differ diff --git a/common/params_keys.h b/common/params_keys.h index cf0b1b28..83906ffd 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -38,6 +38,7 @@ inline static std::unordered_map keys = { {"DoUninstall", {CLEAR_ON_MANAGER_START, BOOL}}, {"DriverTooDistracted", {CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON, BOOL}}, {"AlphaLongitudinalEnabled", {PERSISTENT, BOOL}}, + {"ExperimentalLongitudinalEnabled", {PERSISTENT, BOOL}}, {"ExperimentalMode", {PERSISTENT, BOOL}}, {"ExperimentalModeConfirmed", {PERSISTENT, BOOL}}, {"FirmwareQueryDone", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}}, diff --git a/common/params_pyx.so b/common/params_pyx.so index 92d2fccc..2b590413 100755 Binary files a/common/params_pyx.so and b/common/params_pyx.so differ diff --git a/frogpilot/controls/frogpilot_card.py b/frogpilot/controls/frogpilot_card.py index 3601fee0..f0244a91 100644 --- a/frogpilot/controls/frogpilot_card.py +++ b/frogpilot/controls/frogpilot_card.py @@ -37,13 +37,13 @@ class FrogPilotCard: def handle_button_event(self, key, sm, frogpilot_toggles): if sm["carControl"].longActive and getattr(frogpilot_toggles, f"experimental_mode_via_{key}"): self.handle_experimental_mode(sm, frogpilot_toggles) - elif sm["carControl"].longActive and getattr(frogpilot_toggles, f"force_coast_via_{key}"): + elif getattr(frogpilot_toggles, f"force_coast_via_{key}"): self.force_coast = not self.force_coast elif getattr(frogpilot_toggles, f"pause_lateral_via_{key}"): self.pause_lateral = not self.pause_lateral - elif sm["carControl"].longActive and getattr(frogpilot_toggles, f"pause_longitudinal_via_{key}"): + elif getattr(frogpilot_toggles, f"pause_longitudinal_via_{key}"): self.pause_longitudinal = not self.pause_longitudinal - elif getattr(frogpilot_toggles, f"traffic_mode_via_{key}"): + elif sm["carControl"].longActive and getattr(frogpilot_toggles, f"traffic_mode_via_{key}"): self.traffic_mode_enabled = not self.traffic_mode_enabled def handle_experimental_mode(self, sm, frogpilot_toggles): @@ -83,6 +83,8 @@ class FrogPilotCard: if sm.updated["frogpilotPlan"] or any(be.type == ButtonType.decelCruise for be in carState.buttonEvents): self.decel_pressed = any(be.type == ButtonType.decelCruise for be in carState.buttonEvents) + frogpilotCarState.distancePressed |= self.params_memory.get_bool("OnroadDistanceButtonPressed") + if frogpilotCarState.distancePressed: self.gap_counter += 1 elif not self.distancePressed_previously: diff --git a/frogpilot/controls/lib/curve_speed_controller.py b/frogpilot/controls/lib/curve_speed_controller.py index 36febe46..0c3f1e9a 100644 --- a/frogpilot/controls/lib/curve_speed_controller.py +++ b/frogpilot/controls/lib/curve_speed_controller.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +import json + import numpy as np from openpilot.common.realtime import DT_MDL @@ -21,7 +23,11 @@ class CurveSpeedController: self.training_timer = 0 - self.curvature_data = self.frogpilot_planner.params.get("CurvatureData") + curvature_data_raw = self.frogpilot_planner.params.get("CurvatureData", encoding="utf-8") + try: + self.curvature_data = json.loads(curvature_data_raw or "{}") + except (TypeError, ValueError): + self.curvature_data = {} self.calculate_weights() self.update_lateral_acceleration() diff --git a/frogpilot/controls/lib/speed_limit_controller.py b/frogpilot/controls/lib/speed_limit_controller.py index 96d95d2f..a54c81c7 100644 --- a/frogpilot/controls/lib/speed_limit_controller.py +++ b/frogpilot/controls/lib/speed_limit_controller.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 # PFEIFER - SLC - Modified by FrogAi for FrogPilot import calendar +import json import numpy as np import requests @@ -36,6 +37,7 @@ OFFSET_MAP_METRIC = [ class SpeedLimitController: def __init__(self, FrogPilotVCruise): self.frogpilot_planner = FrogPilotVCruise.frogpilot_planner + self.frogpilot_toggles = None self.calling_mapbox = False self.override_slc = False @@ -53,14 +55,18 @@ class SpeedLimitController: self.previous_source = "None" self.source = "None" - self.mapbox_requests = self.frogpilot_planner.params.get("MapBoxRequests") + mapbox_requests_raw = self.frogpilot_planner.params.get("MapBoxRequests", encoding="utf-8") + try: + self.mapbox_requests = json.loads(mapbox_requests_raw or "{}") + except (TypeError, ValueError): + self.mapbox_requests = {} self.mapbox_requests.setdefault("total_requests", 0) self.mapbox_requests.setdefault("max_requests", FREE_MAPBOX_REQUESTS - (28 * 100)) self.mapbox_host = "https://api.mapbox.com" - self.mapbox_token = self.frogpilot_planner.params.get("MapboxSecretKey") + self.mapbox_token = self.frogpilot_planner.params.get("MapboxSecretKey", encoding="utf-8") - self.previous_target = self.frogpilot_planner.params.get("PreviousSpeedLimit") + self.previous_target = self.frogpilot_planner.params.get_float("PreviousSpeedLimit") self.executor = ThreadPoolExecutor(max_workers=1) @@ -70,10 +76,12 @@ class SpeedLimitController: @property def experimental_mode(self): - return self.target == 0 and self.frogpilot_toggles.slc_fallback_experimental_mode + return self.target == 0 and bool(getattr(self.frogpilot_toggles, "slc_fallback_experimental_mode", False)) @property def offset(self): + if self.frogpilot_toggles is None: + return 0 offset_map = OFFSET_MAP_METRIC if self.frogpilot_toggles.is_metric else OFFSET_MAP_IMPERIAL return next((getattr(self.frogpilot_toggles, offset) for low, high, offset in offset_map if low < self.target < high), 0) diff --git a/frogpilot/controls/lib/weather_checker.py b/frogpilot/controls/lib/weather_checker.py index fefd70e1..9305e675 100644 --- a/frogpilot/controls/lib/weather_checker.py +++ b/frogpilot/controls/lib/weather_checker.py @@ -56,7 +56,7 @@ class WeatherChecker: self.last_updated = None self.requesting = False - self.user_api_key = self.frogpilot_planner.params.get("WeatherToken") + self.user_api_key = self.frogpilot_planner.params.get("WeatherToken", encoding="utf-8") if self.user_api_key: self.check_interval = 60 diff --git a/opendbc_repo/opendbc/car/gm/carcontroller.py b/opendbc_repo/opendbc/car/gm/carcontroller.py index 1a0233f0..aad53446 100644 --- a/opendbc_repo/opendbc/car/gm/carcontroller.py +++ b/opendbc_repo/opendbc/car/gm/carcontroller.py @@ -20,6 +20,13 @@ CAMERA_CANCEL_DELAY_FRAMES = 10 MIN_STEER_MSG_INTERVAL_MS = 15 +def get_stock_cc_active_for_cancel(CP, CS): + stock_cc_active = CS.out.cruiseState.enabled or CS.pcm_acc_status != AccState.OFF + if CP.carFingerprint == CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL: + return CS.out.cruiseState.enabled + return stock_cc_active + + class CarController(CarControllerBase): def __init__(self, dbc_names, CP): super().__init__(dbc_names, CP) @@ -529,16 +536,12 @@ class CarController(CarControllerBase): can_sends += gmcan.create_adas_keepalive(CanBus.POWERTRAIN) # - CC_LONG: cancel stock CC if OP is not active - stock_cc_active = CS.out.cruiseState.enabled or CS.pcm_acc_status != AccState.OFF - # Pedal-long cancel should only run while stock cruise is actually enabled. - # Using pcm_acc_status here causes cancel spam even after disable, which can - # intermittently knock CruiseMain off. - stock_cc_active_pedal = CS.out.cruiseState.enabled + stock_cc_active = get_stock_cc_active_for_cancel(self.CP, CS) pedal_cancel = bool(self.CP.flags & GMFlags.PEDAL_LONG.value) if self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC: pedal_cancel = pedal_cancel and CC.longActive - if ((pedal_cancel and stock_cc_active_pedal) or + if ((pedal_cancel and stock_cc_active) or (((self.CP.flags & GMFlags.CC_LONG.value) and not CC.enabled) and stock_cc_active)): if self.CP.carFingerprint == CAR.CHEVROLET_MALIBU_HYBRID_CC: malibu_cancel_requested = True diff --git a/opendbc_repo/opendbc/car/gm/carstate.py b/opendbc_repo/opendbc/car/gm/carstate.py index ce726e64..47bea4ed 100644 --- a/opendbc_repo/opendbc/car/gm/carstate.py +++ b/opendbc_repo/opendbc/car/gm/carstate.py @@ -319,9 +319,16 @@ class CarState(CarStateBase): self.cruise_buttons in (CruiseButtons.CANCEL, CruiseButtons.MAIN) or prev_cruise_buttons in (CruiseButtons.CANCEL, CruiseButtons.MAIN) ) + suppress_bolt_cancel_lkas = bolt_cancel_personality and ( + self.cruise_buttons == CruiseButtons.CANCEL or + prev_cruise_buttons == CruiseButtons.CANCEL + ) distance_events = [] if suppress_malibu_side_buttons else create_button_events( self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise} ) + lkas_events = [] if (suppress_malibu_side_buttons or suppress_bolt_cancel_lkas) else create_button_events( + self.lkas_enabled, self.lkas_previously_enabled, {1: ButtonType.lkas} + ) # Don't add events if transitioning from INIT, unless it's to an actual button. if self.cruise_buttons != CruiseButtons.UNPRESS or prev_cruise_buttons != CruiseButtons.INIT: @@ -329,6 +336,7 @@ class CarState(CarStateBase): *cruise_events, *cancel_gap_events, *distance_events, + *lkas_events, ] if ret.vEgo < self.CP.minSteerSpeed: diff --git a/opendbc_repo/opendbc/car/gm/gmcan.py b/opendbc_repo/opendbc/car/gm/gmcan.py index 692dd8b3..b59e5d7e 100644 --- a/opendbc_repo/opendbc/car/gm/gmcan.py +++ b/opendbc_repo/opendbc/car/gm/gmcan.py @@ -116,23 +116,24 @@ def create_adas_keepalive(bus): def create_gas_regen_command(packer, bus, throttle, idx, enabled, at_full_stop, include_always_one3=False): - # Legacy callsites may still pass include_always_one3; this DBC encodes ACC type explicitly instead. - _ = include_always_one3 - values = { - "GasRegenCmdActive": enabled, - "RollingCounter": idx, - "GasRegenCmd": throttle, - "GasRegenFullStopActive": at_full_stop, - "GasRegenAccType": 1, - } + # Keep GM camera-long GasRegen bytes aligned with StarPilot's legacy layout. + # The regenerated DBC shape does not pack to the same wire format on Global A. + dat = bytearray(8) + dat[0] = ((idx & 0x3) << 6) | int(enabled) + dat[1] = 0x42 | (0x20 if at_full_stop else 0x00) - dat = packer.make_can_msg("ASCMGasRegenCmd", bus, values)[1] - values["GasRegenChecksum"] = ((1 - int(enabled)) << 24) | \ - (((0xff - dat[1]) & 0xff) << 16) | \ - (((0xff - dat[2]) & 0xff) << 8) | \ - ((0x100 - dat[3] - idx) & 0xff) + cmd = int(throttle) << 3 + dat[2] = (cmd >> 8) & 0xFF + dat[3] = cmd & 0xFF + if include_always_one3: + dat[2] |= 0x80 - return packer.make_can_msg("ASCMGasRegenCmd", bus, values) + dat[4] = 0x00 if enabled else 0x01 + dat[5] = (0xFF - dat[1]) & 0xFF + dat[6] = (0xFF - dat[2]) & 0xFF + dat[7] = (0x100 - dat[3] - idx) & 0xFF + + return CanData(0x2CB, bytes(dat), bus) def create_ecm_cruise_control_command(packer, bus, enabled, target_speed_kph): diff --git a/opendbc_repo/opendbc/car/gm/interface.py b/opendbc_repo/opendbc/car/gm/interface.py index 1bda5e6b..c66e088b 100755 --- a/opendbc_repo/opendbc/car/gm/interface.py +++ b/opendbc_repo/opendbc/car/gm/interface.py @@ -527,6 +527,10 @@ class CarInterface(CarInterfaceBase): else: ret.longitudinalTuning.kfDEPRECATED = 0.25 + if is_bolt_2022_2023_pedal: + # Gen2 Bolt pedal-long should follow the no-ACC panda path like StarPilot. + ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_NO_ACC.value + if candidate in (CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL, CAR.CHEVROLET_MALIBU_HYBRID_CC): ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_BOLT_2022_PEDAL.value diff --git a/opendbc_repo/opendbc/car/tests/test_car_interfaces.py b/opendbc_repo/opendbc/car/tests/test_car_interfaces.py index a329ee3b..2a36ff75 100644 --- a/opendbc_repo/opendbc/car/tests/test_car_interfaces.py +++ b/opendbc_repo/opendbc/car/tests/test_car_interfaces.py @@ -10,6 +10,7 @@ from opendbc.car import DT_CTRL, CanData, structs from opendbc.car.car_helpers import interfaces from opendbc.car.fingerprints import FW_VERSIONS from opendbc.car.fw_versions import FW_QUERY_CONFIGS +from opendbc.car.gm.values import CAR as GM_CAR, CanBus as GMCanBus, GMSafetyFlags from opendbc.car.interfaces import CarInterfaceBase, get_interface_attr from opendbc.car.mock.values import CAR as MOCK from opendbc.car.values import PLATFORMS @@ -57,6 +58,33 @@ def get_fuzzy_car_interface(car_name: str, draw: DrawType) -> CarInterfaceBase: class TestCarInterfaces: + def test_gm_bolt_gen2_pedal_safety_flags(self): + CarInterface = interfaces[GM_CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL] + + pedal_fingerprint = {bus: {} for bus in range(8)} + pedal_fingerprint[GMCanBus.POWERTRAIN][0x201] = 6 + pedal_params = CarInterface.get_params( + GM_CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL, + pedal_fingerprint, + [], + alpha_long=False, + is_release=False, + docs=False, + ) + assert pedal_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_NO_ACC.value + assert pedal_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_BOLT_2022_PEDAL.value + + acc_fingerprint = {bus: {} for bus in range(8)} + acc_params = CarInterface.get_params( + GM_CAR.CHEVROLET_BOLT_ACC_2022_2023, + acc_fingerprint, + [], + alpha_long=False, + is_release=False, + docs=False, + ) + assert not (acc_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_NO_ACC.value) + # FIXME: Due to the lists used in carParams, Phase.target is very slow and will cause # many generated examples to overrun when max_examples > ~20, don't use it @pytest.mark.parametrize("car_name", sorted(PLATFORMS)) diff --git a/opendbc_repo/opendbc/safety/modes/gm.h b/opendbc_repo/opendbc/safety/modes/gm.h index bce49a01..d9f956fa 100644 --- a/opendbc_repo/opendbc/safety/modes/gm.h +++ b/opendbc_repo/opendbc/safety/modes/gm.h @@ -51,6 +51,7 @@ typedef enum { GM_CAM } GmHardware; static GmHardware gm_hw = GM_ASCM; +static bool gm_cam_long = false; static bool gm_pcm_cruise = false; static bool gm_sdgm = false; static bool gm_ascm_int = false; @@ -178,10 +179,6 @@ static void gm_try_send_3d1_spoof(uint32_t now_us) { return; } - if (!gm_3d1_scheduler_ready(now_us)) { - return; - } - if ((int32_t)(now_us - gm_3d1_next_tx_us) < 0) { return; } @@ -509,6 +506,33 @@ static bool gm_tx_hook(const CANPacket_t *msg) { return tx; } +static bool gm_fwd_hook(int bus_num, int addr) { + bool block_msg = false; + + if ((gm_hw == GM_CAM) || gm_sdgm) { + if (bus_num == 0) { + bool is_pscm_msg = addr == 0x184U; + // Keep the camera side sourced only from OP's spoofed cruise status on non-ACC paths. + bool is_ecm_cruise_status_msg = (addr == 0x3D1U) && !gm_has_acc; + block_msg = is_pscm_msg || is_ecm_cruise_status_msg; + } else if (bus_num == 2) { + bool is_lkas_msg = addr == 0x180U; + bool is_acc_status_msg = addr == 0x370U; + bool is_acc_actuation_msg = (addr == 0x315U) || (addr == 0x2CBU); + + block_msg = is_lkas_msg; + if (gm_cam_long || gm_pedal_long) { + block_msg |= is_acc_status_msg; + } + if (gm_cam_long) { + block_msg |= is_acc_actuation_msg; + } + } + } + + return block_msg; +} + static safety_config gm_init(uint16_t param) { const uint16_t GM_PARAM_HW_CAM = 1; const uint16_t GM_PARAM_HW_CAM_LONG = 2; @@ -663,7 +687,7 @@ static safety_config gm_init(uint16_t param) { gm_prndl2_state.phase_locked = false; gm_zero_u8(gm_prndl2_state.spoof_data, 8U); - bool gm_cam_long = GET_FLAG(param, GM_PARAM_HW_CAM_LONG); + gm_cam_long = GET_FLAG(param, GM_PARAM_HW_CAM_LONG) && !gm_cc_long; gm_pcm_cruise = (gm_hw == GM_CAM || gm_sdgm) && !gm_cam_long && !gm_force_ascm && !gm_pedal_long; gm_steer_limits = GET_FLAG(param, GM_PARAM_BOLT_2017) ? &GM_BOLT_2017_STEERING_LIMITS : &GM_STEERING_LIMITS; @@ -707,7 +731,7 @@ static safety_config gm_init(uint16_t param) { } // ASCM does not forward any messages - if (gm_hw == GM_ASCM || gm_cc_long) { + if (gm_hw == GM_ASCM) { ret.disable_forwarding = true; } return ret; @@ -717,4 +741,5 @@ const safety_hooks gm_hooks = { .init = gm_init, .rx = gm_rx_hook, .tx = gm_tx_hook, + .fwd = gm_fwd_hook, }; diff --git a/opendbc_repo/opendbc/safety/tests/test_gm.py b/opendbc_repo/opendbc/safety/tests/test_gm.py index f37ccd46..c9ef1864 100755 --- a/opendbc_repo/opendbc/safety/tests/test_gm.py +++ b/opendbc_repo/opendbc/safety/tests/test_gm.py @@ -246,6 +246,7 @@ def interceptor_msg(gas, addr): class TestGmInterceptorSafety(common.GasInterceptorSafetyTest, TestGmCameraSafety, TestGmEVSafetyBase): INTERCEPTOR_THRESHOLD = 550 + FWD_BLACKLISTED_ADDRS = {2: [0x180, 0x370], 0: [0x184, 0x3D1]} def setUp(self): self.packer = CANPackerPanda("gm_global_a_powertrain_generated") @@ -292,9 +293,6 @@ class TestGmInterceptorSafety(common.GasInterceptorSafetyTest, TestGmCameraSafet self.assertEqual(enabled, self._tx(self._button_msg(Buttons.CANCEL))) self.assertTrue(self.safety.get_controls_allowed()) - def test_fwd_hook(self): - pass - def test_disable_control_allowed_from_cruise(self): pass @@ -314,7 +312,7 @@ class TestGmInterceptorSafety(common.GasInterceptorSafetyTest, TestGmCameraSafet class TestGmCcLongitudinalSafety(TestGmCameraSafety): TX_MSGS = [[0x180, 0], [0x370, 0], [0x1E1, 0], [0x3D1, 0], [0xBD, 0], [0x1F5, 0], [0x184, 2], [0x1E1, 2]] - FWD_BLACKLISTED_ADDRS = {2: [0x180], 0: [0x184]} # block LKAS message and PSCMStatus + FWD_BLACKLISTED_ADDRS = {2: [0x180], 0: [0x184, 0x3D1]} # block LKAS, PSCMStatus, and stock cruise status BUTTONS_BUS = 0 # tx only def setUp(self): @@ -328,9 +326,6 @@ class TestGmCcLongitudinalSafety(TestGmCameraSafety): values = {"CruiseActive": enable} return self.packer.make_can_msg_panda("ECMCruiseControl", 0, values) - def test_fwd_hook(self): - pass - def test_buttons(self): self.safety.set_controls_allowed(0) for btn in range(8): diff --git a/panda/board/obj/body_h7.bin.signed b/panda/board/obj/body_h7.bin.signed index 6beca399..f8c50c0f 100644 Binary files a/panda/board/obj/body_h7.bin.signed and b/panda/board/obj/body_h7.bin.signed differ diff --git a/panda/board/obj/body_h7/bootstub.elf b/panda/board/obj/body_h7/bootstub.elf index 014d0373..9bdd11ec 100755 Binary files a/panda/board/obj/body_h7/bootstub.elf and b/panda/board/obj/body_h7/bootstub.elf differ diff --git a/panda/board/obj/body_h7/main.bin b/panda/board/obj/body_h7/main.bin index 6c819f09..13afad54 100755 Binary files a/panda/board/obj/body_h7/main.bin and b/panda/board/obj/body_h7/main.bin differ diff --git a/panda/board/obj/body_h7/main.elf b/panda/board/obj/body_h7/main.elf index e565940b..faee7588 100755 Binary files a/panda/board/obj/body_h7/main.elf and b/panda/board/obj/body_h7/main.elf differ diff --git a/panda/board/obj/bootstub.body_h7.bin b/panda/board/obj/bootstub.body_h7.bin index cb3c3e9f..8f8dc686 100755 Binary files a/panda/board/obj/bootstub.body_h7.bin and b/panda/board/obj/bootstub.body_h7.bin differ diff --git a/panda/board/obj/bootstub.panda.bin b/panda/board/obj/bootstub.panda.bin index 9078a5b1..4e129a1b 100755 Binary files a/panda/board/obj/bootstub.panda.bin and b/panda/board/obj/bootstub.panda.bin differ diff --git a/panda/board/obj/bootstub.panda_h7.bin b/panda/board/obj/bootstub.panda_h7.bin index 1f4ee9a3..d42e08f2 100755 Binary files a/panda/board/obj/bootstub.panda_h7.bin and b/panda/board/obj/bootstub.panda_h7.bin differ diff --git a/panda/board/obj/bootstub.panda_h7_remote.bin b/panda/board/obj/bootstub.panda_h7_remote.bin index 1f4ee9a3..d42e08f2 100755 Binary files a/panda/board/obj/bootstub.panda_h7_remote.bin and b/panda/board/obj/bootstub.panda_h7_remote.bin differ diff --git a/panda/board/obj/bootstub.panda_jungle_h7.bin b/panda/board/obj/bootstub.panda_jungle_h7.bin index d523f5e4..4f8c37b1 100755 Binary files a/panda/board/obj/bootstub.panda_jungle_h7.bin and b/panda/board/obj/bootstub.panda_jungle_h7.bin differ diff --git a/panda/board/obj/bootstub.panda_remote.bin b/panda/board/obj/bootstub.panda_remote.bin index 9078a5b1..4e129a1b 100755 Binary files a/panda/board/obj/bootstub.panda_remote.bin and b/panda/board/obj/bootstub.panda_remote.bin differ diff --git a/panda/board/obj/gitversion.h b/panda/board/obj/gitversion.h index 1b357695..d04731af 100644 --- a/panda/board/obj/gitversion.h +++ b/panda/board/obj/gitversion.h @@ -1,2 +1,2 @@ extern const uint8_t gitversion[19]; -const uint8_t gitversion[19] = "DEV-9ec91aa7-DEBUG"; +const uint8_t gitversion[19] = "DEV-60a7fb11-DEBUG"; diff --git a/panda/board/obj/panda.bin.signed b/panda/board/obj/panda.bin.signed index 68f15e6b..0c650c2a 100644 Binary files a/panda/board/obj/panda.bin.signed and b/panda/board/obj/panda.bin.signed differ diff --git a/panda/board/obj/panda/bootstub.elf b/panda/board/obj/panda/bootstub.elf index 5e767e9b..06125f5b 100755 Binary files a/panda/board/obj/panda/bootstub.elf and b/panda/board/obj/panda/bootstub.elf differ diff --git a/panda/board/obj/panda/main.bin b/panda/board/obj/panda/main.bin index bb4ebcb7..75dd3ae9 100755 Binary files a/panda/board/obj/panda/main.bin and b/panda/board/obj/panda/main.bin differ diff --git a/panda/board/obj/panda/main.elf b/panda/board/obj/panda/main.elf index 4f55d117..fdff9927 100755 Binary files a/panda/board/obj/panda/main.elf and b/panda/board/obj/panda/main.elf differ diff --git a/panda/board/obj/panda_h7.bin.signed b/panda/board/obj/panda_h7.bin.signed index 57c57c0f..1e8e353f 100644 Binary files a/panda/board/obj/panda_h7.bin.signed and b/panda/board/obj/panda_h7.bin.signed differ diff --git a/panda/board/obj/panda_h7/bootstub.elf b/panda/board/obj/panda_h7/bootstub.elf index bbd4c743..40ad4d9f 100755 Binary files a/panda/board/obj/panda_h7/bootstub.elf and b/panda/board/obj/panda_h7/bootstub.elf differ diff --git a/panda/board/obj/panda_h7/main.bin b/panda/board/obj/panda_h7/main.bin index 967d2497..48fa8308 100755 Binary files a/panda/board/obj/panda_h7/main.bin and b/panda/board/obj/panda_h7/main.bin differ diff --git a/panda/board/obj/panda_h7/main.elf b/panda/board/obj/panda_h7/main.elf index 72319bec..4eeb2a64 100755 Binary files a/panda/board/obj/panda_h7/main.elf and b/panda/board/obj/panda_h7/main.elf differ diff --git a/panda/board/obj/panda_h7_remote.bin.signed b/panda/board/obj/panda_h7_remote.bin.signed index bc90b58f..29d819fb 100644 Binary files a/panda/board/obj/panda_h7_remote.bin.signed and b/panda/board/obj/panda_h7_remote.bin.signed differ diff --git a/panda/board/obj/panda_h7_remote/bootstub.elf b/panda/board/obj/panda_h7_remote/bootstub.elf index 551941cf..7aa4cab3 100755 Binary files a/panda/board/obj/panda_h7_remote/bootstub.elf and b/panda/board/obj/panda_h7_remote/bootstub.elf differ diff --git a/panda/board/obj/panda_h7_remote/main.bin b/panda/board/obj/panda_h7_remote/main.bin index 87ca956b..d78d074b 100755 Binary files a/panda/board/obj/panda_h7_remote/main.bin and b/panda/board/obj/panda_h7_remote/main.bin differ diff --git a/panda/board/obj/panda_h7_remote/main.elf b/panda/board/obj/panda_h7_remote/main.elf index d8f7b7e0..083bd177 100755 Binary files a/panda/board/obj/panda_h7_remote/main.elf and b/panda/board/obj/panda_h7_remote/main.elf differ diff --git a/panda/board/obj/panda_jungle_h7.bin.signed b/panda/board/obj/panda_jungle_h7.bin.signed index 4644f079..0c359998 100644 Binary files a/panda/board/obj/panda_jungle_h7.bin.signed and b/panda/board/obj/panda_jungle_h7.bin.signed differ diff --git a/panda/board/obj/panda_jungle_h7/bootstub.elf b/panda/board/obj/panda_jungle_h7/bootstub.elf index 2901c147..530d99d6 100755 Binary files a/panda/board/obj/panda_jungle_h7/bootstub.elf and b/panda/board/obj/panda_jungle_h7/bootstub.elf differ diff --git a/panda/board/obj/panda_jungle_h7/main.bin b/panda/board/obj/panda_jungle_h7/main.bin index 925708e6..9e1033bb 100755 Binary files a/panda/board/obj/panda_jungle_h7/main.bin and b/panda/board/obj/panda_jungle_h7/main.bin differ diff --git a/panda/board/obj/panda_jungle_h7/main.elf b/panda/board/obj/panda_jungle_h7/main.elf index 4ddeef4a..3dde733f 100755 Binary files a/panda/board/obj/panda_jungle_h7/main.elf and b/panda/board/obj/panda_jungle_h7/main.elf differ diff --git a/panda/board/obj/panda_remote.bin.signed b/panda/board/obj/panda_remote.bin.signed index 1c39f942..690cf937 100644 Binary files a/panda/board/obj/panda_remote.bin.signed and b/panda/board/obj/panda_remote.bin.signed differ diff --git a/panda/board/obj/panda_remote/bootstub.elf b/panda/board/obj/panda_remote/bootstub.elf index dba5facb..9bc68593 100755 Binary files a/panda/board/obj/panda_remote/bootstub.elf and b/panda/board/obj/panda_remote/bootstub.elf differ diff --git a/panda/board/obj/panda_remote/main.bin b/panda/board/obj/panda_remote/main.bin index 868c36b4..1b88b64e 100755 Binary files a/panda/board/obj/panda_remote/main.bin and b/panda/board/obj/panda_remote/main.bin differ diff --git a/panda/board/obj/panda_remote/main.elf b/panda/board/obj/panda_remote/main.elf index 92a2165a..6ca31b2c 100755 Binary files a/panda/board/obj/panda_remote/main.elf and b/panda/board/obj/panda_remote/main.elf differ diff --git a/panda/board/obj/version b/panda/board/obj/version index f809ae33..5c83ce11 100644 --- a/panda/board/obj/version +++ b/panda/board/obj/version @@ -1 +1 @@ -DEV-9ec91aa7-DEBUG \ No newline at end of file +DEV-60a7fb11-DEBUG \ No newline at end of file diff --git a/selfdrive/pandad/pandad b/selfdrive/pandad/pandad index e5c457c7..6664b04d 100755 Binary files a/selfdrive/pandad/pandad and b/selfdrive/pandad/pandad differ diff --git a/selfdrive/ui/ui b/selfdrive/ui/ui index 3d1e1d5d..2035f80e 100755 Binary files a/selfdrive/ui/ui and b/selfdrive/ui/ui differ diff --git a/system/camerad/camerad b/system/camerad/camerad index 8cbcc868..24bdfdb6 100755 Binary files a/system/camerad/camerad and b/system/camerad/camerad differ diff --git a/system/loggerd/bootlog b/system/loggerd/bootlog index a9896863..b61e2203 100755 Binary files a/system/loggerd/bootlog and b/system/loggerd/bootlog differ diff --git a/system/loggerd/encoderd b/system/loggerd/encoderd index 31a834ba..6db06a65 100755 Binary files a/system/loggerd/encoderd and b/system/loggerd/encoderd differ diff --git a/system/loggerd/loggerd b/system/loggerd/loggerd index 5146808a..aa9018cb 100755 Binary files a/system/loggerd/loggerd and b/system/loggerd/loggerd differ diff --git a/system/manager/manager.py b/system/manager/manager.py index 35f6b675..007e6ca1 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -250,6 +250,21 @@ def migrate_param_type_canonicalization(params: Params) -> None: cloudlog.exception(f"Failed to write migration flag: {STARPILOT_PARAM_CANONICALIZATION_MIGRATION_FLAG}") +def migrate_legacy_experimental_longitudinal(params: Params, params_cache: Params) -> None: + legacy_value = params.get("ExperimentalLongitudinalEnabled") + if legacy_value is None: + return + + if params.get("AlphaLongitudinalEnabled") is None: + alpha_long_enabled = params.get_bool("ExperimentalLongitudinalEnabled") + params.put_bool("AlphaLongitudinalEnabled", alpha_long_enabled) + params_cache.put_bool("AlphaLongitudinalEnabled", alpha_long_enabled) + cloudlog.warning("Migrated legacy ExperimentalLongitudinalEnabled to AlphaLongitudinalEnabled") + + params.remove("ExperimentalLongitudinalEnabled") + params_cache.remove("ExperimentalLongitudinalEnabled") + + def manager_init() -> None: save_bootlog() @@ -272,6 +287,9 @@ def manager_init() -> None: cache_params_path = os.path.join(Paths.comma_home(), "cache", "params") params_cache = Params(cache_params_path, return_defaults=True) + # Preserve StarPilot's legacy longitudinal toggle when switching branches. + migrate_legacy_experimental_longitudinal(params, params_cache) + # Canonicalize legacy string encodings (e.g. INT params stored as "26.000000") # before bulk reads below to avoid repeated cast warnings and UI-side churn. migrate_param_type_canonicalization(params) diff --git a/system/manager/test/test_manager.py b/system/manager/test/test_manager.py index 34d07c67..5eca7a9f 100644 --- a/system/manager/test/test_manager.py +++ b/system/manager/test/test_manager.py @@ -51,6 +51,40 @@ class TestManager: assert params.get("OpenpilotEnabledToggle") assert params.get("RouteCount") == 0 + def test_migrate_legacy_experimental_longitudinal(self): + class FakeParams: + def __init__(self, values): + self.values = dict(values) + + def get(self, key): + return self.values.get(key) + + def get_bool(self, key): + value = self.values.get(key) + if value is None: + return False + if isinstance(value, bytes): + value = value.decode("utf-8", errors="ignore") + if isinstance(value, str): + return value.strip().lower() in ("1", "true", "yes", "on") + return bool(value) + + def put_bool(self, key, value): + self.values[key] = b"1" if value else b"0" + + def remove(self, key): + self.values.pop(key, None) + + params = FakeParams({"ExperimentalLongitudinalEnabled": b"1"}) + params_cache = FakeParams({}) + + manager.migrate_legacy_experimental_longitudinal(params, params_cache) + + assert params.get_bool("AlphaLongitudinalEnabled") + assert params_cache.get_bool("AlphaLongitudinalEnabled") + assert params.get("ExperimentalLongitudinalEnabled") is None + assert params_cache.get("ExperimentalLongitudinalEnabled") is None + @pytest.mark.skip("this test is flaky the way it's currently written, should be moved to test_onroad") def test_clean_exit(self, subtests): """