From 63490fe5e69980196f56d94e7767448c15bd1df4 Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Sat, 20 Jun 2026 01:23:43 -0500 Subject: [PATCH] one pedal update --- opendbc_repo/opendbc/car/gm/interface.py | 15 +++++++++ opendbc_repo/opendbc/car/gm/tests/test_gm.py | 1 + opendbc_repo/opendbc/safety/modes/gm.h | 17 +++++++--- opendbc_repo/opendbc/safety/tests/test_gm.py | 35 ++++++++++++++++++++ 4 files changed, 63 insertions(+), 5 deletions(-) diff --git a/opendbc_repo/opendbc/car/gm/interface.py b/opendbc_repo/opendbc/car/gm/interface.py index 502d1637bf..6ab9fe5257 100755 --- a/opendbc_repo/opendbc/car/gm/interface.py +++ b/opendbc_repo/opendbc/car/gm/interface.py @@ -691,6 +691,21 @@ class CarInterface(CarInterfaceBase): # be present regardless of the current long-control mode. ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value + volt_stock_one_pedal_safety = ( + volt_one_pedal_mode and + candidate in { + CAR.CHEVROLET_VOLT, + CAR.CHEVROLET_VOLT_2019, + CAR.CHEVROLET_VOLT_ASCM, + CAR.CHEVROLET_VOLT_CAMERA, + } + ) + if volt_stock_one_pedal_safety: + # Reuse the 3D1 scheduler bit as a Volt one-pedal marker on non-pedal + # ACC paths. The bit is ignored by the actual 3D1 scheduler unless the + # car is on a pedal-long CC-only path, so this stays isolated from Bolt. + ret.safetyConfigs[0].safetyParam |= GMSafetyFlags.FLAG_GM_PANDA_3D1_SCHED.value + use_panda_3d1_sched = ( ret.openpilotLongitudinalControl and ret.enableGasInterceptorDEPRECATED and diff --git a/opendbc_repo/opendbc/car/gm/tests/test_gm.py b/opendbc_repo/opendbc/car/gm/tests/test_gm.py index da31a018be..bb1b70e225 100644 --- a/opendbc_repo/opendbc/car/gm/tests/test_gm.py +++ b/opendbc_repo/opendbc/car/gm/tests/test_gm.py @@ -203,6 +203,7 @@ class TestGMInterface: assert car_params.openpilotLongitudinalControl assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED.value + assert car_params.safetyConfigs[0].safetyParam & GMSafetyFlags.FLAG_GM_PANDA_3D1_SCHED.value @parameterized.expand(VOLT_CARS) def test_volt_bsm_is_enabled_without_fingerprint_match(self, car_model): diff --git a/opendbc_repo/opendbc/safety/modes/gm.h b/opendbc_repo/opendbc/safety/modes/gm.h index f365f91669..5976fb6fc9 100644 --- a/opendbc_repo/opendbc/safety/modes/gm.h +++ b/opendbc_repo/opendbc/safety/modes/gm.h @@ -61,6 +61,7 @@ static bool gm_panda_paddle_sched = false; static bool gm_bolt_2022_pedal = false; static bool gm_alt_brake = false; static bool gm_volt_auto_hold = false; +static bool gm_volt_one_pedal = false; static bool gm_cc_long = false; static bool gm_has_acc = true; @@ -366,8 +367,9 @@ static bool gm_tx_hook(const CANPacket_t *msg) { int brake = ((msg->data[0] & 0xFU) << 8) + msg->data[1]; brake = (0x1000 - brake) & 0xFFF; bool stock_auto_hold_brake_allowed = gm_volt_auto_hold && !vehicle_moving && !gas_pressed_prev; + bool stock_one_pedal_brake_allowed = gm_volt_one_pedal && acc_main_on && !gas_pressed_prev && !brake_pressed; bool violation = false; - violation |= !(get_longitudinal_allowed() || stock_auto_hold_brake_allowed) && (brake != 0); + violation |= !(get_longitudinal_allowed() || stock_auto_hold_brake_allowed || stock_one_pedal_brake_allowed) && (brake != 0); if (stock_auto_hold_brake_allowed && !get_longitudinal_allowed()) { violation |= brake > GM_VOLT_AUTO_HOLD_MAX_BRAKE; } else { @@ -699,6 +701,10 @@ static safety_config gm_init(uint16_t param) { gm_panda_paddle_sched = GET_FLAG(param, GM_PARAM_PANDA_PADDLE_SCHED) && gm_pedal_long && enable_gas_interceptor; // Reuse the paddle-scheduler bit as a stock-Volt auto-hold marker on non-pedal ACC paths. gm_volt_auto_hold = GET_FLAG(param, GM_PARAM_PANDA_PADDLE_SCHED) && !gm_pedal_long && !gm_cc_long && gm_has_acc; + // Reuse the 3D1 scheduler bit as a stock-Volt one-pedal marker on non-pedal + // ACC paths. The actual 3D1 scheduler still requires pedal-long and no-ACC, + // so this stays isolated from the Bolt pedal path. + gm_volt_one_pedal = GET_FLAG(param, GM_PARAM_PANDA_3D1_SCHED) && !gm_pedal_long && !gm_cc_long && gm_has_acc; gm_alt_brake = GET_FLAG(param, GM_PARAM_NO_CAMERA) && (gm_hw == GM_ASCM) && !gm_sdgm && !gm_ascm_int; gm_3d1_spoof_valid = false; @@ -740,9 +746,10 @@ static safety_config gm_init(uint16_t param) { safety_config ret; const bool gm_sdgm_stock = gm_sdgm && !gm_cc_long && !gm_cam_long && !gm_no_camera; + const bool gm_volt_stock_brake = gm_volt_auto_hold || gm_volt_one_pedal; // SDGM behaves like a forwarding camera path for whitelist/forwarding purposes. if (gm_sdgm_stock) { - if (gm_volt_auto_hold) { + if (gm_volt_stock_brake) { ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_SDGM_VOLT_AUTO_HOLD_TX_MSGS); } else { ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_SDGM_TX_MSGS); @@ -764,16 +771,16 @@ static safety_config gm_init(uint16_t param) { ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_LONG_TX_MSGS); } } else { - if (gm_volt_auto_hold && gm_sdgm) { + if (gm_volt_stock_brake && gm_sdgm) { ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_SDGM_VOLT_AUTO_HOLD_TX_MSGS); } else if (gm_no_camera) { - if (gm_volt_auto_hold) { + if (gm_volt_stock_brake) { ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_NO_CAMERA_VOLT_AUTO_HOLD_TX_MSGS); } else { ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_NO_CAMERA_TX_MSGS); } } else { - if (gm_volt_auto_hold) { + if (gm_volt_stock_brake) { ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_VOLT_AUTO_HOLD_TX_MSGS); } else { ret = BUILD_SAFETY_CFG(gm_rx_checks, GM_CAM_TX_MSGS); diff --git a/opendbc_repo/opendbc/safety/tests/test_gm.py b/opendbc_repo/opendbc/safety/tests/test_gm.py index b6418726f1..3cfcee19ee 100755 --- a/opendbc_repo/opendbc/safety/tests/test_gm.py +++ b/opendbc_repo/opendbc/safety/tests/test_gm.py @@ -585,6 +585,41 @@ class TestGmVoltAutoHoldCameraSafety(TestGmCameraSafetyBase): self.assertFalse(self._tx(self._send_brake_msg(100))) +class TestGmVoltOnePedalCameraSafety(TestGmCameraSafetyBase): + TX_MSGS = TestGmCameraSafety.TX_MSGS + [[0x315, 0]] + EXTRA_SAFETY_PARAM = GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED | GMSafetyFlags.FLAG_GM_PANDA_3D1_SCHED + + def setUp(self): + self.packer = CANPackerSafety("gm_global_a_powertrain_generated") + self.packer_chassis = CANPackerSafety("gm_global_a_chassis") + self.safety = libsafety_py.libsafety + self.safety.set_safety_hooks(CarParams.SafetyModel.gm, GMSafetyFlags.HW_CAM | self.EXTRA_SAFETY_PARAM) + self.safety.init_tests() + + def _send_brake_msg(self, brake): + values = {"FrictionBrakeCmd": -brake} + return self.packer_chassis.make_can_msg_safety("EBCMFrictionBrakeCmd", 0, values) + + def test_moving_brake_allowed_without_controls_when_main_on(self): + self._rx(self._speed_msg(self.STANDSTILL_THRESHOLD + 1)) + self._rx(self._toggle_aol(True)) + self.safety.set_controls_allowed(False) + self.assertTrue(self._tx(self._send_brake_msg(100))) + + def test_moving_brake_blocked_without_main_on(self): + self._rx(self._speed_msg(self.STANDSTILL_THRESHOLD + 1)) + self._rx(self._toggle_aol(False)) + self.safety.set_controls_allowed(False) + self.assertFalse(self._tx(self._send_brake_msg(100))) + + def test_gas_blocks_moving_brake_without_controls(self): + self._rx(self._speed_msg(self.STANDSTILL_THRESHOLD + 1)) + self._rx(self._toggle_aol(True)) + self._rx(self._user_gas_msg(True)) + self.safety.set_controls_allowed(False) + self.assertFalse(self._tx(self._send_brake_msg(100))) + + class TestGmVoltAutoHoldSdgmSafety(TestGmSafetyBase): TX_MSGS = TestGmSdgmSafety.TX_MSGS + [[0x315, 2]] EXTRA_SAFETY_PARAM = GMSafetyFlags.FLAG_GM_PANDA_PADDLE_SCHED