diff --git a/cereal/custom.capnp b/cereal/custom.capnp
index ad587c63a..82263a4b6 100644
--- a/cereal/custom.capnp
+++ b/cereal/custom.capnp
@@ -105,7 +105,7 @@ struct FrogPilotCarParams @0xf35cc4560bbf6ec2 {
isHDA2 @3 :Bool;
openpilotLongitudinalControlDisabled @4 :Bool;
safetyConfigs @5 :List(SafetyConfig);
-
+ canUseSASCM @6 :Bool;
struct SafetyConfig {
safetyParam @0 :UInt16;
diff --git a/frogpilot/common/frogpilot_variables.py b/frogpilot/common/frogpilot_variables.py
index 3bde9f102..89c6bdd1f 100644
--- a/frogpilot/common/frogpilot_variables.py
+++ b/frogpilot/common/frogpilot_variables.py
@@ -569,6 +569,7 @@ class FrogPilotVariables:
toggle.has_pedal = CP.enableGasInterceptor
has_radar = not CP.radarUnavailable
toggle.has_sdsu = toggle.car_make == "toyota" and bool(CP.flags & ToyotaFlags.SMART_DSU.value)
+ toggle.has_sascm = toggle.car_make == "gm" and bool(CP.flags & GMFlags.SASCM.value)
has_sng = CP.autoResumeSng
toggle.has_zss = toggle.car_make == "toyota" and bool(FPCP.fpFlags & ToyotaFrogPilotFlags.ZSS.value)
is_angle_car = CP.steerControlType == car.CarParams.SteerControlType.angle
diff --git a/frogpilot/system/frogpilot_stats.py b/frogpilot/system/frogpilot_stats.py
index 2a202d5b8..b488113ca 100644
--- a/frogpilot/system/frogpilot_stats.py
+++ b/frogpilot/system/frogpilot_stats.py
@@ -178,6 +178,7 @@ def send_stats():
.field("has_openpilot_longitudinal", frogpilot_toggles.openpilot_longitudinal)
.field("has_pedal", frogpilot_toggles.has_pedal)
.field("has_sdsu", frogpilot_toggles.has_sdsu)
+ .field("has_sascm", frogpilot_toggles.has_sascm)
.field("has_zss", frogpilot_toggles.has_zss)
.field("latitude", latitude)
.field("longitude", longitude)
diff --git a/frogpilot/ui/qt/offroad/frogpilot_settings.cc b/frogpilot/ui/qt/offroad/frogpilot_settings.cc
index 4fa9a3c4d..c4e8ec270 100644
--- a/frogpilot/ui/qt/offroad/frogpilot_settings.cc
+++ b/frogpilot/ui/qt/offroad/frogpilot_settings.cc
@@ -269,6 +269,7 @@ void FrogPilotSettingsWindow::updateVariables() {
hasPedal = CP.getEnableGasInterceptor();
hasRadar = !CP.getRadarUnavailable();
hasSDSU = frogpilot_toggles.value("has_sdsu").toBool();
+ hasSASCM = frogpilot_toggles.value("has_sascm").toBool();
hasSNG = hasOpenpilotLongitudinal && CP.getAutoResumeSng();
hasZSS = frogpilot_toggles.value("has_zss").toBool();
isAngleCar = CP.getSteerControlType() == cereal::CarParams::SteerControlType::ANGLE;
@@ -392,6 +393,7 @@ void FrogPilotSettingsWindow::updateVariables() {
canUsePedal = FPCP.getCanUsePedal();
canUseSDSU = FPCP.getCanUseSDSU();
+ canUseSASCM = FPCP.getCanUseSASCM();
openpilotLongitudinalControlDisabled = FPCP.getOpenpilotLongitudinalControlDisabled();
}
diff --git a/frogpilot/ui/qt/offroad/frogpilot_settings.h b/frogpilot/ui/qt/offroad/frogpilot_settings.h
index bd48e67e4..aa4db8d8f 100644
--- a/frogpilot/ui/qt/offroad/frogpilot_settings.h
+++ b/frogpilot/ui/qt/offroad/frogpilot_settings.h
@@ -13,6 +13,7 @@ public:
bool canUsePedal = false;
bool canUseSDSU = false;
+ bool canUseSASCM = false;
bool forceOpenDescriptions = false;
bool hasAutoTune = true;
bool hasBSM = true;
@@ -24,6 +25,7 @@ public:
bool hasPedal = false;
bool hasRadar = true;
bool hasSDSU = false;
+ bool hasSASCM = false;
bool hasSNG = false;
bool hasZSS = false;
bool isAngleCar = false;
diff --git a/frogpilot/ui/qt/offroad/vehicle_settings.cc b/frogpilot/ui/qt/offroad/vehicle_settings.cc
index 9ecfa3a75..777d0a790 100644
--- a/frogpilot/ui/qt/offroad/vehicle_settings.cc
+++ b/frogpilot/ui/qt/offroad/vehicle_settings.cc
@@ -189,6 +189,7 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent)
{"PedalSupport", tr("comma Pedal Support"), tr("Does your vehicle support the \"comma pedal\"?"), ""},
{"OpenpilotLongitudinal", tr("openpilot Longitudinal Support"), tr("Can openpilot control the vehicle's acceleration and braking?"), ""},
{"RadarSupport", tr("Radar Support"), tr("Does openpilot use the vehicle's radar data alongside the device's camera for tracking lead vehicles?"), ""},
+ {"SASCMSupport", tr("SASCM Support"), tr("Does your vehicle support \"SASCMs\"?"), ""},
{"SDSUSupport", tr("SDSU Support"), tr("Does your vehicle support \"SDSUs\"?"), ""},
{"SNGSupport", tr("Stop-and-Go Support"), tr("Does your vehicle support stop-and-go driving?"), ""}
};
@@ -342,6 +343,7 @@ void FrogPilotVehiclesPanel::showEvent(QShowEvent *event) {
QStringList detected;
if (hasPedal) detected << "comma Pedal";
+ if (parent->hasSASCM) detected << "SASCM";
if (parent->hasSDSU) detected << "SDSU";
if (parent->hasZSS) detected << "ZSS";
static_cast(toggles["HardwareDetected"])->setText(detected.isEmpty() ? tr("None") : detected.join(", "));
@@ -350,6 +352,7 @@ void FrogPilotVehiclesPanel::showEvent(QShowEvent *event) {
static_cast(toggles["OpenpilotLongitudinal"])->setText(hasOpenpilotLongitudinal ? tr("Yes") : tr("No"));
static_cast(toggles["PedalSupport"])->setText(parent->canUsePedal ? tr("Yes") : tr("No"));
static_cast(toggles["RadarSupport"])->setText(parent->hasRadar ? tr("Yes") : tr("No"));
+ static_cast(toggles["SASCMSupport"])->setText(parent->canUseSASCM ? tr("Yes") : tr("No"));
static_cast(toggles["SDSUSupport"])->setText(parent->canUseSDSU ? tr("Yes") : tr("No"));
static_cast(toggles["SNGSupport"])->setText(hasSNG ? tr("Yes") : tr("No"));
diff --git a/frogpilot/ui/qt/offroad/vehicle_settings.h b/frogpilot/ui/qt/offroad/vehicle_settings.h
index dd94a4f70..f29cd896a 100644
--- a/frogpilot/ui/qt/offroad/vehicle_settings.h
+++ b/frogpilot/ui/qt/offroad/vehicle_settings.h
@@ -40,7 +40,7 @@ private:
QSet hkgKeys = {"NewLongAPI", "TacoTuneHacks"};
QSet longitudinalKeys = {"ExperimentalGMTune", "FrogsGoMoosTweak", "LongPitch", "NewLongAPI", "SNGHack", "VoltSNG"};
QSet toyotaKeys = {"ClusterOffset", "FrogsGoMoosTweak", "LockDoorsTimer", "SNGHack", "ToyotaDoors"};
- QSet vehicleInfoKeys = {"BlindSpotSupport", "HardwareDetected", "OpenpilotLongitudinal", "PedalSupport", "RadarSupport", "SDSUSupport", "SNGSupport"};
+ QSet vehicleInfoKeys = {"BlindSpotSupport", "HardwareDetected", "OpenpilotLongitudinal", "PedalSupport", "RadarSupport", "SASCMSupport", "SDSUSupport", "SNGSupport"};
QSet parentKeys;
diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py
index ff51110e8..6a0c574b8 100644
--- a/selfdrive/car/gm/interface.py
+++ b/selfdrive/car/gm/interface.py
@@ -111,6 +111,11 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.gm)]
ret.autoResumeSng = False
ret.enableBsm = 0x142 in fingerprint[CanBus.POWERTRAIN]
+
+ # Detect Beartech SASCM allows openpilot longitudinal control on SDGM and ASCM_INT vehicles
+ if 0x2FF in fingerprint[0]:
+ ret.flags |= GMFlags.SASCM.value
+
if PEDAL_MSG in fingerprint[0]:
ret.enableGasInterceptor = True
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_GM_GAS_INTERCEPTOR
diff --git a/selfdrive/car/gm/values.py b/selfdrive/car/gm/values.py
index 52ab348dd..e6ce414f3 100644
--- a/selfdrive/car/gm/values.py
+++ b/selfdrive/car/gm/values.py
@@ -258,6 +258,8 @@ class GMFlags(IntFlag):
CC_LONG = 2
NO_CAMERA = 4
NO_ACCELERATOR_POS_MSG = 8
+ FORCE_BRAKE_C9 = 16
+ SASCM = 32
# In a Data Module, an identifier is a string used to recognize an object,
diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py
index 948e758ee..90af90df2 100644
--- a/selfdrive/car/interfaces.py
+++ b/selfdrive/car/interfaces.py
@@ -187,6 +187,7 @@ class CarInterfaceBase(ABC):
elif platform in GMCAR:
fp_ret.canUsePedal = True
+ fp_ret.canUseSASCM = True
elif platform in HondaCAR:
if candidate == HondaCAR.HONDA_CLARITY: