diff --git a/common/params.cc b/common/params.cc index 15d941353..e5adbbc75 100644 --- a/common/params.cc +++ b/common/params.cc @@ -249,6 +249,7 @@ std::unordered_map keys = { {"DecelerationProfile", PERSISTENT}, {"DeviceManagement", PERSISTENT}, {"DeviceShutdown", PERSISTENT}, + {"DisableOpenpilotLongitudinal", PERSISTENT}, {"DisengageVolume", PERSISTENT}, {"DynamicPathWidth", PERSISTENT}, {"EngageVolume", PERSISTENT}, @@ -257,6 +258,7 @@ std::unordered_map keys = { {"GoatScream", PERSISTENT}, {"HideAOLStatusBar", PERSISTENT}, {"HideCEMStatusBar", PERSISTENT}, + {"HideDisableOpenpilotLongitudinal", PERSISTENT}, {"HideLeadMarker", PERSISTENT}, {"IncreaseThermalLimits", PERSISTENT}, {"LaneLinesWidth", PERSISTENT}, diff --git a/selfdrive/car/body/interface.py b/selfdrive/car/body/interface.py index 97a56d4d1..fe71b5353 100644 --- a/selfdrive/car/body/interface.py +++ b/selfdrive/car/body/interface.py @@ -7,7 +7,7 @@ from openpilot.selfdrive.car.body.values import SPEED_FROM_RPM class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret, params, candidate, fingerprint, car_fw, disable_openpilot_long, experimental_long, docs): ret.notCar = True ret.carName = "body" ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.body)] diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index c557963b3..1d99cc33f 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -199,7 +199,7 @@ def get_car_interface(CP): return CarInterface(CP, CarController, CarState) -def get_car(params, logcan, sendcan, experimental_long_allowed, num_pandas=1): +def get_car(params, logcan, sendcan, disable_openpilot_long, experimental_long_allowed, num_pandas=1): candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan, num_pandas) if candidate is None: @@ -211,7 +211,7 @@ def get_car(params, logcan, sendcan, experimental_long_allowed, num_pandas=1): candidate = "mock" CarInterface, _, _ = interfaces[candidate] - CP = CarInterface.get_params(params, candidate, fingerprints, car_fw, experimental_long_allowed, docs=False) + CP = CarInterface.get_params(params, candidate, fingerprints, car_fw, disable_openpilot_long, experimental_long_allowed, docs=False) CP.carVin = vin CP.carFw = car_fw CP.fingerprintSource = source diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index c858f4de2..82ae8110a 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -43,8 +43,9 @@ class CarD: get_one_can(self.can_sock) num_pandas = len(messaging.recv_one_retry(self.sm.sock['pandaStates']).pandaStates) - experimental_long_allowed = self.params.get_bool("ExperimentalLongitudinalEnabled") - self.CI, self.CP = get_car(self.params, self.can_sock, self.pm.sock['sendcan'], experimental_long_allowed, num_pandas) + disable_openpilot_long = self.params.get_bool("DisableOpenpilotLongitudinal") + experimental_long_allowed = not disable_openpilot_long and self.params.get_bool("ExperimentalLongitudinalEnabled") + self.CI, self.CP = get_car(self.params, self.can_sock, self.pm.sock['sendcan'], disable_openpilot_long, experimental_long_allowed, num_pandas) else: self.CI, self.CP = CI, CI.CP diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index bd1e9c1fa..d2d6dd381 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -11,7 +11,7 @@ FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret, params, candidate, fingerprint, car_fw, disable_openpilot_long, experimental_long, docs): ret.carName = "chrysler" ret.dashcamOnly = candidate in RAM_HD diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index cd3e6a135..37b8b105e 100644 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -14,7 +14,7 @@ FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret, params, candidate, fingerprint, car_fw, disable_openpilot_long, experimental_long, docs): ret.carName = "ford" ret.dashcamOnly = bool(ret.flags & FordFlags.CANFD) diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index fda6b4080..dbbbed2d5 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -89,7 +89,9 @@ class CarInterface(CarInterfaceBase): return self.torque_from_lateral_accel_linear @staticmethod - def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret, params, candidate, fingerprint, car_fw, disable_openpilot_long, experimental_long, docs): + params.put_bool("HideDisableOpenpilotLongitudinal", candidate not in (SDGM_CAR | CAMERA_ACC_CAR)) + ret.carName = "gm" ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.gm)] ret.autoResumeSng = False @@ -241,7 +243,7 @@ class CarInterface(CarInterfaceBase): ret.radarUnavailable = True ret.experimentalLongitudinalAvailable = False ret.minEnableSpeed = 24 * CV.MPH_TO_MS - ret.openpilotLongitudinalControl = True + ret.openpilotLongitudinalControl = not disable_openpilot_long ret.pcmCruise = False ret.longitudinalTuning.deadzoneBP = [0.] diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index e58201257..04bc90df2 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -41,7 +41,7 @@ class CarInterface(CarInterfaceBase): return CarControllerParams.NIDEC_ACCEL_MIN, interp(current_speed, ACCEL_MAX_BP, ACCEL_MAX_VALS) @staticmethod - def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret, params, candidate, fingerprint, car_fw, disable_openpilot_long, experimental_long, docs): ret.carName = "honda" CAN = CanBus(ret, fingerprint) @@ -58,7 +58,7 @@ class CarInterface(CarInterfaceBase): else: ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hondaNidec)] ret.enableGasInterceptor = 0x201 in fingerprint[CAN.pt] - ret.openpilotLongitudinalControl = True + ret.openpilotLongitudinalControl = not disable_openpilot_long ret.pcmCruise = not ret.enableGasInterceptor diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index b0815f272..8f0bc2e16 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -20,7 +20,7 @@ FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret, params, candidate, fingerprint, car_fw, disable_openpilot_long, experimental_long, docs): ret.carName = "hyundai" ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or DBC[ret.carFingerprint]["radar"] is None diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index f18ef83e2..d15be6e5e 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -120,10 +120,10 @@ class CarInterfaceBase(ABC): """ Parameters essential to controlling the car may be incomplete or wrong without FW versions or fingerprints. """ - return cls.get_params(candidate, gen_empty_fingerprint(), list(), False, False) + return cls.get_params(candidate, gen_empty_fingerprint(), list(), False, False, False) @classmethod - def get_params(cls, params, candidate: str, fingerprint: dict[int, dict[int, int]], car_fw: list[car.CarParams.CarFw], experimental_long: bool, docs: bool): + def get_params(cls, params, candidate: str, fingerprint: dict[int, dict[int, int]], car_fw: list[car.CarParams.CarFw], disable_openpilot_long: bool, experimental_long: bool, docs: bool): ret = CarInterfaceBase.get_std_params(candidate) platform = PLATFORMS[candidate] @@ -136,7 +136,7 @@ class CarInterfaceBase(ABC): ret.tireStiffnessFactor = platform.config.specs.tireStiffnessFactor ret.flags |= int(platform.config.flags) - ret = cls._get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs) + ret = cls._get_params(ret, params, candidate, fingerprint, car_fw, disable_openpilot_long, experimental_long, docs) # Vehicle mass is published curb weight plus assumed payload such as a human driver; notCars have no assumed payload if not ret.notCar: diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py index 05ced8ad1..a09a140f6 100755 --- a/selfdrive/car/mazda/interface.py +++ b/selfdrive/car/mazda/interface.py @@ -12,7 +12,7 @@ FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret, params, candidate, fingerprint, car_fw, disable_openpilot_long, experimental_long, docs): ret.carName = "mazda" ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.mazda)] ret.radarUnavailable = True diff --git a/selfdrive/car/mock/interface.py b/selfdrive/car/mock/interface.py index 90aa3beb3..7368f1ab2 100755 --- a/selfdrive/car/mock/interface.py +++ b/selfdrive/car/mock/interface.py @@ -12,7 +12,7 @@ class CarInterface(CarInterfaceBase): self.sm = messaging.SubMaster(['gpsLocation', 'gpsLocationExternal']) @staticmethod - def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret, params, candidate, fingerprint, car_fw, disable_openpilot_long, experimental_long, docs): ret.carName = "mock" ret.mass = 1700. ret.wheelbase = 2.70 diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py index 0c63aebaa..1d21c36ad 100644 --- a/selfdrive/car/nissan/interface.py +++ b/selfdrive/car/nissan/interface.py @@ -11,7 +11,7 @@ FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret, params, candidate, fingerprint, car_fw, disable_openpilot_long, experimental_long, docs): ret.carName = "nissan" ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.nissan)] ret.autoResumeSng = False diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index ea14169e6..acba1ab8f 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -10,7 +10,7 @@ FrogPilotButtonType = custom.FrogPilotCarState.ButtonEvent.Type class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, params, candidate: CAR, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret, params, candidate: CAR, fingerprint, car_fw, disable_openpilot_long, experimental_long, docs): ret.carName = "subaru" ret.radarUnavailable = True # for HYBRID CARS to be upstreamed, we need: diff --git a/selfdrive/car/tesla/interface.py b/selfdrive/car/tesla/interface.py index 374a3e317..74bb61a29 100755 --- a/selfdrive/car/tesla/interface.py +++ b/selfdrive/car/tesla/interface.py @@ -8,7 +8,7 @@ from openpilot.selfdrive.car.interfaces import CarInterfaceBase class CarInterface(CarInterfaceBase): @staticmethod - def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret, params, candidate, fingerprint, car_fw, disable_openpilot_long, experimental_long, docs): ret.carName = "tesla" # There is no safe way to do steer blending with user torque, @@ -30,7 +30,7 @@ class CarInterface(CarInterfaceBase): # If so, we assume that it is connected to the longitudinal harness. flags = (Panda.FLAG_TESLA_RAVEN if candidate == CAR.MODELS_RAVEN else 0) if (CANBUS.autopilot_powertrain in fingerprint.keys()) and (0x2bf in fingerprint[CANBUS.autopilot_powertrain].keys()): - ret.openpilotLongitudinalControl = True + ret.openpilotLongitudinalControl = not disable_openpilot_long flags |= Panda.FLAG_TESLA_LONG_CONTROL ret.safetyConfigs = [ get_safety_config(car.CarParams.SafetyModel.tesla, flags), diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 9c40b5ce6..b45e5353b 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -22,7 +22,7 @@ class CarInterface(CarInterfaceBase): return CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX @staticmethod - def _get_params(ret, params, candidate, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret, params, candidate, fingerprint, car_fw, disable_openpilot_long, experimental_long, docs): ret.carName = "toyota" ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.toyota)] ret.safetyConfigs[0].safetyParam = EPS_SCALE[candidate] @@ -136,6 +136,7 @@ class CarInterface(CarInterfaceBase): # - TSS2 radar ACC cars w/o smartDSU installed (disables radar) # - TSS-P DSU-less cars w/ CAN filter installed (no radar parser yet) ret.openpilotLongitudinalControl = use_sdsu or ret.enableDsu or candidate in (TSS2_CAR - RADAR_ACC_CAR) or bool(ret.flags & ToyotaFlags.DISABLE_RADAR.value) + ret.openpilotLongitudinalControl &= not disable_openpilot_long ret.autoResumeSng = ret.openpilotLongitudinalControl and candidate in NO_STOP_TIMER_CAR ret.enableGasInterceptor = 0x201 in fingerprint[0] and ret.openpilotLongitudinalControl diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index e9d5f145f..9b9f4e06a 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -22,7 +22,7 @@ class CarInterface(CarInterfaceBase): self.eps_timer_soft_disable_alert = False @staticmethod - def _get_params(ret, params, candidate: CAR, fingerprint, car_fw, experimental_long, docs): + def _get_params(ret, params, candidate: CAR, fingerprint, car_fw, disable_openpilot_long, experimental_long, docs): ret.carName = "volkswagen" ret.radarUnavailable = True diff --git a/selfdrive/frogpilot/ui/qt/offroad/control_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/control_settings.cc index 9beb4ffc7..1403cc655 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/control_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/control_settings.cc @@ -289,6 +289,8 @@ FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPil } void FrogPilotControlsPanel::showEvent(QShowEvent *event, const UIState &s) { + hasOpenpilotLongitudinal = hasOpenpilotLongitudinal && !params.getBool("DisableOpenpilotLongitudinal"); + online = s.scene.online; bool parked = s.scene.parked; started = s.scene.started; diff --git a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc index c31457801..fdcbcda9a 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc @@ -1,6 +1,25 @@ #include "selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h" FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) { + bool disableOpenpilotLongState = params.getBool("DisableOpenpilotLongitudinal"); + disableOpenpilotLong = new ToggleControl(tr("Disable openpilot Longitudinal Control"), tr("Disable openpilot longitudinal control and use stock ACC instead."), "", disableOpenpilotLongState); + QObject::connect(disableOpenpilotLong, &ToggleControl::toggleFlipped, [=](bool state) { + if (state) { + if (FrogPilotConfirmationDialog::yesorno(tr("Are you sure you want to completely disable openpilot longitudinal control?"), this)) { + params.putBool("DisableOpenpilotLongitudinal", state); + if (started) { + if (FrogPilotConfirmationDialog::toggle(tr("Reboot required to take effect."), tr("Reboot Now"), this)) { + Hardware::reboot(); + } + } + } + } else { + params.putBool("DisableOpenpilotLongitudinal", state); + } + updateCarToggles(); + }); + addItem(disableOpenpilotLong); + std::vector> vehicleToggles { {"LongitudinalTune", tr("Longitudinal Tune"), tr("Use a custom Toyota longitudinal tune.\n\nCydia = More focused on TSS-P vehicles but works for all Toyotas\n\nDragonPilot = Focused on TSS2 vehicles\n\nFrogPilot = Takes the best of both worlds with some personal tweaks focused around FrogsGoMoo's 2019 Lexus ES 350"), ""}, }; @@ -104,6 +123,8 @@ void FrogPilotVehiclesPanel::updateCarToggles() { } void FrogPilotVehiclesPanel::hideToggles() { + disableOpenpilotLong->setVisible(hasOpenpilotLongitudinal && !hasExperimentalOpenpilotLongitudinal && !params.getBool("HideDisableOpenpilotLongitudinal")); + bool gm = carMake == "Buick" || carMake == "Cadillac" || carMake == "Chevrolet" || carMake == "GM" || carMake == "GMC"; bool subaru = carMake == "Subaru"; bool toyota = carMake == "Lexus" || carMake == "Toyota"; @@ -118,7 +139,7 @@ void FrogPilotVehiclesPanel::hideToggles() { if (toggle) { toggle->setVisible(false); - if (!hasOpenpilotLongitudinal && longitudinalKeys.find(key.c_str()) != longitudinalKeys.end()) { + if ((!hasOpenpilotLongitudinal || params.getBool("DisableOpenpilotLongitudinal")) && longitudinalKeys.find(key.c_str()) != longitudinalKeys.end()) { continue; } diff --git a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h index 3597c4f8c..9f3f2a4bc 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h @@ -20,6 +20,8 @@ private: void updateState(const UIState &s); void updateToggles(); + ToggleControl *disableOpenpilotLong; + std::set gmKeys = {}; std::set subaruKeys = {}; std::set toyotaKeys = {"LongitudinalTune"}; diff --git a/selfdrive/frogpilot/ui/qt/offroad/visual_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/visual_settings.cc index ac93b795b..abe03f96e 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/visual_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/visual_settings.cc @@ -180,6 +180,10 @@ FrogPilotVisualsPanel::FrogPilotVisualsPanel(SettingsWindow *parent) : FrogPilot updateMetric(); } +void FrogPilotVisualsPanel::showEvent(QShowEvent *event) { + hasOpenpilotLongitudinal = hasOpenpilotLongitudinal && !params.getBool("DisableOpenpilotLongitudinal"); +} + void FrogPilotVisualsPanel::updateState(const UIState &s) { if (!isVisible()) return; @@ -202,7 +206,7 @@ void FrogPilotVisualsPanel::updateCarToggles() { cereal::CarParams::Reader CP = cmsg.getRoot(); hasBSM = CP.getEnableBsm(); - hasOpenpilotLongitudinal = CP.getOpenpilotLongitudinalControl(); + hasOpenpilotLongitudinal = CP.getOpenpilotLongitudinalControl() && !params.getBool("DisableOpenpilotLongitudinal"); } else { hasBSM = true; hasOpenpilotLongitudinal = true; diff --git a/selfdrive/frogpilot/ui/qt/offroad/visual_settings.h b/selfdrive/frogpilot/ui/qt/offroad/visual_settings.h index daddc2fed..a81a77f17 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/visual_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/visual_settings.h @@ -17,6 +17,7 @@ signals: private: void hideToggles(); + void showEvent(QShowEvent *event); void updateCarToggles(); void updateMetric(); void updateState(const UIState &s);