From ced3a53a0d70318ea2ff471d378ad7b819e9a684 Mon Sep 17 00:00:00 2001 From: FrogAi <91348155+FrogAi@users.noreply.github.com> Date: Tue, 10 Sep 2024 11:01:59 -0700 Subject: [PATCH] September 10th, 2024 Patch --- README.md | 2 +- .../controls/lib/download_functions.py | 46 +++--- .../frogpilot/controls/lib/model_manager.py | 56 ++++--- .../frogpilot/controls/lib/theme_manager.py | 7 +- selfdrive/frogpilot/frogpilot_process.py | 8 +- selfdrive/frogpilot/navigation/mapd.py | 16 +- .../navigation/ui/navigation_functions.h | 138 ++++++++++-------- selfdrive/ui/qt/onroad/annotated_camera.cc | 2 +- selfdrive/ui/qt/onroad/buttons.cc | 3 + 9 files changed, 154 insertions(+), 124 deletions(-) diff --git a/README.md b/README.md index e0eb4e1529..7ae1b0eabb 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ FrogPilot is a fully open-sourced fork of openpilot, featuring clear and concise ------ FrogPilot was last updated on: -**September 5th, 2024** +**September 10th, 2024** Features ------ diff --git a/selfdrive/frogpilot/controls/lib/download_functions.py b/selfdrive/frogpilot/controls/lib/download_functions.py index 7aa23ef44b..7d6655dd1a 100644 --- a/selfdrive/frogpilot/controls/lib/download_functions.py +++ b/selfdrive/frogpilot/controls/lib/download_functions.py @@ -43,34 +43,30 @@ def handle_error(destination, error_message, error, download_param, progress_par params_memory.put(progress_param, error_message) def handle_request_error(error, destination, download_param, progress_param, params_memory): - if isinstance(error, requests.HTTPError): - if error.response.status_code == 404: - return - error_message = f"Server error ({error.response.status_code})" if error.response else "Server error." - elif isinstance(error, requests.ConnectionError): - error_message = "Connection dropped." - elif isinstance(error, requests.Timeout): - error_message = "Download timed out." - elif isinstance(error, requests.RequestException): - error_message = "Network request error. Check connection." - else: - error_message = "Unexpected error." + error_map = { + requests.HTTPError: lambda e: f"Server error ({e.response.status_code})" if e.response else "Server error.", + requests.ConnectionError: "Connection dropped.", + requests.Timeout: "Download timed out.", + requests.RequestException: "Network request error. Check connection." + } + + error_message = error_map.get(type(error), "Unexpected error.") + if isinstance(error, requests.HTTPError) and error.response and error.response.status_code == 404: + return handle_error(destination, f"Failed: {error_message}", error, download_param, progress_param, params_memory) def get_remote_file_size(url): try: response = requests.head(url, headers={'Accept-Encoding': 'identity'}, timeout=5) + if response.status_code == 404: + print(f"URL not found: {url}") + return None response.raise_for_status() return int(response.headers.get('Content-Length', 0)) - except requests.HTTPError as e: - if e.response.status_code == 404: - return 0 - else: - handle_request_error(e, None, None, None, None) - except Exception as e: + except (requests.RequestException, ValueError) as e: handle_request_error(e, None, None, None, None) - return 0 + return None def get_repository_url(): if is_url_pingable("https://github.com"): @@ -84,17 +80,25 @@ def link_valid(url): response = requests.head(url, allow_redirects=True, timeout=5) response.raise_for_status() return True + except requests.HTTPError as e: + if e.response.status_code != 404: + handle_request_error(e, None, None, None, None) + return False except Exception as e: handle_request_error(e, None, None, None, None) return False def verify_download(file_path, url): - if not os.path.exists(file_path): + if not os.path.isfile(file_path): print(f"File not found: {file_path}") return False remote_file_size = get_remote_file_size(url) if remote_file_size is None: + print(f"Error fetching remote size for {file_path}") + return None + if remote_file_size != os.path.getsize(file_path): + print(f"File size mismatch for {file_path}") return False - return remote_file_size == os.path.getsize(file_path) + return True diff --git a/selfdrive/frogpilot/controls/lib/model_manager.py b/selfdrive/frogpilot/controls/lib/model_manager.py index a8f2f34c22..a86ceb90c7 100644 --- a/selfdrive/frogpilot/controls/lib/model_manager.py +++ b/selfdrive/frogpilot/controls/lib/model_manager.py @@ -1,7 +1,6 @@ import json import os import re -import requests import shutil import time import urllib.request @@ -46,16 +45,16 @@ class ModelManager: def download_model(self, model_to_download): model_path = os.path.join(MODELS_PATH, f"{model_to_download}.thneed") - if os.path.exists(model_path): + if os.path.isfile(model_path): handle_error(model_path, "Model already exists...", "Model already exists...", self.download_param, self.download_progress_param, self.params_memory) return - self.repo_url = get_repository_url() - if not self.repo_url: + repo_url = get_repository_url() + if not repo_url: handle_error(model_path, "GitHub and GitLab are offline...", "Repository unavailable", self.download_param, self.download_progress_param, self.params_memory) return - model_url = f"{self.repo_url}Models/{model_to_download}.thneed" + model_url = f"{repo_url}Models/{model_to_download}.thneed" print(f"Downloading model: {model_to_download}") download_file(self.cancel_download_param, model_path, self.download_progress_param, model_url, self.download_param, self.params_memory) @@ -74,7 +73,7 @@ class ModelManager: handle_request_error(error, None, None, None, None) return [] - def update_model_params(self, model_info): + def update_model_params(self, model_info, repo_url): available_models, available_model_names, experimental_models, navigation_models, radarless_models = [], [], [], [], [] for model in model_info: @@ -96,20 +95,23 @@ class ModelManager: print("Models list updated successfully.") if available_models: - models_downloaded = self.are_all_models_downloaded(available_models, available_model_names) + models_downloaded = self.are_all_models_downloaded(available_models, available_model_names, repo_url) self.params.put_bool_nonblocking("ModelsDownloaded", models_downloaded) - def are_all_models_downloaded(self, available_models, available_model_names): + def are_all_models_downloaded(self, available_models, available_model_names, repo_url): automatically_update_models = self.params.get_bool("AutomaticallyUpdateModels") all_models_downloaded = True for model in available_models: model_path = os.path.join(MODELS_PATH, f"{model}.thneed") - model_url = f"{self.repo_url}Models/{model}.thneed" + model_url = f"{repo_url}Models/{model}.thneed" - if os.path.exists(model_path): + if os.path.isfile(model_path): if automatically_update_models: - if not verify_download(model_path, model_url): + verify_result = verify_download(model_path, model_url) + if verify_result is None: + all_models_downloaded = False + elif not verify_result: print(f"Model {model} is outdated. Re-downloading...") delete_file(model_path) self.remove_model_params(available_model_names, available_models, model) @@ -152,6 +154,11 @@ class ModelManager: if not available_models: return + current_model_path = os.path.join(MODELS_PATH, f"{current_model}.thneed") + if not os.path.isfile(current_model_path): + print(f"Model {current_model} is not downloaded. Downloading...") + self.download_model(current_model) + for model_file in os.listdir(MODELS_PATH): if model_file.replace(".thneed", "") not in available_models.split(','): if model_file == current_model: @@ -163,35 +170,38 @@ class ModelManager: def copy_default_model(self): default_model_path = os.path.join(MODELS_PATH, f"{DEFAULT_MODEL}.thneed") - if not os.path.exists(default_model_path): + if not os.path.isfile(default_model_path): source_path = os.path.join(BASEDIR, "selfdrive", "modeld", "models", "supercombo.thneed") - if os.path.exists(source_path): + if os.path.isfile(source_path): shutil.copyfile(source_path, default_model_path) print(f"Copied default model from {source_path} to {default_model_path}") else: print(f"Source default model not found at {source_path}. Exiting...") - def update_models(self, boot_run=True): + def update_models(self, boot_run=False): if boot_run: self.copy_default_model() - self.repo_url = get_repository_url() - if self.repo_url is None: + repo_url = get_repository_url() + if repo_url is None: print("GitHub and GitLab are offline...") return - model_info = self.fetch_models(f"{self.repo_url}Versions/model_names_{VERSION}.json") + model_info = self.fetch_models(f"{repo_url}Versions/model_names_{VERSION}.json") if model_info: - self.update_model_params(model_info) + self.update_model_params(model_info, repo_url) + + if boot_run: + self.validate_models() def download_all_models(self): - self.repo_url = get_repository_url() - if not self.repo_url: + repo_url = get_repository_url() + if not repo_url: handle_error(None, "GitHub and GitLab are offline...", "Repository unavailable", self.download_param, self.download_progress_param, self.params_memory) return - model_info = self.fetch_models(f"{self.repo_url}Versions/model_names_{VERSION}.json") + model_info = self.fetch_models(f"{repo_url}Versions/model_names_{VERSION}.json") if not model_info: handle_error(None, "Unable to update model list...", "Model list unavailable", self.download_param, self.download_progress_param, self.params_memory) return @@ -208,7 +218,7 @@ class ModelManager: if self.params_memory.get_bool(self.cancel_download_param): return - if not os.path.exists(os.path.join(MODELS_PATH, f"{model}.thneed")): + if not os.path.isfile(os.path.join(MODELS_PATH, f"{model}.thneed")): model_index = available_models.index(model) model_name = available_model_names[model_index] @@ -220,7 +230,7 @@ class ModelManager: while self.params_memory.get(self.download_param, encoding='utf-8'): time.sleep(1) - while not all(os.path.exists(os.path.join(MODELS_PATH, f"{model}.thneed")) for model in available_models): + while not all(os.path.isfile(os.path.join(MODELS_PATH, f"{model}.thneed")) for model in available_models): time.sleep(1) self.params_memory.put(self.download_progress_param, "All models downloaded!") diff --git a/selfdrive/frogpilot/controls/lib/theme_manager.py b/selfdrive/frogpilot/controls/lib/theme_manager.py index e7a4f27925..73578a2b23 100644 --- a/selfdrive/frogpilot/controls/lib/theme_manager.py +++ b/selfdrive/frogpilot/controls/lib/theme_manager.py @@ -258,7 +258,7 @@ class ThemeManager: for ext in extentions: theme_path = download_path + ext - if os.path.exists(theme_path): + if os.path.isfile(theme_path): handle_error(theme_path, "Theme already exists...", "Theme already exists...", theme_param, self.download_progress_param, self.params_memory) return @@ -366,7 +366,7 @@ class ThemeManager: self.previous_assets = {} self.update_active_theme() - def update_themes(self): + def update_themes(self, boot_run=False): if not os.path.exists(THEME_SAVE_PATH): return @@ -375,6 +375,9 @@ class ThemeManager: print("GitHub and GitLab are offline...") return + if boot_run: + self.validate_themes() + if repo_url == GITHUB_URL: base_url = "https://github.com/FrogAi/FrogPilot-Resources/blob/Themes/" distance_icons_files = self.fetch_files("https://github.com/FrogAi/FrogPilot-Resources/blob/Distance-Icons") diff --git a/selfdrive/frogpilot/frogpilot_process.py b/selfdrive/frogpilot/frogpilot_process.py index 2531d8fb40..2971ee8fdf 100644 --- a/selfdrive/frogpilot/frogpilot_process.py +++ b/selfdrive/frogpilot/frogpilot_process.py @@ -86,13 +86,13 @@ def time_checks(automatic_updates, deviceState, model_manager, now, started, the update_maps(now, params, params_memory) with locks["update_models"]: - model_manager.update_models(boot_run=False) + model_manager.update_models() with locks["update_themes"]: theme_manager.update_themes() def toggle_updates(frogpilot_toggles, started, time_validated, params, params_storage): - FrogPilotVariables.update_frogpilot_params(started, True) + FrogPilotVariables.update_frogpilot_params(started) if not frogpilot_toggles.model_manager: params.put_nonblocking("Model", DEFAULT_MODEL) @@ -195,8 +195,8 @@ def frogpilot_thread(): if not time_validated: continue if deviceState.networkType == WIFI: - run_thread_with_lock("update_models", model_manager.update_models) - run_thread_with_lock("update_themes", theme_manager.update_themes) + run_thread_with_lock("update_models", model_manager.update_models, (True,)) + run_thread_with_lock("update_themes", theme_manager.update_themes, (True,)) theme_manager.update_holiday() diff --git a/selfdrive/frogpilot/navigation/mapd.py b/selfdrive/frogpilot/navigation/mapd.py index 2b763e149c..20a51a21d5 100644 --- a/selfdrive/frogpilot/navigation/mapd.py +++ b/selfdrive/frogpilot/navigation/mapd.py @@ -5,9 +5,6 @@ import stat import subprocess import time import urllib.request -import http.client -import socket -import openpilot.system.sentry as sentry from openpilot.common.realtime import Ratekeeper @@ -26,9 +23,8 @@ def get_latest_version(): try: with urllib.request.urlopen(url, timeout=5) as response: return json.loads(response.read().decode('utf-8'))['version'] - except (http.client.IncompleteRead, http.client.RemoteDisconnected, socket.gaierror, socket.timeout, urllib.error.HTTPError, urllib.error.URLError) as e: - sentry.capture_exception(e) - print(f"Failed to get latest version from {url}. Error: {e}") + except Exception as e: + print(f"Error fetching version from {url}: {e}") print("Failed to get the latest version from both sources.") return None @@ -54,9 +50,8 @@ def download(current_version): print(f"Successfully downloaded mapd from {url}") return True - except (http.client.IncompleteRead, http.client.RemoteDisconnected, socket.gaierror, socket.timeout, urllib.error.HTTPError, urllib.error.URLError) as e: - sentry.capture_exception(e) - print(f"Failed to download from {url}. Error: {e}") + except Exception as e: + print(f"Failed to download from {url}: {e}") print(f"Failed to download mapd for version {current_version} from both sources.") return False @@ -66,7 +61,6 @@ def ensure_mapd_is_running(): try: subprocess.run([MAPD_PATH], check=True) except Exception as e: - sentry.capture_exception(e) print(f"Error running mapd process: {e}") time.sleep(1) @@ -89,7 +83,6 @@ def mapd_thread(sm=None, pm=None): continue ensure_mapd_is_running() except Exception as e: - sentry.capture_exception(e) print(f"Exception in mapd_thread: {e}") time.sleep(1) @@ -99,7 +92,6 @@ def main(sm=None, pm=None): try: mapd_thread(sm, pm) except Exception as e: - sentry.capture_exception(e) print(f"Unhandled exception in main: {e}") if __name__ == "__main__": diff --git a/selfdrive/frogpilot/navigation/ui/navigation_functions.h b/selfdrive/frogpilot/navigation/ui/navigation_functions.h index b4db3bc260..85b0b1c67e 100644 --- a/selfdrive/frogpilot/navigation/ui/navigation_functions.h +++ b/selfdrive/frogpilot/navigation/ui/navigation_functions.h @@ -14,31 +14,31 @@ #include "selfdrive/ui/ui.h" QMap northeastMap = { - {"CT", "Connecticut"}, {"DE", "Delaware"}, {"MA", "Massachusetts"}, - {"MD", "Maryland"}, {"ME", "Maine"}, {"NH", "New Hampshire"}, + {"CT", "Connecticut"}, {"DE", "Delaware"}, {"ME", "Maine"}, + {"MD", "Maryland"}, {"MA", "Massachusetts"}, {"NH", "New Hampshire"}, {"NJ", "New Jersey"}, {"NY", "New York"}, {"PA", "Pennsylvania"}, {"RI", "Rhode Island"}, {"VT", "Vermont"} }; QMap midwestMap = { - {"IA", "Iowa"}, {"IL", "Illinois"}, {"IN", "Indiana"}, + {"IL", "Illinois"}, {"IN", "Indiana"}, {"IA", "Iowa"}, {"KS", "Kansas"}, {"MI", "Michigan"}, {"MN", "Minnesota"}, - {"MO", "Missouri"}, {"ND", "North Dakota"}, {"NE", "Nebraska"}, + {"MO", "Missouri"}, {"NE", "Nebraska"}, {"ND", "North Dakota"}, {"OH", "Ohio"}, {"SD", "South Dakota"}, {"WI", "Wisconsin"} }; QMap southMap = { {"AL", "Alabama"}, {"AR", "Arkansas"}, {"FL", "Florida"}, {"GA", "Georgia"}, {"KY", "Kentucky"}, {"LA", "Louisiana"}, - {"MS", "Mississippi"}, {"NC", "North Carolina"}, {"OK", "Oklahoma"}, - {"SC", "South Carolina"}, {"TN", "Tennessee"}, {"TX", "Texas"}, - {"VA", "Virginia"}, {"WV", "West Virginia"} + {"MD", "Maryland"}, {"MS", "Mississippi"}, {"NC", "North Carolina"}, + {"OK", "Oklahoma"}, {"SC", "South Carolina"}, {"TN", "Tennessee"}, + {"TX", "Texas"}, {"VA", "Virginia"}, {"WV", "West Virginia"} }; QMap westMap = { {"AK", "Alaska"}, {"AZ", "Arizona"}, {"CA", "California"}, {"CO", "Colorado"}, {"HI", "Hawaii"}, {"ID", "Idaho"}, - {"MT", "Montana"}, {"NM", "New Mexico"}, {"NV", "Nevada"}, + {"MT", "Montana"}, {"NV", "Nevada"}, {"NM", "New Mexico"}, {"OR", "Oregon"}, {"UT", "Utah"}, {"WA", "Washington"}, {"WY", "Wyoming"} }; @@ -51,19 +51,23 @@ QMap territoriesMap = { QMap africaMap = { {"DZ", "Algeria"}, {"AO", "Angola"}, {"BJ", "Benin"}, {"BW", "Botswana"}, - {"BF", "Burkina Faso"}, {"BI", "Burundi"}, {"CM", "Cameroon"}, {"CV", "Cape Verde"}, - {"CF", "Central African Republic"}, {"TD", "Chad"}, {"KM", "Comoros"}, {"CG", "Congo (Brazzaville)"}, - {"CD", "Congo (Kinshasa)"}, {"CI", "Ivory Coast"}, {"DJ", "Djibouti"}, {"EG", "Egypt"}, - {"GQ", "Equatorial Guinea"}, {"ER", "Eritrea"}, {"SZ", "Eswatini"}, {"ET", "Ethiopia"}, - {"GA", "Gabon"}, {"GM", "Gambia"}, {"GH", "Ghana"}, {"GN", "Guinea"}, - {"GW", "Guinea-Bissau"}, {"KE", "Kenya"}, {"LS", "Lesotho"}, {"LR", "Liberia"}, - {"LY", "Libya"}, {"MG", "Madagascar"}, {"MW", "Malawi"}, {"ML", "Mali"}, - {"MR", "Mauritania"}, {"MU", "Mauritius"}, {"MA", "Morocco"}, {"MZ", "Mozambique"}, - {"NA", "Namibia"}, {"NE", "Niger"}, {"NG", "Nigeria"}, {"RW", "Rwanda"}, - {"ST", "Sao Tome and Principe"}, {"SN", "Senegal"}, {"SC", "Seychelles"}, {"SL", "Sierra Leone"}, - {"SO", "Somalia"}, {"ZA", "South Africa"}, {"SS", "South Sudan"}, {"SD", "Sudan"}, - {"TZ", "Tanzania"}, {"TG", "Togo"}, {"TN", "Tunisia"}, {"UG", "Uganda"}, - {"EH", "Western Sahara"}, {"ZM", "Zambia"}, {"ZW", "Zimbabwe"} + {"BF", "Burkina Faso"}, {"BI", "Burundi"}, {"CV", "Cape Verde"}, + {"CM", "Cameroon"}, {"CF", "Central African Republic"}, {"TD", "Chad"}, + {"KM", "Comoros"}, {"CG", "Congo (Brazzaville)"}, {"CD", "Congo (Kinshasa)"}, + {"CI", "Ivory Coast"}, {"DJ", "Djibouti"}, {"EG", "Egypt"}, + {"GQ", "Equatorial Guinea"}, {"ER", "Eritrea"}, {"SZ", "Eswatini"}, + {"ET", "Ethiopia"}, {"GA", "Gabon"}, {"GM", "Gambia"}, {"GH", "Ghana"}, + {"GN", "Guinea"}, {"GW", "Guinea-Bissau"}, {"KE", "Kenya"}, + {"LS", "Lesotho"}, {"LR", "Liberia"}, {"LY", "Libya"}, + {"MG", "Madagascar"}, {"MW", "Malawi"}, {"ML", "Mali"}, {"MR", "Mauritania"}, + {"MU", "Mauritius"}, {"MA", "Morocco"}, {"MZ", "Mozambique"}, + {"NA", "Namibia"}, {"NE", "Niger"}, {"NG", "Nigeria"}, + {"RW", "Rwanda"}, {"ST", "Sao Tome and Principe"}, + {"SN", "Senegal"}, {"SC", "Seychelles"}, {"SL", "Sierra Leone"}, + {"SO", "Somalia"}, {"ZA", "South Africa"}, {"SS", "South Sudan"}, + {"SD", "Sudan"}, {"TZ", "Tanzania"}, {"TG", "Togo"}, {"TN", "Tunisia"}, + {"UG", "Uganda"}, {"EH", "Western Sahara"}, {"ZM", "Zambia"}, + {"ZW", "Zimbabwe"} }; QMap antarcticaMap = { @@ -71,57 +75,66 @@ QMap antarcticaMap = { }; QMap asiaMap = { - {"AF", "Afghanistan"}, {"AM", "Armenia"}, {"AZ", "Azerbaijan"}, {"BH", "Bahrain"}, - {"BD", "Bangladesh"}, {"BT", "Bhutan"}, {"BN", "Brunei"}, {"KH", "Cambodia"}, - {"CN", "China"}, {"CY", "Cyprus"}, {"GE", "Georgia"}, {"IN", "India"}, - {"ID", "Indonesia"}, {"IR", "Iran"}, {"IQ", "Iraq"}, {"IL", "Israel"}, - {"JP", "Japan"}, {"JO", "Jordan"}, {"KZ", "Kazakhstan"}, {"KP", "North Korea"}, - {"KR", "South Korea"}, {"KW", "Kuwait"}, {"KG", "Kyrgyzstan"}, {"LA", "Laos"}, - {"LB", "Lebanon"}, {"MY", "Malaysia"}, {"MV", "Maldives"}, {"MN", "Mongolia"}, - {"MM", "Myanmar"}, {"NP", "Nepal"}, {"OM", "Oman"}, {"PK", "Pakistan"}, - {"PS", "Palestine"}, {"PH", "Philippines"}, {"QA", "Qatar"}, {"SA", "Saudi Arabia"}, - {"SG", "Singapore"}, {"LK", "Sri Lanka"}, {"SY", "Syria"}, {"TW", "Taiwan"}, - {"TJ", "Tajikistan"}, {"TH", "Thailand"}, {"TL", "Timor-Leste"}, {"TR", "Turkey"}, - {"TM", "Turkmenistan"}, {"AE", "United Arab Emirates"}, {"UZ", "Uzbekistan"}, {"VN", "Vietnam"}, - {"YE", "Yemen"} + {"AF", "Afghanistan"}, {"AM", "Armenia"}, {"AZ", "Azerbaijan"}, + {"BH", "Bahrain"}, {"BD", "Bangladesh"}, {"BT", "Bhutan"}, + {"BN", "Brunei"}, {"MM", "Myanmar"}, {"KH", "Cambodia"}, {"CN", "China"}, + {"CY", "Cyprus"}, {"GE", "Georgia"}, {"IN", "India"}, {"ID", "Indonesia"}, + {"IR", "Iran"}, {"IQ", "Iraq"}, {"IL", "Israel"}, {"JP", "Japan"}, + {"JO", "Jordan"}, {"KZ", "Kazakhstan"}, {"KW", "Kuwait"}, {"KG", "Kyrgyzstan"}, + {"LA", "Laos"}, {"LB", "Lebanon"}, {"MV", "Maldives"}, {"MY", "Malaysia"}, + {"MN", "Mongolia"}, {"NP", "Nepal"}, {"OM", "Oman"}, {"PK", "Pakistan"}, + {"PH", "Philippines"}, {"QA", "Qatar"}, {"RU", "Russia"}, + {"SA", "Saudi Arabia"}, {"SG", "Singapore"}, {"KR", "South Korea"}, + {"LK", "Sri Lanka"}, {"SY", "Syria"}, {"TJ", "Tajikistan"}, + {"TH", "Thailand"}, {"TL", "Timor-Leste"}, {"TR", "Turkey"}, + {"TM", "Turkmenistan"}, {"AE", "United Arab Emirates"}, + {"UZ", "Uzbekistan"}, {"VN", "Vietnam"}, {"YE", "Yemen"} }; QMap europeMap = { - {"AL", "Albania"}, {"AD", "Andorra"}, {"AT", "Austria"}, {"BY", "Belarus"}, - {"BE", "Belgium"}, {"BA", "Bosnia and Herzegovina"}, {"BG", "Bulgaria"}, {"HR", "Croatia"}, - {"CY", "Cyprus"}, {"CZ", "Czech Republic"}, {"DK", "Denmark"}, {"EE", "Estonia"}, - {"FI", "Finland"}, {"FR", "France"}, {"DE", "Germany"}, {"GR", "Greece"}, - {"HU", "Hungary"}, {"IS", "Iceland"}, {"IE", "Ireland"}, {"IT", "Italy"}, - {"LV", "Latvia"}, {"LI", "Liechtenstein"}, {"LT", "Lithuania"}, {"LU", "Luxembourg"}, - {"MT", "Malta"}, {"MD", "Moldova"}, {"MC", "Monaco"}, {"ME", "Montenegro"}, - {"NL", "Netherlands"}, {"MK", "North Macedonia"}, {"NO", "Norway"}, {"PL", "Poland"}, - {"PT", "Portugal"}, {"RO", "Romania"}, {"RU", "Russia"}, {"SM", "San Marino"}, - {"RS", "Serbia"}, {"SK", "Slovakia"}, {"SI", "Slovenia"}, {"ES", "Spain"}, - {"SE", "Sweden"}, {"CH", "Switzerland"}, {"TR", "Turkey"}, {"UA", "Ukraine"}, - {"GB", "United Kingdom"}, {"VA", "Vatican City"} + {"AL", "Albania"}, {"AD", "Andorra"}, {"AT", "Austria"}, + {"BY", "Belarus"}, {"BE", "Belgium"}, {"BA", "Bosnia and Herzegovina"}, + {"BG", "Bulgaria"}, {"HR", "Croatia"}, {"CY", "Cyprus"}, + {"CZ", "Czech Republic"}, {"DK", "Denmark"}, {"EE", "Estonia"}, + {"FI", "Finland"}, {"FR", "France"}, {"GE", "Georgia"}, + {"DE", "Germany"}, {"GR", "Greece"}, {"HU", "Hungary"}, + {"IS", "Iceland"}, {"IE", "Ireland"}, {"IT", "Italy"}, + {"LV", "Latvia"}, {"LI", "Liechtenstein"}, {"LT", "Lithuania"}, + {"LU", "Luxembourg"}, {"MT", "Malta"}, {"MD", "Moldova"}, + {"MC", "Monaco"}, {"ME", "Montenegro"}, {"NL", "Netherlands"}, + {"MK", "North Macedonia"}, {"NO", "Norway"}, {"PL", "Poland"}, + {"PT", "Portugal"}, {"RO", "Romania"}, {"RU", "Russia"}, + {"SM", "San Marino"}, {"RS", "Serbia"}, {"SK", "Slovakia"}, + {"SI", "Slovenia"}, {"ES", "Spain"}, {"SE", "Sweden"}, + {"CH", "Switzerland"}, {"UA", "Ukraine"}, {"GB", "United Kingdom"}, + {"VA", "Vatican City"} }; QMap northAmericaMap = { - {"AG", "Antigua and Barbuda"}, {"BS", "Bahamas"}, {"BB", "Barbados"}, {"BZ", "Belize"}, - {"CA", "Canada"}, {"CR", "Costa Rica"}, {"CU", "Cuba"}, {"DM", "Dominica"}, - {"DO", "Dominican Republic"}, {"SV", "El Salvador"}, {"GD", "Grenada"}, {"GT", "Guatemala"}, - {"HT", "Haiti"}, {"HN", "Honduras"}, {"JM", "Jamaica"}, {"MX", "Mexico"}, - {"NI", "Nicaragua"}, {"PA", "Panama"}, {"KN", "Saint Kitts and Nevis"}, {"LC", "Saint Lucia"}, - {"VC", "Saint Vincent and the Grenadines"}, {"TT", "Trinidad and Tobago"}, {"US", "United States"} + {"AG", "Antigua and Barbuda"}, {"BS", "Bahamas"}, {"BB", "Barbados"}, + {"BZ", "Belize"}, {"CA", "Canada"}, {"CR", "Costa Rica"}, + {"CU", "Cuba"}, {"DM", "Dominica"}, {"DO", "Dominican Republic"}, + {"SV", "El Salvador"}, {"GD", "Grenada"}, {"GT", "Guatemala"}, + {"HT", "Haiti"}, {"HN", "Honduras"}, {"JM", "Jamaica"}, + {"MX", "Mexico"}, {"NI", "Nicaragua"}, {"PA", "Panama"}, + {"KN", "Saint Kitts and Nevis"}, {"LC", "Saint Lucia"}, + {"VC", "Saint Vincent and the Grenadines"}, {"TT", "Trinidad and Tobago"}, + {"US", "United States"} }; QMap oceaniaMap = { - {"AU", "Australia"}, {"FJ", "Fiji"}, {"KI", "Kiribati"}, {"MH", "Marshall Islands"}, - {"FM", "Micronesia"}, {"NR", "Nauru"}, {"NZ", "New Zealand"}, {"PW", "Palau"}, - {"PG", "Papua New Guinea"}, {"WS", "Samoa"}, {"SB", "Solomon Islands"}, {"TO", "Tonga"}, + {"AU", "Australia"}, {"FJ", "Fiji"}, {"FM", "Micronesia"}, + {"KI", "Kiribati"}, {"MH", "Marshall Islands"}, {"NR", "Nauru"}, + {"NZ", "New Zealand"}, {"PW", "Palau"}, {"PG", "Papua New Guinea"}, + {"WS", "Samoa"}, {"SB", "Solomon Islands"}, {"TO", "Tonga"}, {"TV", "Tuvalu"}, {"VU", "Vanuatu"} }; QMap southAmericaMap = { - {"AR", "Argentina"}, {"BO", "Bolivia"}, {"BR", "Brazil"}, {"CL", "Chile"}, - {"CO", "Colombia"}, {"EC", "Ecuador"}, {"GY", "Guyana"}, {"PY", "Paraguay"}, - {"PE", "Peru"}, {"SR", "Suriname"}, {"TT", "Trinidad and Tobago"}, {"UY", "Uruguay"}, - {"VE", "Venezuela"} + {"AR", "Argentina"}, {"BO", "Bolivia"}, {"BR", "Brazil"}, + {"CL", "Chile"}, {"CO", "Colombia"}, {"EC", "Ecuador"}, + {"GY", "Guyana"}, {"PY", "Paraguay"}, {"PE", "Peru"}, + {"SR", "Suriname"}, {"UY", "Uruguay"}, {"VE", "Venezuela"} }; class ButtonSelectionControl : public QWidget { @@ -145,7 +158,12 @@ public: QJsonObject mapsSelected = QJsonDocument::fromJson(QString::fromStdString(Params().get("MapsSelected")).toUtf8()).object(); - for (const QString &stateCode : map.keys()) { + QList sortedKeys = map.keys(); + std::sort(sortedKeys.begin(), sortedKeys.end(), [&](const QString &a, const QString &b) { + return map[a] < map[b]; + }); + + for (const QString &stateCode : sortedKeys) { if (count % max == 0 && count != 0) { buttonsLayout = new QHBoxLayout(); buttonsLayout->setSpacing(10); diff --git a/selfdrive/ui/qt/onroad/annotated_camera.cc b/selfdrive/ui/qt/onroad/annotated_camera.cc index 3873862638..da4f66302a 100644 --- a/selfdrive/ui/qt/onroad/annotated_camera.cc +++ b/selfdrive/ui/qt/onroad/annotated_camera.cc @@ -874,7 +874,7 @@ void AnnotatedCameraWidget::updateFrogPilotWidgets(int alert_height, const UISce unconfirmedSpeedLimit = speedLimitController ? scene.unconfirmed_speed_limit : 0; useViennaSLCSign = scene.use_vienna_slc_sign; - bool stoppedTimer = scene.stopped_timer && scene.standstill && scene.started_timer / UI_FREQ >= 10; + bool stoppedTimer = scene.stopped_timer && scene.standstill && scene.started_timer / UI_FREQ >= 10 && !mapOpen; if (stoppedTimer) { if (!standstillTimer.isValid()) { standstillTimer.start(); diff --git a/selfdrive/ui/qt/onroad/buttons.cc b/selfdrive/ui/qt/onroad/buttons.cc index b0f4c77e90..7a3f7420dd 100644 --- a/selfdrive/ui/qt/onroad/buttons.cc +++ b/selfdrive/ui/qt/onroad/buttons.cc @@ -161,6 +161,9 @@ void ExperimentalButton::paintEvent(QPaintEvent *event) { } QPainter p(this); + if (use_stock_wheel) { + img = experimental_mode ? experimental_img : engage_img; + } updateBackgroundColor(); drawIcon(p, QPoint(btn_size / 2, btn_size / 2 + y_offset), img, background_color, (isDown() || !engageable) ? 0.6 : 1.0, steering_angle_deg); }