diff --git a/frogpilot/common/frogpilot_utilities.py b/frogpilot/common/frogpilot_utilities.py index 7972c90b7..ccdd4d8ec 100644 --- a/frogpilot/common/frogpilot_utilities.py +++ b/frogpilot/common/frogpilot_utilities.py @@ -15,6 +15,7 @@ import openpilot.system.sentry as sentry from cereal import log, messaging from openpilot.common.realtime import DT_DMON, DT_HW +from panda import Panda from openpilot.frogpilot.common.frogpilot_variables import EARTH_RADIUS, FROGS_GO_MOO_PATH @@ -120,6 +121,19 @@ def extract_zip(zip_file, extract_path): print(f"Extraction completed!") +def flash_panda(params_memory): + for serial in Panda.list(): + try: + with Panda(serial=serial) as panda: + print(f"Flashing Panda {serial}") + panda.flash() + except Exception as exception: + print(f"Failed to flash Panda {serial}: {exception}") + sentry.capture_exception(exception) + + params_memory.remove("FlashPanda") + + @cache def is_FrogsGoMoo(): return FROGS_GO_MOO_PATH.is_file() diff --git a/frogpilot/frogpilot_process.py b/frogpilot/frogpilot_process.py index 108b0dff4..e7d741e95 100644 --- a/frogpilot/frogpilot_process.py +++ b/frogpilot/frogpilot_process.py @@ -11,7 +11,7 @@ from openpilot.common.time_helpers import system_time_valid from openpilot.frogpilot.assets.theme_manager import THEME_COMPONENT_PARAMS, ThemeManager from openpilot.frogpilot.common.frogpilot_backups import backup_toggles from openpilot.frogpilot.common.frogpilot_functions import update_openpilot -from openpilot.frogpilot.common.frogpilot_utilities import ThreadManager, is_url_pingable +from openpilot.frogpilot.common.frogpilot_utilities import ThreadManager, flash_panda, is_url_pingable from openpilot.frogpilot.common.frogpilot_variables import ERROR_LOGS_PATH, FrogPilotVariables from openpilot.frogpilot.controls.frogpilot_planner import FrogPilotPlanner from openpilot.frogpilot.system.frogpilot_stats import send_stats @@ -25,6 +25,9 @@ def check_assets(theme_manager, thread_manager, params_memory, frogpilot_toggles if asset_to_download: thread_manager.run_with_lock(theme_manager.download_theme, (asset_type, asset_to_download, asset_param, frogpilot_toggles)) + if params_memory.get_bool("FlashPanda"): + thread_manager.run_with_lock(flash_panda, (params_memory)) + def transition_offroad(frogpilot_planner, thread_manager, time_validated, sm, params, frogpilot_toggles): params.put("LastGPSPosition", json.dumps(frogpilot_planner.gps_position)) diff --git a/frogpilot/ui/qt/offroad/utilities.cc b/frogpilot/ui/qt/offroad/utilities.cc index 93fa66ccf..9c86abba1 100644 --- a/frogpilot/ui/qt/offroad/utilities.cc +++ b/frogpilot/ui/qt/offroad/utilities.cc @@ -9,6 +9,37 @@ FrogPilotUtilitiesPanel::FrogPilotUtilitiesPanel(FrogPilotSettingsWindow *parent } addItem(debugModeToggle); + ButtonControl *flashPandaButton = new ButtonControl(tr("Flash Panda"), tr("FLASH"), tr("Flash the latest, official firmware onto your Panda device to restore core functionality, fix bugs, or ensure you have the most up-to-date software.")); + QObject::connect(flashPandaButton, &ButtonControl::clicked, [parent, flashPandaButton, this]() { + if (ConfirmationDialog::confirm(tr("Are you sure you want to flash the Panda firmware?"), tr("Flash"), this)) { + std::thread([parent, flashPandaButton, this]() { + parent->keepScreenOn = true; + + flashPandaButton->setEnabled(false); + flashPandaButton->setValue(tr("Flashing...")); + + params_memory.putBool("FlashPanda", true); + while (params_memory.getBool("FlashPanda")) { + util::sleep_for(UI_FREQ); + } + + flashPandaButton->setValue(tr("Flashed!")); + + util::sleep_for(2500); + + flashPandaButton->setValue(tr("Rebooting...")); + + util::sleep_for(2500); + + Hardware::reboot(); + }).detach(); + } + }); + if (forceOpenDescriptions) { + flashPandaButton->showDescription(); + } + addItem(flashPandaButton); + ButtonControl *resetTogglesButton = new ButtonControl(tr("Reset Toggles to Default"), tr("RESET"), tr("Reset all toggles to their default values.")); QObject::connect(resetTogglesButton, &ButtonControl::clicked, [parent, resetTogglesButton, this]() { if (ConfirmationDialog::confirm(tr("Are you sure you want to reset all toggles to their default values?"), tr("Reset"), this)) {