From 05c2a90e16c6e8360ddb4704592bb61e53822b4f Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Fri, 19 Jun 2026 21:10:41 -0500 Subject: [PATCH] lacrosse --- opendbc_repo/opendbc/car/gm/carcontroller.py | 59 +++++++++++-------- opendbc_repo/opendbc/car/gm/interface.py | 3 + .../car/gm/tests/test_carcontroller.py | 11 ++++ opendbc_repo/opendbc/car/gm/tests/test_gm.py | 18 ++++++ opendbc_repo/opendbc/car/gm/values.py | 2 + opendbc_repo/opendbc/safety/modes/gm.h | 9 +++ opendbc_repo/opendbc/safety/tests/test_gm.py | 27 +++++++++ panda/board/obj/gitversion.h | 2 +- panda/board/obj/version | 2 +- 9 files changed, 105 insertions(+), 28 deletions(-) diff --git a/opendbc_repo/opendbc/car/gm/carcontroller.py b/opendbc_repo/opendbc/car/gm/carcontroller.py index f179512cd8..630288da25 100644 --- a/opendbc_repo/opendbc/car/gm/carcontroller.py +++ b/opendbc_repo/opendbc/car/gm/carcontroller.py @@ -149,6 +149,19 @@ def get_adas_keepalive_step(CP, is_kaofui_car): return None +def should_send_adas_status(CP, is_kaofui_car): + if CP.radarUnavailable: + return False + + if not is_kaofui_car: + return True + + if CP.carFingerprint in ASCM_INT: + return CP.carFingerprint == CAR.BUICK_LACROSSE_ASCM + + return CP.networkLocation != NetworkLocation.fwdCamera and CP.carFingerprint not in SDGM_CAR + + def get_testing_ground_1_brake_switch_bias(v_ego: float) -> int: return int(round(np.interp(v_ego, [0.0, 6.0, 15.0, 30.0], [40.0, 85.0, 130.0, 170.0]))) @@ -908,33 +921,27 @@ class CarController(CarControllerBase): # Radar needs to know current speed and yaw rate (50hz), # and that ADAS is alive (10hz) - if not self.CP.radarUnavailable: - send_adas = True + if should_send_adas_status(self.CP, self.CP.carFingerprint in kaofui_cars): + tt = self.frame * DT_CTRL if self.CP.carFingerprint in kaofui_cars: - if self.CP.carFingerprint not in ASCM_INT: - send_adas = (self.CP.networkLocation != NetworkLocation.fwdCamera) and (self.CP.carFingerprint not in SDGM_CAR) - - if send_adas: - tt = self.frame * DT_CTRL - if self.CP.carFingerprint in kaofui_cars: - time_and_headlights_step = 10 - speed_and_accelerometer_step = 2 - if self.frame % time_and_headlights_step == 0: - idx = (self.frame // time_and_headlights_step) % 4 - can_sends.append(gmcan.create_adas_time_status(CanBus.OBSTACLE, int((tt - self.start_time) * 60), idx)) - can_sends.append(gmcan.create_adas_headlights_status(self.packer_obj, CanBus.OBSTACLE)) - if self.frame % speed_and_accelerometer_step == 0: - idx = (self.frame // speed_and_accelerometer_step) % 4 - can_sends.append(gmcan.create_adas_steering_status(CanBus.OBSTACLE, idx)) - can_sends.append(gmcan.create_adas_accelerometer_speed_status(CanBus.OBSTACLE, CS.out.vEgo, idx)) - else: - time_and_headlights_step = 20 - if self.frame % time_and_headlights_step == 0: - idx = (self.frame // time_and_headlights_step) % 4 - can_sends.append(gmcan.create_adas_time_status(CanBus.OBSTACLE, int((tt - self.start_time) * 60), idx)) - can_sends.append(gmcan.create_adas_headlights_status(self.packer_obj, CanBus.OBSTACLE)) - can_sends.append(gmcan.create_adas_steering_status(CanBus.OBSTACLE, idx)) - can_sends.append(gmcan.create_adas_accelerometer_speed_status(CanBus.OBSTACLE, CS.out.vEgo, idx)) + time_and_headlights_step = 10 + speed_and_accelerometer_step = 2 + if self.frame % time_and_headlights_step == 0: + idx = (self.frame // time_and_headlights_step) % 4 + can_sends.append(gmcan.create_adas_time_status(CanBus.OBSTACLE, int((tt - self.start_time) * 60), idx)) + can_sends.append(gmcan.create_adas_headlights_status(self.packer_obj, CanBus.OBSTACLE)) + if self.frame % speed_and_accelerometer_step == 0: + idx = (self.frame // speed_and_accelerometer_step) % 4 + can_sends.append(gmcan.create_adas_steering_status(CanBus.OBSTACLE, idx)) + can_sends.append(gmcan.create_adas_accelerometer_speed_status(CanBus.OBSTACLE, CS.out.vEgo, idx)) + else: + time_and_headlights_step = 20 + if self.frame % time_and_headlights_step == 0: + idx = (self.frame // time_and_headlights_step) % 4 + can_sends.append(gmcan.create_adas_time_status(CanBus.OBSTACLE, int((tt - self.start_time) * 60), idx)) + can_sends.append(gmcan.create_adas_headlights_status(self.packer_obj, CanBus.OBSTACLE)) + can_sends.append(gmcan.create_adas_steering_status(CanBus.OBSTACLE, idx)) + can_sends.append(gmcan.create_adas_accelerometer_speed_status(CanBus.OBSTACLE, CS.out.vEgo, idx)) keepalive_step = get_adas_keepalive_step(self.CP, self.CP.carFingerprint in kaofui_cars) if keepalive_step is not None and self.frame % keepalive_step == 0: diff --git a/opendbc_repo/opendbc/car/gm/interface.py b/opendbc_repo/opendbc/car/gm/interface.py index 502d1637bf..44d9f11430 100755 --- a/opendbc_repo/opendbc/car/gm/interface.py +++ b/opendbc_repo/opendbc/car/gm/interface.py @@ -675,6 +675,9 @@ class CarInterface(CarInterfaceBase): if remote_start_boots_comma: ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_REMOTE_START_BOOTS_COMMA.value + if candidate == CAR.BUICK_LACROSSE_ASCM: + ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_LACROSSE_RADAR.value + volt_stock_friction_brake_safety = ( (gm_auto_hold or volt_one_pedal_mode) and candidate in { diff --git a/opendbc_repo/opendbc/car/gm/tests/test_carcontroller.py b/opendbc_repo/opendbc/car/gm/tests/test_carcontroller.py index 0460ebb62a..8fd423959d 100644 --- a/opendbc_repo/opendbc/car/gm/tests/test_carcontroller.py +++ b/opendbc_repo/opendbc/car/gm/tests/test_carcontroller.py @@ -47,6 +47,7 @@ from opendbc.car.gm.carcontroller import ( should_activate_auto_hold, should_activate_volt_one_pedal, should_neutralize_volt_long_on_driver_override, + should_send_adas_status, should_send_stock_long_cancel, should_spoof_dash_speed, should_spoof_ecm_cruise_status, @@ -153,6 +154,16 @@ def test_live_camera_path_does_not_send_pt_keepalive(): assert get_adas_keepalive_step(cp, is_kaofui_car=True) is None +def test_only_lacrosse_ascm_int_sends_radar_status(): + common = { + "networkLocation": CarParams.NetworkLocation.fwdCamera, + "radarUnavailable": False, + } + + assert should_send_adas_status(SimpleNamespace(carFingerprint=CAR.BUICK_LACROSSE_ASCM, **common), is_kaofui_car=True) + assert not should_send_adas_status(SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_ASCM, **common), is_kaofui_car=True) + + def test_volt_auto_hold_requires_toggle_supported_non_cc_only_volt_and_stock_safety(): stock_safety = [SimpleNamespace(safetyParam=0x8000)] no_safety = [SimpleNamespace(safetyParam=0)] diff --git a/opendbc_repo/opendbc/car/gm/tests/test_gm.py b/opendbc_repo/opendbc/car/gm/tests/test_gm.py index 285f5a934c..11026e550c 100644 --- a/opendbc_repo/opendbc/car/gm/tests/test_gm.py +++ b/opendbc_repo/opendbc/car/gm/tests/test_gm.py @@ -139,6 +139,24 @@ class TestGMInterface: assert list(car_params.longitudinalTuning.kiBP) == pytest.approx([0.0, 5.0, 15.0, 35.0]) assert list(car_params.longitudinalTuning.kiV) == pytest.approx([0.28, 0.26, 0.20, 0.16]) + def test_lacrosse_radar_marker_is_not_set_on_volt_ascm(self): + fingerprint = _empty_fingerprint() + fingerprint[0][0x2FF] = 8 + + LacrosseInterface = interfaces[CAR.BUICK_LACROSSE_ASCM] + lacrosse_params = LacrosseInterface.get_params( + CAR.BUICK_LACROSSE_ASCM, fingerprint, [], alpha_long=True, is_release=False, docs=False, + starpilot_toggles=_test_starpilot_toggles(), + ) + VoltInterface = interfaces[CAR.CHEVROLET_VOLT_ASCM] + volt_params = VoltInterface.get_params( + CAR.CHEVROLET_VOLT_ASCM, fingerprint, [], alpha_long=True, is_release=False, docs=False, + starpilot_toggles=_test_starpilot_toggles(), + ) + + assert lacrosse_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_LACROSSE_RADAR.value + assert not volt_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_LACROSSE_RADAR.value + def test_blazer_uses_earlier_stronger_low_speed_stop_tune(self): CarInterface = interfaces[CAR.CHEVROLET_BLAZER] fingerprint = _empty_fingerprint() diff --git a/opendbc_repo/opendbc/car/gm/values.py b/opendbc_repo/opendbc/car/gm/values.py index 9f4a3970fc..99efe68011 100644 --- a/opendbc_repo/opendbc/car/gm/values.py +++ b/opendbc_repo/opendbc/car/gm/values.py @@ -174,6 +174,8 @@ class GMSafetyFlags(IntFlag): FLAG_GM_BOLT_2022_PEDAL = 4096 FLAG_GM_REMOTE_START_BOOTS_COMMA = 8192 FLAG_GM_PANDA_3D1_SCHED = 16384 + # Context-specific alias: the 3D1 scheduler remains inactive on this camera-long ACC path. + FLAG_GM_LACROSSE_RADAR = 16384 FLAG_GM_PANDA_PADDLE_SCHED = 32768 diff --git a/opendbc_repo/opendbc/safety/modes/gm.h b/opendbc_repo/opendbc/safety/modes/gm.h index f365f91669..d41e2b0c17 100644 --- a/opendbc_repo/opendbc/safety/modes/gm.h +++ b/opendbc_repo/opendbc/safety/modes/gm.h @@ -545,6 +545,7 @@ static safety_config gm_init(uint16_t param) { const uint16_t GM_PARAM_BOLT_2022_PEDAL = 4096; const uint16_t GM_PARAM_REMOTE_START_BOOTS_COMMA = 8192; const uint16_t GM_PARAM_PANDA_3D1_SCHED = 16384; + const uint16_t GM_PARAM_LACROSSE_RADAR = 16384; const uint16_t GM_PARAM_PANDA_PADDLE_SCHED = 32768; static const LongitudinalLimits GM_ASCM_LONG_LIMITS = { @@ -581,6 +582,11 @@ static safety_config gm_init(uint16_t param) { {0x184, 2, 8, .check_relay = true}, // camera bus {0x200, 0, 6, .check_relay = false}, {0x1E1, 0, 7, .check_relay = false}, {0xBD, 0, 7, .check_relay = false}, {0x1F5, 0, 8, .check_relay = false}}; // pt bus + static const CanMsg GM_CAM_LONG_LACROSSE_RADAR_TX_MSGS[] = {{0x180, 0, 4, .check_relay = true}, {0x315, 0, 5, .check_relay = true}, {0x2CB, 0, 8, .check_relay = true}, {0x370, 0, 6, .check_relay = true}, {0x3D1, 0, 8, .check_relay = false}, // pt bus + {0xA1, 1, 7, .check_relay = false}, {0x306, 1, 8, .check_relay = false}, {0x308, 1, 7, .check_relay = false}, {0x310, 1, 2, .check_relay = false}, // obs bus + {0x184, 2, 8, .check_relay = true}, // camera bus + {0x200, 0, 6, .check_relay = false}, {0x1E1, 0, 7, .check_relay = false}, + {0xBD, 0, 7, .check_relay = false}, {0x1F5, 0, 8, .check_relay = false}}; // pt bus static const CanMsg GM_CAM_LONG_NO_CAMERA_TX_MSGS[] = {{0x180, 0, 4, .check_relay = false}, {0x315, 0, 5, .check_relay = false}, {0x2CB, 0, 8, .check_relay = false}, {0x370, 0, 6, .check_relay = false}, {0x3D1, 0, 8, .check_relay = false}, // pt bus {0x409, 0, 7, .check_relay = false}, {0x40A, 0, 7, .check_relay = false}, @@ -727,6 +733,7 @@ static safety_config gm_init(uint16_t param) { gm_zero_u8(gm_prndl2_state.spoof_data, 8U); gm_cam_long = GET_FLAG(param, GM_PARAM_HW_CAM_LONG) && !gm_cc_long; + const bool gm_lacrosse_radar = GET_FLAG(param, GM_PARAM_LACROSSE_RADAR) && gm_ascm_int && gm_cam_long; gm_pcm_cruise = (gm_hw == GM_CAM || gm_sdgm) && !gm_cam_long && !gm_force_ascm && !gm_pedal_long; const bool gm_ascm_int_stock_cam = gm_ascm_int && (gm_hw == GM_CAM) && gm_pcm_cruise && !gm_cam_long && !gm_pedal_long && !gm_cc_long; const bool gm_ascm_int_no_accel_pos = gm_ascm_int && (gm_hw == GM_CAM) && gm_force_brake_c9; @@ -760,6 +767,8 @@ static safety_config gm_init(uint16_t param) { } else if (gm_cam_long) { if (gm_no_camera) { ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_LONG_NO_CAMERA_TX_MSGS); + } else if (gm_lacrosse_radar) { + ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_LONG_LACROSSE_RADAR_TX_MSGS); } else { ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_LONG_TX_MSGS); } diff --git a/opendbc_repo/opendbc/safety/tests/test_gm.py b/opendbc_repo/opendbc/safety/tests/test_gm.py index b0fb7a6dac..b57cede7a6 100755 --- a/opendbc_repo/opendbc/safety/tests/test_gm.py +++ b/opendbc_repo/opendbc/safety/tests/test_gm.py @@ -307,6 +307,33 @@ def test_gm_ascm_int_long_no_accel_pos_uses_stock_cam_rx_checks(): assert safety.safety_config_valid() +def test_lacrosse_radar_status_tx_requires_dedicated_camera_long_marker(): + safety = libsafety_py.libsafety + radar_status_msgs = ( + (0xA1, 7), + (0x306, 8), + (0x308, 7), + (0x310, 2), + ) + ascm_int_long = GMSafetyFlags.HW_CAM | GMSafetyFlags.HW_CAM_LONG | GMSafetyFlags.HW_ASCM_INT + + safety.set_safety_hooks(CarParams.SafetyModel.gm, ascm_int_long) + safety.init_tests() + for addr, length in radar_status_msgs: + assert not safety.safety_tx_hook(common.make_msg(1, addr, length)) + + safety.set_safety_hooks(CarParams.SafetyModel.gm, ascm_int_long | GMSafetyFlags.FLAG_GM_LACROSSE_RADAR) + safety.init_tests() + for addr, length in radar_status_msgs: + assert safety.safety_tx_hook(common.make_msg(1, addr, length)) + + volt_sdgm_long = GMSafetyFlags.HW_CAM | GMSafetyFlags.HW_CAM_LONG | GMSafetyFlags.HW_SDGM + safety.set_safety_hooks(CarParams.SafetyModel.gm, volt_sdgm_long) + safety.init_tests() + for addr, length in radar_status_msgs: + assert not safety.safety_tx_hook(common.make_msg(1, addr, length)) + + class TestGmCameraEVSafety(GmCameraAccEVRegenMixin, TestGmCameraSafety, TestGmEVSafetyBase): pass diff --git a/panda/board/obj/gitversion.h b/panda/board/obj/gitversion.h index d2f9a0dc89..4071002e2d 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-2c2d8b86-DEBUG"; +const uint8_t gitversion[19] = "DEV-dc581f63-DEBUG"; diff --git a/panda/board/obj/version b/panda/board/obj/version index da8cada02b..848cbbb670 100644 --- a/panda/board/obj/version +++ b/panda/board/obj/version @@ -1 +1 @@ -DEV-2c2d8b86-DEBUG \ No newline at end of file +DEV-dc581f63-DEBUG \ No newline at end of file