diff --git a/common/params.cc b/common/params.cc index 9e5eaf84e..341655c76 100644 --- a/common/params.cc +++ b/common/params.cc @@ -224,6 +224,8 @@ std::unordered_map keys = { {"BlindSpotPath", PERSISTENT}, {"CameraView", PERSISTENT}, {"CameraViewReset", PERSISTENT}, + {"CarMake", PERSISTENT}, + {"CarModel", PERSISTENT}, {"CECurves", PERSISTENT}, {"CECurvesLead", PERSISTENT}, {"CENavigation", PERSISTENT}, @@ -265,6 +267,7 @@ std::unordered_map keys = { {"ExperimentalModeViaLKAS", PERSISTENT}, {"ExperimentalModeViaTap", PERSISTENT}, {"ForceAutoTune", PERSISTENT}, + {"ForceFingerprint", PERSISTENT}, {"FrogPilotTogglesUpdated", PERSISTENT}, {"FrogsGoMoo", PERSISTENT}, {"GoatScream", PERSISTENT}, diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index 1d99cc33f..6d32f100e 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -200,11 +200,23 @@ def get_car_interface(CP): def get_car(params, logcan, sendcan, disable_openpilot_long, experimental_long_allowed, num_pandas=1): + car_brand = params.get("CarMake", encoding='utf-8') + car_model = params.get("CarModel", encoding='utf-8') + + force_fingerprint = params.get_bool("ForceFingerprint") + candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(logcan, sendcan, num_pandas) - if candidate is None: - cloudlog.event("car doesn't match any fingerprints", fingerprints=repr(fingerprints), error=True) - candidate = "mock" + if candidate is None or force_fingerprint: + if car_model is not None: + candidate = car_model + else: + cloudlog.event("car doesn't match any fingerprints", fingerprints=repr(fingerprints), error=True) + candidate = "mock" + + if car_model is None and candidate != "mock": + params.put("CarMake", candidate.split(' ')[0].title()) + params.put("CarModel", candidate) if get_short_branch() == "FrogPilot-Development" and not Params("/persist/params").get_bool("FrogsGoMoo"): cloudlog.event("Blocked user from using the 'FrogPilot-Development' branch", fingerprints=repr(fingerprints), error=True) diff --git a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc index 452ebf7b4..2928e1544 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc +++ b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.cc @@ -1,6 +1,97 @@ +#include +#include +#include + #include "selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h" +QStringList getCarNames(const QString &carMake) { + QMap makeMap; + makeMap["acura"] = "honda"; + makeMap["audi"] = "volkswagen"; + makeMap["buick"] = "gm"; + makeMap["cadillac"] = "gm"; + makeMap["chevrolet"] = "gm"; + makeMap["chrysler"] = "chrysler"; + makeMap["dodge"] = "chrysler"; + makeMap["ford"] = "ford"; + makeMap["gm"] = "gm"; + makeMap["gmc"] = "gm"; + makeMap["genesis"] = "hyundai"; + makeMap["honda"] = "honda"; + makeMap["hyundai"] = "hyundai"; + makeMap["infiniti"] = "nissan"; + makeMap["jeep"] = "chrysler"; + makeMap["kia"] = "hyundai"; + makeMap["lexus"] = "toyota"; + makeMap["lincoln"] = "ford"; + makeMap["man"] = "volkswagen"; + makeMap["mazda"] = "mazda"; + makeMap["nissan"] = "nissan"; + makeMap["ram"] = "chrysler"; + makeMap["seat"] = "volkswagen"; + makeMap["škoda"] = "volkswagen"; + makeMap["subaru"] = "subaru"; + makeMap["tesla"] = "tesla"; + makeMap["toyota"] = "toyota"; + makeMap["volkswagen"] = "volkswagen"; + + QString dirPath = "../car"; + QDir dir(dirPath); + QString targetFolder = makeMap.value(carMake, carMake); + QStringList names; + + QString filePath = dir.absoluteFilePath(targetFolder + "/values.py"); + QFile file(filePath); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&file); + QRegularExpression regex(R"delimiter(\w+\s*=\s*\w+PlatformConfig\(\s*"([^"]+)",)delimiter"); + QRegularExpressionMatchIterator it = regex.globalMatch(in.readAll()); + while (it.hasNext()) { + QRegularExpressionMatch match = it.next(); + names << match.captured(1); + } + file.close(); + } + + std::sort(names.begin(), names.end()); + return names; +} + FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) { + selectMakeButton = new ButtonControl(tr("Select Make"), tr("SELECT")); + QObject::connect(selectMakeButton, &ButtonControl::clicked, [this]() { + QStringList makes = { + "Acura", "Audi", "BMW", "Buick", "Cadillac", "Chevrolet", "Chrysler", "Dodge", "Ford", "GM", "GMC", + "Genesis", "Honda", "Hyundai", "Infiniti", "Jeep", "Kia", "Lexus", "Lincoln", "MAN", "Mazda", + "Mercedes", "Nissan", "Ram", "SEAT", "Škoda", "Subaru", "Tesla", "Toyota", "Volkswagen", "Volvo", + }; + + QString newMakeSelection = MultiOptionDialog::getSelection(tr("Select a Make"), makes, "", this); + if (!newMakeSelection.isEmpty()) { + carMake = newMakeSelection; + params.putNonBlocking("CarMake", carMake.toStdString()); + selectMakeButton->setValue(newMakeSelection); + setModels(); + } + }); + addItem(selectMakeButton); + + selectModelButton = new ButtonControl(tr("Select Model"), tr("SELECT")); + QString modelSelection = QString::fromStdString(params.get("CarModel")); + QObject::connect(selectModelButton, &ButtonControl::clicked, [this]() { + QString newModelSelection = MultiOptionDialog::getSelection(tr("Select a Model"), models, "", this); + if (!newModelSelection.isEmpty()) { + params.putNonBlocking("CarModel", newModelSelection.toStdString()); + selectModelButton->setValue(newModelSelection); + } + }); + selectModelButton->setValue(modelSelection); + addItem(selectModelButton); + selectModelButton->setVisible(false); + + ParamControl *forceFingerprint = new ParamControl("ForceFingerprint", tr("Disable Automatic Fingerprint Detection"), tr("Forces the selected fingerprint and prevents it from ever changing."), "", this); + addItem(forceFingerprint); + 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) { @@ -71,8 +162,23 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(SettingsWindow *parent) : FrogPil }); } - QObject::connect(uiState(), &UIState::offroadTransition, this, &FrogPilotVehiclesPanel::updateCarToggles); + QObject::connect(uiState(), &UIState::offroadTransition, [this](bool offroad) { + std::thread([this]() { + while (carMake.isEmpty()) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + carMake = QString::fromStdString(params.get("CarMake")); + } + setModels(); + updateCarToggles(); + }).detach(); + }); + QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotVehiclesPanel::updateState); + + carMake = QString::fromStdString(params.get("CarMake")); + if (!carMake.isEmpty()) { + setModels(); + } } void FrogPilotVehiclesPanel::updateState(const UIState &s) { @@ -123,9 +229,17 @@ void FrogPilotVehiclesPanel::updateCarToggles() { hideToggles(); } +void FrogPilotVehiclesPanel::setModels() { + models = getCarNames(carMake.toLower()); + hideToggles(); +} + void FrogPilotVehiclesPanel::hideToggles() { disableOpenpilotLong->setVisible(hasOpenpilotLongitudinal && !hasExperimentalOpenpilotLongitudinal && !params.getBool("HideDisableOpenpilotLongitudinal")); + selectMakeButton->setValue(carMake); + selectModelButton->setVisible(!carMake.isEmpty()); + bool gm = carMake == "Buick" || carMake == "Cadillac" || carMake == "Chevrolet" || carMake == "GM" || carMake == "GMC"; bool subaru = carMake == "Subaru"; bool toyota = carMake == "Lexus" || carMake == "Toyota"; diff --git a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h index 9f3f2a4bc..2f4b5eac6 100644 --- a/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h +++ b/selfdrive/frogpilot/ui/qt/offroad/vehicle_settings.h @@ -16,12 +16,19 @@ public: private: void hideToggles(); + void setModels(); void updateCarToggles(); void updateState(const UIState &s); void updateToggles(); + ButtonControl *selectMakeButton; + ButtonControl *selectModelButton; + ToggleControl *disableOpenpilotLong; + QString carMake; + QStringList models; + std::set gmKeys = {}; std::set subaruKeys = {}; std::set toyotaKeys = {"LongitudinalTune"};