From 09bdc79e69f9d5947bde325c11955c8586863cb1 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 27 Apr 2024 00:43:39 -0500 Subject: [PATCH] wip --- selfdrive/clearpilot/buttons.py | 22 + selfdrive/clearpilot/events.py | 40 + selfdrive/clearpilot/settings/advanced.cc | 1 + selfdrive/clearpilot/settings/advanced.h | 0 selfdrive/clearpilot/settings/basic.cc | 149 ++ selfdrive/clearpilot/settings/basic.example | 280 ++++ selfdrive/clearpilot/settings/basic.h | 34 + selfdrive/clearpilot/settings/basic.h.example | 36 + selfdrive/clearpilot/settings/defaults.cc | 177 +++ selfdrive/clearpilot/settings/defaults.h | 0 selfdrive/clearpilot/settings/newmenus | 38 + selfdrive/clearpilot/settings/notes | 20 + selfdrive/clearpilot/settings/settings.cc | 176 +++ selfdrive/clearpilot/settings/settings.h | 43 + selfdrive/clearpilot/settings/style.cc | 42 + selfdrive/clearpilot/settings/style.h | 16 + selfdrive/clearpilot/settings_sync.py | 0 selfdrive/clearpilot/stocklong.py | 0 .../clearpilot/theme/images/button_flag.png | Bin 0 -> 12051 bytes .../clearpilot/theme/images/button_home.png | Bin 0 -> 10723 bytes .../theme/images/button_settings.png | Bin 0 -> 1846 bytes .../clearpilot/theme/images/turn_signal_1.png | Bin 0 -> 64120 bytes .../theme/images/turn_signal_1_red.png | Bin 0 -> 38001 bytes .../clearpilot/theme/images/turn_signal_2.png | Bin 0 -> 77793 bytes .../clearpilot/theme/images/turn_signal_3.png | Bin 0 -> 84999 bytes .../clearpilot/theme/images/turn_signal_4.png | Bin 0 -> 87564 bytes .../clearpilot/theme/sounds/disengage.wav | Bin 0 -> 972 bytes selfdrive/clearpilot/theme/sounds/engage.wav | Bin 0 -> 972 bytes selfdrive/clearpilot/theme/sounds/firefox.wav | Bin 0 -> 972 bytes selfdrive/clearpilot/theme/sounds/prompt.wav | Bin 0 -> 64634 bytes .../theme/sounds/prompt_distracted.wav | Bin 0 -> 85662 bytes selfdrive/clearpilot/theme/sounds/refuse.wav | Bin 0 -> 83228 bytes .../theme/sounds/warning_immediate.wav | Bin 0 -> 68306 bytes .../clearpilot/theme/sounds/warning_soft.wav | Bin 0 -> 68306 bytes selfdrive/clearpilot/ui/control_settings.cc | 559 +++++++ .../clearpilot/ui/control_settings.cc.org | 559 +++++++ selfdrive/clearpilot/ui/control_settings.h | 54 + .../clearpilot/ui/control_settings.h.org | 53 + .../clearpilot/ui/frogpilot_functions.cc | 177 +++ .../clearpilot/ui/frogpilot_functions.cc.org | 177 +++ selfdrive/clearpilot/ui/frogpilot_functions.h | 661 ++++++++ .../clearpilot/ui/frogpilot_functions.h.org | 661 ++++++++ selfdrive/clearpilot/ui/vehicle_settings.cc | 185 +++ .../clearpilot/ui/vehicle_settings.cc.org | 185 +++ selfdrive/clearpilot/ui/vehicle_settings.h | 34 + .../clearpilot/ui/vehicle_settings.h.org | 34 + selfdrive/clearpilot/ui/visual_settings.cc | 242 +++ .../clearpilot/ui/visual_settings.cc.org | 242 +++ selfdrive/clearpilot/ui/visual_settings.h | 36 + selfdrive/clearpilot/ui/visual_settings.h.org | 36 + selfdrive/clearpilot/weather.cc | 0 selfdrive/clearpilot/weather.h | 0 system/clearpilot/configure/dependencies.sh | 21 + system/clearpilot/notes_wayland.txt | 47 + system/clearpilot/on_boot.sh | 0 system/clearpilot/on_start.sh | 0 system/clearpilot/provision_shell.sh | 4 + system/clearpilot/shell/authorized_keys | 3 + system/clearpilot/shell/bg.jpg | Bin 0 -> 45240 bytes system/clearpilot/shell/configure_ssh.sh | 5 + system/clearpilot/shell/dependencies.sh | 14 + system/clearpilot/shell/init_shell.sh | 16 + .../shell/node_modules/.package-lock.json | 32 + .../shell/node_modules/http/README.md | 9 + .../shell/node_modules/http/package.json | 6 + .../clearpilot/shell/node_modules/ws/LICENSE | 20 + .../shell/node_modules/ws/README.md | 549 +++++++ .../shell/node_modules/ws/browser.js | 8 + .../clearpilot/shell/node_modules/ws/index.js | 13 + .../shell/node_modules/ws/lib/buffer-util.js | 131 ++ .../shell/node_modules/ws/lib/constants.js | 12 + .../shell/node_modules/ws/lib/event-target.js | 292 ++++ .../shell/node_modules/ws/lib/extension.js | 203 +++ .../shell/node_modules/ws/lib/limiter.js | 55 + .../node_modules/ws/lib/permessage-deflate.js | 514 +++++++ .../shell/node_modules/ws/lib/receiver.js | 742 +++++++++ .../shell/node_modules/ws/lib/sender.js | 477 ++++++ .../shell/node_modules/ws/lib/stream.js | 159 ++ .../shell/node_modules/ws/lib/subprotocol.js | 62 + .../shell/node_modules/ws/lib/validation.js | 130 ++ .../node_modules/ws/lib/websocket-server.js | 539 +++++++ .../shell/node_modules/ws/lib/websocket.js | 1336 +++++++++++++++++ .../shell/node_modules/ws/package.json | 68 + .../shell/node_modules/ws/wrapper.mjs | 8 + system/clearpilot/shell/package-lock.json | 38 + system/clearpilot/shell/package.json | 6 + system/clearpilot/shell/revert_logo.sh | 23 + system/clearpilot/shell/set_logo.sh | 54 + system/clearpilot/shell/usr_comma_comma.sh | 95 ++ system/clearpilot/shell/watcher.example.py | 32 + system/clearpilot/shell/watcher.html | 42 + system/clearpilot/shell/watcher.js | 247 +++ system/clearpilot/shell/watcher_run_loop.sh | 20 + system/clearpilot/startup_logo/bg.jpg | Bin 0 -> 45240 bytes system/clearpilot/startup_logo/revert_logo.sh | 23 + system/clearpilot/startup_logo/set_logo.sh | 54 + system/clearpilot/tools/remount_ro.sh | 1 + system/clearpilot/tools/remount_rw.sh | 1 + system/clearpilot/tools/shell_wayland.py | 90 ++ 99 files changed, 11170 insertions(+) create mode 100644 selfdrive/clearpilot/buttons.py create mode 100644 selfdrive/clearpilot/events.py create mode 100644 selfdrive/clearpilot/settings/advanced.cc create mode 100644 selfdrive/clearpilot/settings/advanced.h create mode 100644 selfdrive/clearpilot/settings/basic.cc create mode 100644 selfdrive/clearpilot/settings/basic.example create mode 100644 selfdrive/clearpilot/settings/basic.h create mode 100644 selfdrive/clearpilot/settings/basic.h.example create mode 100644 selfdrive/clearpilot/settings/defaults.cc create mode 100644 selfdrive/clearpilot/settings/defaults.h create mode 100644 selfdrive/clearpilot/settings/newmenus create mode 100644 selfdrive/clearpilot/settings/notes create mode 100644 selfdrive/clearpilot/settings/settings.cc create mode 100644 selfdrive/clearpilot/settings/settings.h create mode 100644 selfdrive/clearpilot/settings/style.cc create mode 100644 selfdrive/clearpilot/settings/style.h create mode 100644 selfdrive/clearpilot/settings_sync.py create mode 100644 selfdrive/clearpilot/stocklong.py create mode 100644 selfdrive/clearpilot/theme/images/button_flag.png create mode 100644 selfdrive/clearpilot/theme/images/button_home.png create mode 100644 selfdrive/clearpilot/theme/images/button_settings.png create mode 100644 selfdrive/clearpilot/theme/images/turn_signal_1.png create mode 100644 selfdrive/clearpilot/theme/images/turn_signal_1_red.png create mode 100644 selfdrive/clearpilot/theme/images/turn_signal_2.png create mode 100644 selfdrive/clearpilot/theme/images/turn_signal_3.png create mode 100644 selfdrive/clearpilot/theme/images/turn_signal_4.png create mode 100644 selfdrive/clearpilot/theme/sounds/disengage.wav create mode 100644 selfdrive/clearpilot/theme/sounds/engage.wav create mode 100644 selfdrive/clearpilot/theme/sounds/firefox.wav create mode 100644 selfdrive/clearpilot/theme/sounds/prompt.wav create mode 100644 selfdrive/clearpilot/theme/sounds/prompt_distracted.wav create mode 100644 selfdrive/clearpilot/theme/sounds/refuse.wav create mode 100644 selfdrive/clearpilot/theme/sounds/warning_immediate.wav create mode 100644 selfdrive/clearpilot/theme/sounds/warning_soft.wav create mode 100644 selfdrive/clearpilot/ui/control_settings.cc create mode 100644 selfdrive/clearpilot/ui/control_settings.cc.org create mode 100644 selfdrive/clearpilot/ui/control_settings.h create mode 100644 selfdrive/clearpilot/ui/control_settings.h.org create mode 100644 selfdrive/clearpilot/ui/frogpilot_functions.cc create mode 100644 selfdrive/clearpilot/ui/frogpilot_functions.cc.org create mode 100644 selfdrive/clearpilot/ui/frogpilot_functions.h create mode 100644 selfdrive/clearpilot/ui/frogpilot_functions.h.org create mode 100644 selfdrive/clearpilot/ui/vehicle_settings.cc create mode 100644 selfdrive/clearpilot/ui/vehicle_settings.cc.org create mode 100644 selfdrive/clearpilot/ui/vehicle_settings.h create mode 100644 selfdrive/clearpilot/ui/vehicle_settings.h.org create mode 100644 selfdrive/clearpilot/ui/visual_settings.cc create mode 100644 selfdrive/clearpilot/ui/visual_settings.cc.org create mode 100644 selfdrive/clearpilot/ui/visual_settings.h create mode 100644 selfdrive/clearpilot/ui/visual_settings.h.org create mode 100644 selfdrive/clearpilot/weather.cc create mode 100644 selfdrive/clearpilot/weather.h create mode 100644 system/clearpilot/configure/dependencies.sh create mode 100644 system/clearpilot/notes_wayland.txt create mode 100644 system/clearpilot/on_boot.sh create mode 100644 system/clearpilot/on_start.sh create mode 100644 system/clearpilot/provision_shell.sh create mode 100644 system/clearpilot/shell/authorized_keys create mode 100644 system/clearpilot/shell/bg.jpg create mode 100644 system/clearpilot/shell/configure_ssh.sh create mode 100644 system/clearpilot/shell/dependencies.sh create mode 100644 system/clearpilot/shell/init_shell.sh create mode 100644 system/clearpilot/shell/node_modules/.package-lock.json create mode 100644 system/clearpilot/shell/node_modules/http/README.md create mode 100644 system/clearpilot/shell/node_modules/http/package.json create mode 100644 system/clearpilot/shell/node_modules/ws/LICENSE create mode 100644 system/clearpilot/shell/node_modules/ws/README.md create mode 100644 system/clearpilot/shell/node_modules/ws/browser.js create mode 100644 system/clearpilot/shell/node_modules/ws/index.js create mode 100644 system/clearpilot/shell/node_modules/ws/lib/buffer-util.js create mode 100644 system/clearpilot/shell/node_modules/ws/lib/constants.js create mode 100644 system/clearpilot/shell/node_modules/ws/lib/event-target.js create mode 100644 system/clearpilot/shell/node_modules/ws/lib/extension.js create mode 100644 system/clearpilot/shell/node_modules/ws/lib/limiter.js create mode 100644 system/clearpilot/shell/node_modules/ws/lib/permessage-deflate.js create mode 100644 system/clearpilot/shell/node_modules/ws/lib/receiver.js create mode 100644 system/clearpilot/shell/node_modules/ws/lib/sender.js create mode 100644 system/clearpilot/shell/node_modules/ws/lib/stream.js create mode 100644 system/clearpilot/shell/node_modules/ws/lib/subprotocol.js create mode 100644 system/clearpilot/shell/node_modules/ws/lib/validation.js create mode 100644 system/clearpilot/shell/node_modules/ws/lib/websocket-server.js create mode 100644 system/clearpilot/shell/node_modules/ws/lib/websocket.js create mode 100644 system/clearpilot/shell/node_modules/ws/package.json create mode 100644 system/clearpilot/shell/node_modules/ws/wrapper.mjs create mode 100644 system/clearpilot/shell/package-lock.json create mode 100644 system/clearpilot/shell/package.json create mode 100644 system/clearpilot/shell/revert_logo.sh create mode 100644 system/clearpilot/shell/set_logo.sh create mode 100644 system/clearpilot/shell/usr_comma_comma.sh create mode 100644 system/clearpilot/shell/watcher.example.py create mode 100644 system/clearpilot/shell/watcher.html create mode 100644 system/clearpilot/shell/watcher.js create mode 100644 system/clearpilot/shell/watcher_run_loop.sh create mode 100644 system/clearpilot/startup_logo/bg.jpg create mode 100644 system/clearpilot/startup_logo/revert_logo.sh create mode 100644 system/clearpilot/startup_logo/set_logo.sh create mode 100644 system/clearpilot/tools/remount_ro.sh create mode 100644 system/clearpilot/tools/remount_rw.sh create mode 100644 system/clearpilot/tools/shell_wayland.py diff --git a/selfdrive/clearpilot/buttons.py b/selfdrive/clearpilot/buttons.py new file mode 100644 index 0000000..7193f67 --- /dev/null +++ b/selfdrive/clearpilot/buttons.py @@ -0,0 +1,22 @@ +import cereal.messaging as messaging +import numpy as np + +from openpilot.common.conversions import Conversions as CV +from openpilot.common.numpy_fast import clip, interp +from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, V_CRUISE_MAX +from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDXS as T_IDXS_MPC +from openpilot.selfdrive.controls.lib.longitudinal_planner import A_CRUISE_MIN, A_CRUISE_MAX_VALS, A_CRUISE_MAX_BP, get_max_accel +from openpilot.selfdrive.modeld.constants import ModelConstants + +from openpilot.selfdrive.frogpilot.functions.conditional_experimental_mode import ConditionalExperimentalMode +from openpilot.selfdrive.frogpilot.functions.map_turn_speed_controller import MapTurnSpeedController +from openpilot.selfdrive.frogpilot.functions.speed_limit_controller import SpeedLimitController + +# Class for intercepting when buttons are pressed, or dispatching buttons to be pressed + + + +class OscarPilotButtons: + def __init__(self, params, params_memory): + self.params_memory = params_memory + \ No newline at end of file diff --git a/selfdrive/clearpilot/events.py b/selfdrive/clearpilot/events.py new file mode 100644 index 0000000..c5818e3 --- /dev/null +++ b/selfdrive/clearpilot/events.py @@ -0,0 +1,40 @@ +import cereal.messaging as messaging +import numpy as np + +from openpilot.common.conversions import Conversions as CV +from openpilot.common.numpy_fast import clip, interp +from openpilot.selfdrive.controls.lib.drive_helpers import CONTROL_N, V_CRUISE_MAX +from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import T_IDXS as T_IDXS_MPC +from openpilot.selfdrive.controls.lib.longitudinal_planner import A_CRUISE_MIN, A_CRUISE_MAX_VALS, A_CRUISE_MAX_BP, get_max_accel +from openpilot.selfdrive.modeld.constants import ModelConstants + +from openpilot.selfdrive.frogpilot.functions.conditional_experimental_mode import ConditionalExperimentalMode +from openpilot.selfdrive.frogpilot.functions.map_turn_speed_controller import MapTurnSpeedController +from openpilot.selfdrive.frogpilot.functions.speed_limit_controller import SpeedLimitController + +# class FrogPilotPlanner: +# def __init__(self, params, params_memory): +# self.params_memory = params_memory +# self.cem = ConditionalExperimentalMode() +# self.mtsc = MapTurnSpeedController() + +# self.override_slc = False + +# self.overridden_speed = 0 +# self.mtsc_target = 0 +# self.slc_target = 0 +# self.v_cruise = 0 +# self.vtsc_target = 0 + +# self.x_desired_trajectory = np.zeros(CONTROL_N) + +# self.update_frogpilot_params(params, params_memory) + +# def update(self, sm, mpc): +# carState, controlsState, modelData = sm['carState'], sm['controlsState'], sm['modelV2'] + +# enabled = controlsState.enabled + +# v_cruise_kph = min(controlsState.vCruise, V_CRUISE_MAX) +# v_cruise = v_cruise_kph * CV.KPH_TO_MS +# v_ego = carState.vEgo \ No newline at end of file diff --git a/selfdrive/clearpilot/settings/advanced.cc b/selfdrive/clearpilot/settings/advanced.cc new file mode 100644 index 0000000..8eb1354 --- /dev/null +++ b/selfdrive/clearpilot/settings/advanced.cc @@ -0,0 +1 @@ +// Should show a UI showing the settings menu for stock frogpilot \ No newline at end of file diff --git a/selfdrive/clearpilot/settings/advanced.h b/selfdrive/clearpilot/settings/advanced.h new file mode 100644 index 0000000..e69de29 diff --git a/selfdrive/clearpilot/settings/basic.cc b/selfdrive/clearpilot/settings/basic.cc new file mode 100644 index 0000000..391e75f --- /dev/null +++ b/selfdrive/clearpilot/settings/basic.cc @@ -0,0 +1,149 @@ +#include "selfdrive/oscarpilot/settings/basic.h" +#include "selfdrive/ui/ui.h" + +OscarPilotBasicPanel::OscarPilotBasicPanel(OscarSettingsWindow *parent) : FrogPilotListWidget(parent) { + + const std::vector> visualToggles { + // {"HelloWorld", "Hello World", "Hi!", "../frogpilot/assets/wheel_images/frog.png"}, + { + "OpenpilotEnabledToggle","Enable OpenPilot", + "Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off.", + "../assets/offroad/icon_openpilot.png", + }, + { + "AlwaysOnLateral", "Always on Lateral", + "Maintain openpilot lateral control when the brake pedal is used.\n\nDeactivation occurs only through the 'Cruise Control' button.", "../frogpilot/assets/toggle_icons/icon_always_on_lateral.png" + }, + {"VisionTurnControl", "Vision Turn Speed Controller", "Slow down for detected road curvature for smoother curve handling.", "../frogpilot/assets/toggle_icons/icon_vtc.png"}, + + // { + // "ConditionalExperimental", "Slow for curves", + // "Engages 'experimental mode' when a curve is detected, temporairly reducing max speed.", "../frogpilot/assets/toggle_icons/icon_conditional.png" + // }, + // Alert on stopsign / stoplight + + {"LaneChangeAssist", "Lane Change Assist", "Automatically change lanes on turn signal and wheel nudge at highway speeds.", "../frogpilot/assets/toggle_icons/icon_lane.png"}, + {"HyundaiLKAS", "Use Hyundai LKAS when available", "Let the Hyundai LKAS feature steer the car when lanes are detected and HDA mode is available.", ""}, + {"FireTheBabysitter", "Relaxed Driver Monitoring", "Increases driver attention warning timeout from 6 to 15 seconds during the daytime and when no lead car is detected.", ""}, +// - Hands On Wheel: Always / At Dusk / 2+ hrs driving + + // Move this to dashcam subgroup + //{"DashCam", "Dash Cam Recording", "Record video and gps data for all drives automatically.", ""} + }; + + for (const auto &[param, title, desc, icon] : visualToggles) { + ParamControl *toggle; + + toggle = new ParamControl(param, title, desc, icon, this); + + addItem(toggle); + toggles[param.toStdString()] = toggle; + + QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() { + updateToggles(); + }); + + QObject::connect(static_cast(toggle), &FrogPilotParamValueControl::buttonPressed, [this]() { + updateToggles(); + }); + + QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() { + update(); + }); + + QObject::connect(static_cast(toggle), &FrogPilotParamManageControl::manageButtonClicked, [this]() { + update(); + }); + } + + // std::set rebootKeys = {"DriveStats"}; + // for (const std::string &key : rebootKeys) { + // QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() { + // if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + // Hardware::reboot(); + // } + // }); + // } + + + // power buttons + QHBoxLayout *power_layout = new QHBoxLayout(); + power_layout->setSpacing(30); + + QPushButton *reboot_btn = new QPushButton(tr("Reboot")); + reboot_btn->setObjectName("reboot_btn"); + power_layout->addWidget(reboot_btn); + QObject::connect(reboot_btn, &QPushButton::clicked, this, &OscarPilotBasicPanel::reboot); + + QPushButton *poweroff_btn = new QPushButton(tr("Power Off")); + poweroff_btn->setObjectName("poweroff_btn"); + power_layout->addWidget(poweroff_btn); + QObject::connect(poweroff_btn, &QPushButton::clicked, this, &OscarPilotBasicPanel::poweroff); + + if (!Hardware::PC()) { + connect(uiState(), &UIState::offroadTransition, poweroff_btn, &QPushButton::setVisible); + } + + setStyleSheet(R"( + #reboot_btn { height: 120px; border-radius: 15px; background-color: #393939; } + #reboot_btn:pressed { background-color: #4a4a4a; } + #poweroff_btn { height: 120px; border-radius: 15px; background-color: #E22C2C; } + #poweroff_btn:pressed { background-color: #FF2424; } + )"); + addItem(power_layout); +} + +void OscarPilotBasicPanel::updateToggles() { + std::thread([this]() { + paramsMemory.putBool("FrogPilotTogglesUpdated", true); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + paramsMemory.putBool("FrogPilotTogglesUpdated", false); + }).detach(); +} + +void OscarPilotBasicPanel::parentToggleClicked() { + this->openParentToggle(); +} + +void OscarPilotBasicPanel::hideSubToggles() { + // for (auto &[key, toggle] : toggles) { + // bool subToggles = modelUIKeys.find(key.c_str()) != modelUIKeys.end() || + // customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end() || + // customThemeKeys.find(key.c_str()) != customThemeKeys.end() || + // qolKeys.find(key.c_str()) != qolKeys.end(); + // toggle->setVisible(!subToggles); + // } + + this->closeParentToggle(); +} + +void OscarPilotBasicPanel::hideEvent(QHideEvent *event) { + hideSubToggles(); +} + + +void OscarPilotBasicPanel::reboot() { + if (!uiState()->engaged()) { + if (ConfirmationDialog::confirm(tr("Are you sure you want to reboot?"), tr("Reboot"), this)) { + // Check engaged again in case it changed while the dialog was open + if (!uiState()->engaged()) { + params.putBool("DoReboot", true); + } + } + } else { + ConfirmationDialog::alert(tr("Disengage to Reboot"), this); + } +} + +void OscarPilotBasicPanel::poweroff() { + if (!uiState()->engaged()) { + if (ConfirmationDialog::confirm(tr("Are you sure you want to power off?"), tr("Power Off"), this)) { + // Check engaged again in case it changed while the dialog was open + if (!uiState()->engaged()) { + params.putBool("DoShutdown", true); + } + } + } else { + ConfirmationDialog::alert(tr("Disengage to Power Off"), this); + } +} diff --git a/selfdrive/clearpilot/settings/basic.example b/selfdrive/clearpilot/settings/basic.example new file mode 100644 index 0000000..d3af63b --- /dev/null +++ b/selfdrive/clearpilot/settings/basic.example @@ -0,0 +1,280 @@ +#include "selfdrive/oscarpilot/settings/basic.h" +#include "selfdrive/ui/ui.h" + +OscarPilotBasicPanel::OscarPilotBasicPanel(OscarSettingsWindow *parent) : FrogPilotListWidget(parent) { + const std::vector> visualToggles { + {"CustomTheme", "Custom Themes", "Enable the ability to use custom themes.", "../frogpilot/assets/wheel_images/frog.png"}, + {"CustomColors", "Color Theme", "Switch out the standard openpilot color scheme with a custom color scheme.\n\nWant to submit your own color scheme? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + {"CustomIcons", "Icon Pack", "Switch out the standard openpilot icons with a set of custom icons.\n\nWant to submit your own icon pack? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + {"CustomSignals", "Turn Signals", "Add custom animations for your turn signals for a personal touch!\n\nWant to submit your own turn signal animation? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + {"CustomSounds", "Sound Pack", "Switch out the standard openpilot sounds with a set of custom sounds.\n\nWant to submit your own sound pack? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + + {"CameraView", "Camera View", "Choose your preferred camera view for the onroad UI. This is a visual change only and doesn't impact openpilot.", "../frogpilot/assets/toggle_icons/icon_camera.png"}, + {"Compass", "Compass", "Add a compass to your onroad UI.", "../frogpilot/assets/toggle_icons/icon_compass.png"}, + + {"CustomUI", "Custom Onroad UI", "Customize the Onroad UI with some additional visual functions.", "../assets/offroad/icon_road.png"}, + {"AdjacentPath", "Adjacent Paths", "Display paths to the left and right of your car, visualizing where the model detects lanes.", ""}, + {"BlindSpotPath", "Blind Spot Path", "Visualize your blind spots with a red path when another vehicle is detected nearby.", ""}, + {"ShowFPS", "FPS Counter", "Display the Frames Per Second (FPS) of your onroad UI for monitoring system performance.", ""}, + {"LeadInfo", "Lead Info and Logics", "Get detailed information about the vehicle ahead, including speed and distance, and the logic behind your following distance.", ""}, + {"RoadNameUI", "Road Name", "See the name of the road you're on at the bottom of your screen. Sourced from OpenStreetMap.", ""}, + {"UseVienna", "Use Vienna Speed Limit Signs", "Use the Vienna (EU) speed limit style signs as opposed to MUTCD (US).", ""}, + + {"DriverCamera", "Driver Camera On Reverse", "Show the driver's camera feed when you shift to reverse.", "../assets/img_driver_face_static.png"}, + {"GreenLightAlert", "Green Light Alert", "Get an alert when a traffic light changes from red to green.", "../frogpilot/assets/toggle_icons/icon_green_light.png"}, + + {"ModelUI", "Model UI", "Personalize how the model's visualizations appear on your screen.", "../assets/offroad/icon_calibration.png"}, + {"AccelerationPath", "Acceleration Path", "Visualize the car's intended acceleration or deceleration with a color-coded path.", ""}, + {"LaneLinesWidth", "Lane Lines", "Adjust the visual thickness of lane lines on your display.\n\nDefault matches the MUTCD average of 4 inches.", ""}, + {"PathEdgeWidth", "Path Edges", "Adjust the width of the path edges shown on your UI to represent different driving modes and statuses.\n\nDefault is 20% of the total path.\n\nBlue = Navigation\nLight Blue = Always On Lateral\nGreen = Default with 'FrogPilot Colors'\nLight Green = Default with stock colors\nOrange = Experimental Mode Active\nYellow = Conditional Overriden", ""}, + {"PathWidth", "Path Width", "Customize the width of the driving path shown on your UI.\n\nDefault matches the width of a 2019 Lexus ES 350.", ""}, + {"RoadEdgesWidth", "Road Edges", "Adjust the visual thickness of road edges on your display.\n\nDefault is 1/2 of the MUTCD average lane line width of 4 inches.", ""}, + {"UnlimitedLength", "'Unlimited' Road UI Length", "Extend the display of the path, lane lines, and road edges as far as the system can detect, providing a more expansive view of the road ahead.", ""}, + + {"QOLVisuals", "Quality of Life", "Miscellaneous quality of life changes to improve your overall openpilot experience.", "../frogpilot/assets/toggle_icons/quality_of_life.png"}, + {"DriveStats", "Drive Stats In Home Screen", "Display your device's drive stats in the home screen.", ""}, + {"HideSpeed", "Hide Speed", "Hide the speed indicator in the onroad UI.", ""}, + {"ShowSLCOffset", "Show Speed Limit Offset", "Show the speed limit offset seperated from the speed limit in the onroad UI when using 'Speed Limit Controller'.", ""}, + + {"RandomEvents", "Random Events", "Enjoy a bit of unpredictability with random events that can occur during certain driving conditions.", "../frogpilot/assets/toggle_icons/icon_random.png"}, + {"ScreenBrightness", "Screen Brightness", "Customize your screen brightness.", "../frogpilot/assets/toggle_icons/icon_light.png"}, + {"SilentMode", "Silent Mode", "Mute openpilot sounds for a quieter driving experience.", "../frogpilot/assets/toggle_icons/icon_mute.png"}, + {"WheelIcon", "Steering Wheel Icon", "Replace the default steering wheel icon with a custom design, adding a unique touch to your interface.", "../assets/offroad/icon_openpilot.png"}, + }; + + for (const auto &[param, title, desc, icon] : visualToggles) { + ParamControl *toggle; + + if (param == "CameraView") { + std::vector cameraOptions{tr("Auto"), tr("Standard"), tr("Wide"), tr("Driver")}; + FrogPilotButtonParamControl *preferredCamera = new FrogPilotButtonParamControl(param, title, desc, icon, cameraOptions); + toggle = preferredCamera; + + } else if (param == "CustomTheme") { + FrogPilotParamManageControl *customThemeToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(customThemeToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(customThemeKeys.find(key.c_str()) != customThemeKeys.end()); + } + }); + toggle = customThemeToggle; + } else if (param == "CustomColors" || param == "CustomIcons" || param == "CustomSignals" || param == "CustomSounds") { + std::vector themeOptions{tr("Stock"), tr("Frog"), tr("Tesla"), tr("Stalin")}; + FrogPilotButtonParamControl *themeSelection = new FrogPilotButtonParamControl(param, title, desc, icon, themeOptions); + toggle = themeSelection; + + if (param == "CustomSounds") { + QObject::connect(static_cast(toggle), &FrogPilotButtonParamControl::buttonClicked, [this](int id) { + if (id == 1) { + if (FrogPilotConfirmationDialog::yesorno("Do you want to enable the bonus 'Goat' sound effect?", this)) { + params.putBool("GoatScream", true); + } else { + params.putBool("GoatScream", false); + } + } + }); + } + + } else if (param == "CustomUI") { + FrogPilotParamManageControl *customUIToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(customUIToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end()); + } + }); + toggle = customUIToggle; + } else if (param == "LeadInfo") { + std::vector leadInfoToggles{tr("UseSI")}; + std::vector leadInfoToggleNames{tr("Use SI Values")}; + toggle = new FrogPilotParamToggleControl(param, title, desc, icon, leadInfoToggles, leadInfoToggleNames); + + } else if (param == "ModelUI") { + FrogPilotParamManageControl *modelUIToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(modelUIToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(modelUIKeys.find(key.c_str()) != modelUIKeys.end()); + } + }); + toggle = modelUIToggle; + } else if (param == "LaneLinesWidth" || param == "RoadEdgesWidth") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 24, std::map(), this, false, " inches"); + } else if (param == "PathEdgeWidth") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, std::map(), this, false, "%"); + } else if (param == "PathWidth") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, std::map(), this, false, " feet", 10); + + } else if (param == "QOLVisuals") { + FrogPilotParamManageControl *qolToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(qolToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(qolKeys.find(key.c_str()) != qolKeys.end()); + } + }); + toggle = qolToggle; + + } else if (param == "ScreenBrightness") { + std::map brightnessLabels; + for (int i = 0; i <= 101; ++i) { + brightnessLabels[i] = i == 0 ? "Screen Off" : i == 101 ? "Auto" : QString::number(i) + "%"; + } + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 101, brightnessLabels, this, false); + + } else if (param == "WheelIcon") { + std::vector wheelToggles{"RotatingWheel"}; + std::vector wheelToggleNames{tr("Rotating")}; + std::map steeringWheelLabels = {{0, "Stock"}, {1, "Lexus"}, {2, "Toyota"}, {3, "Frog"}, {4, "Rocket"}, {5, "Hyundai"}, {6, "Stalin"}}; + toggle = new FrogPilotParamValueToggleControl(param, title, desc, icon, 0, 6, steeringWheelLabels, this, true, "", 1, wheelToggles, wheelToggleNames); + + } else { + toggle = new ParamControl(param, title, desc, icon, this); + } + + addItem(toggle); + toggles[param.toStdString()] = toggle; + + QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() { + updateToggles(); + }); + + QObject::connect(static_cast(toggle), &FrogPilotParamValueControl::buttonPressed, [this]() { + updateToggles(); + }); + + QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() { + update(); + }); + + QObject::connect(static_cast(toggle), &FrogPilotParamManageControl::manageButtonClicked, [this]() { + update(); + }); + } + + std::set rebootKeys = {"DriveStats"}; + for (const std::string &key : rebootKeys) { + QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() { + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + }); + } + + customOnroadUIKeys = {"AdjacentPath", "BlindSpotPath", "ShowFPS", "LeadInfo", "RoadNameUI", "UseVienna"}; + customThemeKeys = {"CustomColors", "CustomIcons", "CustomSignals", "CustomSounds"}; + modelUIKeys = {"AccelerationPath", "LaneLinesWidth", "PathEdgeWidth", "PathWidth", "RoadEdgesWidth", "UnlimitedLength"}; + qolKeys = {"DriveStats", "HideSpeed", "ShowSLCOffset"}; + + QObject::connect(device(), &Device::interactiveTimeout, this, &OscarPilotBasicPanel::hideSubToggles); + QObject::connect(parent, &OscarSettingsWindow::closeParentToggle, this, &OscarPilotBasicPanel::hideSubToggles); + // QObject::connect(parent, &OscarSettingsWindow::updateMetric, this, &OscarPilotBasicPanel::updateMetric); + + hideSubToggles(); + // updateMetric(); +} + +void OscarPilotBasicPanel::updateToggles() { + std::thread([this]() { + paramsMemory.putBool("FrogPilotTogglesUpdated", true); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + paramsMemory.putBool("FrogPilotTogglesUpdated", false); + }).detach(); +} + +// void OscarPilotBasicPanel::updateMetric() { +// bool previousIsMetric = isMetric; +// isMetric = params.getBool("IsMetric"); + +// if (isMetric != previousIsMetric) { +// double distanceConversion = isMetric ? INCH_TO_CM : CM_TO_INCH; +// double speedConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT; +// params.putInt("LaneLinesWidth", std::nearbyint(params.getInt("LaneLinesWidth") * distanceConversion)); +// params.putInt("RoadEdgesWidth", std::nearbyint(params.getInt("RoadEdgesWidth") * distanceConversion)); +// params.putInt("PathWidth", std::nearbyint(params.getInt("PathWidth") * speedConversion)); +// } + +// FrogPilotParamValueControl *laneLinesWidthToggle = static_cast(toggles["LaneLinesWidth"]); +// FrogPilotParamValueControl *roadEdgesWidthToggle = static_cast(toggles["RoadEdgesWidth"]); +// FrogPilotParamValueControl *pathWidthToggle = static_cast(toggles["PathWidth"]); + +// if (isMetric) { +// laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the Vienna average of 10 centimeters."); +// roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the Vienna average lane line width of 10 centimeters."); + +// laneLinesWidthToggle->updateControl(0, 60, " centimeters"); +// roadEdgesWidthToggle->updateControl(0, 60, " centimeters"); +// pathWidthToggle->updateControl(0, 30, " meters"); +// } else { +// laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the MUTCD average of 4 inches."); +// roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the MUTCD average lane line width of 4 inches."); + +// laneLinesWidthToggle->updateControl(0, 24, " inches"); +// roadEdgesWidthToggle->updateControl(0, 24, " inches"); +// pathWidthToggle->updateControl(0, 100, " feet"); +// } + +// laneLinesWidthToggle->refresh(); +// roadEdgesWidthToggle->refresh(); + +// previousIsMetric = isMetric; +// } + +// void OscarPilotBasicPanel::updateMetric() { +// bool previousIsMetric = isMetric; +// isMetric = params.getBool("IsMetric"); + +// if (isMetric != previousIsMetric) { +// double distanceConversion = isMetric ? INCH_TO_CM : CM_TO_INCH; +// double speedConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT; +// params.putInt("LaneLinesWidth", std::nearbyint(params.getInt("LaneLinesWidth") * distanceConversion)); +// params.putInt("RoadEdgesWidth", std::nearbyint(params.getInt("RoadEdgesWidth") * distanceConversion)); +// params.putInt("PathWidth", std::nearbyint(params.getInt("PathWidth") * speedConversion)); +// } + +// FrogPilotParamValueControl *laneLinesWidthToggle = static_cast(toggles["LaneLinesWidth"]); +// FrogPilotParamValueControl *roadEdgesWidthToggle = static_cast(toggles["RoadEdgesWidth"]); +// FrogPilotParamValueControl *pathWidthToggle = static_cast(toggles["PathWidth"]); + +// if (isMetric) { +// laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the Vienna average of 10 centimeters."); +// roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the Vienna average lane line width of 10 centimeters."); + +// laneLinesWidthToggle->updateControl(0, 60, " centimeters"); +// roadEdgesWidthToggle->updateControl(0, 60, " centimeters"); +// pathWidthToggle->updateControl(0, 30, " meters"); +// } else { +// laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the MUTCD average of 4 inches."); +// roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the MUTCD average lane line width of 4 inches."); + +// laneLinesWidthToggle->updateControl(0, 24, " inches"); +// roadEdgesWidthToggle->updateControl(0, 24, " inches"); +// pathWidthToggle->updateControl(0, 100, " feet"); +// } + +// laneLinesWidthToggle->refresh(); +// roadEdgesWidthToggle->refresh(); + +// previousIsMetric = isMetric; +// } + +void OscarPilotBasicPanel::parentToggleClicked() { + this->openParentToggle(); +} + +void OscarPilotBasicPanel::hideSubToggles() { + for (auto &[key, toggle] : toggles) { + bool subToggles = modelUIKeys.find(key.c_str()) != modelUIKeys.end() || + customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end() || + customThemeKeys.find(key.c_str()) != customThemeKeys.end() || + qolKeys.find(key.c_str()) != qolKeys.end(); + toggle->setVisible(!subToggles); + } + + this->closeParentToggle(); +} + +void OscarPilotBasicPanel::hideEvent(QHideEvent *event) { + hideSubToggles(); +} diff --git a/selfdrive/clearpilot/settings/basic.h b/selfdrive/clearpilot/settings/basic.h new file mode 100644 index 0000000..481bafb --- /dev/null +++ b/selfdrive/clearpilot/settings/basic.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/oscarpilot/settings/settings.h" + +class OscarPilotBasicPanel : public FrogPilotListWidget { + Q_OBJECT + +public: + explicit OscarPilotBasicPanel(OscarSettingsWindow *parent); + +signals: + void closeParentToggle(); + void openParentToggle(); + +private: + void hideEvent(QHideEvent *event); + void hideSubToggles(); + void parentToggleClicked(); + void updateToggles(); + void poweroff(); + void reboot(); + + std::set customOnroadUIKeys; + + std::map toggles; + + Params params; + Params paramsMemory{"/dev/shm/params"}; + + bool isMetric = params.getBool("IsMetric"); +}; diff --git a/selfdrive/clearpilot/settings/basic.h.example b/selfdrive/clearpilot/settings/basic.h.example new file mode 100644 index 0000000..78a07ac --- /dev/null +++ b/selfdrive/clearpilot/settings/basic.h.example @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/oscarpilot/settings/settings.h" + +class OscarPilotBasicPanel : public FrogPilotListWidget { + Q_OBJECT + +public: + explicit OscarPilotBasicPanel(OscarSettingsWindow *parent); + +signals: + void closeParentToggle(); + void openParentToggle(); + +private: + void hideEvent(QHideEvent *event); + void hideSubToggles(); + void parentToggleClicked(); + void updateMetric(); + void updateToggles(); + + std::set customOnroadUIKeys; + std::set customThemeKeys; + std::set modelUIKeys; + std::set qolKeys; + + std::map toggles; + + Params params; + Params paramsMemory{"/dev/shm/params"}; + + bool isMetric = params.getBool("IsMetric"); +}; diff --git a/selfdrive/clearpilot/settings/defaults.cc b/selfdrive/clearpilot/settings/defaults.cc new file mode 100644 index 0000000..0a9ee13 --- /dev/null +++ b/selfdrive/clearpilot/settings/defaults.cc @@ -0,0 +1,177 @@ +#include + +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/ui/ui.h" + +bool FrogPilotConfirmationDialog::toggle(const QString &prompt_text, const QString &confirm_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, confirm_text, tr("Reboot Later"), false, parent); + return d.exec(); +} + +bool FrogPilotConfirmationDialog::toggleAlert(const QString &prompt_text, const QString &button_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, button_text, "", false, parent); + return d.exec(); +} + +bool FrogPilotConfirmationDialog::yesorno(const QString &prompt_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, tr("Yes"), tr("No"), false, parent); + return d.exec(); +} + +FrogPilotButtonIconControl::FrogPilotButtonIconControl(const QString &title, const QString &text, const QString &desc, const QString &icon, QWidget *parent) : AbstractControl(title, desc, icon, parent) { + btn.setText(text); + btn.setStyleSheet(R"( + QPushButton { + padding: 0; + border-radius: 50px; + font-size: 35px; + font-weight: 500; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + QPushButton:disabled { + color: #33E4E4E4; + } + )"); + btn.setFixedSize(250, 100); + QObject::connect(&btn, &QPushButton::clicked, this, &FrogPilotButtonIconControl::clicked); + hlayout->addWidget(&btn); +} + +void setDefaultParams() { + Params params = Params(); + bool FrogsGoMoo = params.get("DongleId").substr(0, 3) == "be6"; + + bool brianbot = params.get("DongleId").substr(0, 6) == "90bb71"; + + std::map defaultValues { + {"AccelerationPath", brianbot ? "1" : "0"}, + {"AccelerationProfile", brianbot ? "2" : "2"}, + {"AdjacentPath", FrogsGoMoo ? "1" : "0"}, + {"AdjustablePersonalities", "0"}, + {"AggressiveAcceleration", "1"}, + {"AggressiveFollow", FrogsGoMoo ? "10" : "12"}, + {"AggressiveJerk", FrogsGoMoo ? "6" : "5"}, + {"AlwaysOnLateral", "1"}, + {"AlwaysOnLateralMain", brianbot ? "1" : "0"}, + {"AverageCurvature", brianbot ? "1" : "0"}, + {"BlindSpotPath", "1"}, + {"CameraView", FrogsGoMoo ? "1" : "0"}, + {"CECurves", "1"}, + {"CECurvesLead", "0"}, + {"CENavigation", "1"}, + {"CESignal", "1"}, + {"CESlowerLead", "0"}, + {"CESpeed", "0"}, + {"CESpeedLead", "0"}, + {"CEStopLights", "0"}, + {"CEStopLightsLead", FrogsGoMoo ? "0" : "0"}, + {"Compass", FrogsGoMoo ? "1" : "0"}, + {"ConditionalExperimental", "1"}, + {"CurveSensitivity", FrogsGoMoo ? "125" : "100"}, + {"CustomColors", "1"}, + {"CustomIcons", "1"}, + {"CustomPersonalities", "0"}, + {"CustomSignals", "0"}, + {"CustomSounds", "1"}, + {"CustomTheme", "1"}, + {"CustomUI", "0"}, + {"DeviceShutdown", "1"}, + {"DisableOnroadUploads", "1"}, + {"DriverCamera", "0"}, + {"DriveStats", "1"}, + {"EVTable", FrogsGoMoo ? "0" : "1"}, + {"ExperimentalModeActivation", "1"}, + {"ExperimentalModeViaLKAS", "0"}, + {"ExperimentalModeViaScreen", FrogsGoMoo ? "0" : "1"}, + {"Fahrenheit", "0"}, + {"FireTheBabysitter", FrogsGoMoo ? "1" : "0"}, + {"FullMap", "0"}, + {"GasRegenCmd", "0"}, + {"GoatScream", "0"}, + {"GreenLightAlert", "0"}, + {"HideSpeed", "0"}, + {"HigherBitrate", "0"}, + {"LaneChangeTime", "0"}, + {"LaneDetection", "1"}, + {"LaneLinesWidth", "4"}, + {"LateralTune", "1"}, + {"LeadInfo", FrogsGoMoo ? "1" : "0"}, + {"LockDoors", "0"}, + {"LongitudinalTune", "1"}, + {"LongPitch", FrogsGoMoo ? "0" : "1"}, + {"LowerVolt", FrogsGoMoo ? "0" : "1"}, + {"Model", "3"}, + {"ModelUI", "1"}, + {"MTSCEnabled", "1"}, + {"MuteDM", FrogsGoMoo ? "1" : "1"}, + {"MuteDoor", FrogsGoMoo ? "1" : "1"}, + {"MuteOverheated", FrogsGoMoo ? "1" : "0"}, + {"MuteSeatbelt", FrogsGoMoo ? "1" : "0"}, + {"NNFF", FrogsGoMoo ? "1" : "1"}, + {"NoLogging", "1"}, + {"NudgelessLaneChange", "0"}, + {"NumericalTemp", FrogsGoMoo ? "1" : "0"}, + {"Offset1", "3"}, + {"Offset2", FrogsGoMoo ? "7" : "5"}, + {"Offset3", "7"}, + {"Offset4", FrogsGoMoo ? "20" : "7"}, + {"OneLaneChange", "1"}, + {"PathEdgeWidth", "20"}, + {"PathWidth", "61"}, + {"PauseLateralOnSignal", "20"}, + {"PreferredSchedule", "0"}, + {"QOLControls", "1"}, + {"QOLVisuals", "1"}, + {"RandomEvents", FrogsGoMoo ? "1" : "0"}, + {"RelaxedFollow", "30"}, + {"RelaxedJerk", "50"}, + {"ReverseCruise", "0"}, + {"RoadEdgesWidth", "2"}, + {"RoadNameUI", "1"}, + {"RotatingWheel", "1"}, + {"ScreenBrightness", "101"}, + {"SearchInput", "0"}, + {"ShowCPU", FrogsGoMoo ? "1" : "0"}, + {"ShowFPS", FrogsGoMoo ? "1" : "0"}, + {"ShowGPU", "0"}, + {"ShowMemoryUsage", FrogsGoMoo ? "1" : "0"}, + {"Sidebar", FrogsGoMoo ? "1" : "0"}, + {"SilentMode", "0"}, + {"SLCFallback", "2"}, + {"SLCOverride", FrogsGoMoo ? "2" : "1"}, + {"SLCPriority", "1"}, + {"SmoothBraking", "1"}, + {"SNGHack", FrogsGoMoo ? "0" : "1"}, + {"SpeedLimitController", "1"}, + {"StandardFollow", "15"}, + {"StandardJerk", "10"}, + {"StoppingDistance", FrogsGoMoo ? "6" : "0"}, + {"TSS2Tune", "1"}, + {"TurnAggressiveness", FrogsGoMoo ? "150" : "100"}, // Test 90? + {"TurnDesires", "0"}, + {"UnlimitedLength", "1"}, + {"UseSI", FrogsGoMoo ? "1" : "0"}, + {"UseVienna", "0"}, + {"VisionTurnControl", "1"}, + {"WheelIcon", FrogsGoMoo ? "1" : "0"} + }; + + bool rebootRequired = false; + for (const auto &[key, value] : defaultValues) { + if (params.get(key).empty()) { + params.put(key, value); + rebootRequired = true; + } + } + + if (rebootRequired) { + while (!std::filesystem::exists("/data/openpilot/prebuilt")) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + Hardware::reboot(); + } +} diff --git a/selfdrive/clearpilot/settings/defaults.h b/selfdrive/clearpilot/settings/defaults.h new file mode 100644 index 0000000..e69de29 diff --git a/selfdrive/clearpilot/settings/newmenus b/selfdrive/clearpilot/settings/newmenus new file mode 100644 index 0000000..79cdbd3 --- /dev/null +++ b/selfdrive/clearpilot/settings/newmenus @@ -0,0 +1,38 @@ +Device +Network & Services +- Standard Wifi +- Metered Wifi +- SSH +- Web companion + - Route logging + - Dashcam upload + - Live driver monitoring / fleet mgr +- Weather + - Display alerts + - API key +- Random facts + - Get random fact about area driver is in (spoken, ai) +Basic +- Enable openpilot / Dashcam only +- Always on Lateral: True / False +- Longitudial Control scheme: Stock / Stock+SLC / OpenPilot +- Experimental Mode: never / on curves / always +- Longitudial Control scheme: Stock / Stock+SLC / Experimental +- Speed Limit offset customization: +- Lane Change Assist: Disabled / Nudge Wheel +- Driver Attention Monitoring: Strict / Relaxed +- Hands On Wheel: Always / At Dusk / 2+ hrs driving +Advanced + Navigation +Customization +Extras + - Window down notification + - Set climate on drive mode + +Fleet Mgr Notes: + - Seperate fork for fleet mgr + - Self drive preferences + - Distance traveled + - SLC + - Driver camera + diff --git a/selfdrive/clearpilot/settings/notes b/selfdrive/clearpilot/settings/notes new file mode 100644 index 0000000..132b28a --- /dev/null +++ b/selfdrive/clearpilot/settings/notes @@ -0,0 +1,20 @@ +Goals: + +- slow down on experimental mode +- LKAS button - should toggle between drive, weather, weather radar. Hold for screen off +- car dashboard should have enough indicators that it is able to represent drive state without screen on +- set speed limit on engage cruise control + +qol: +- customize babysitter - driver awareness timeouts daytime, nighttime, require steering wheel +- set climate on start, roll up windows on stop +- upload park location on stop +- low bandwidth / high bandwidth wifi, upload recordings on high bandwidth +- list drives w/ image on stop + - stop light / stop sign warning alert + + release: + - reenable training screen + - - disregard for my device id + - cleanup code + - rename to diamondpilot \ No newline at end of file diff --git a/selfdrive/clearpilot/settings/settings.cc b/selfdrive/clearpilot/settings/settings.cc new file mode 100644 index 0000000..3e5b69a --- /dev/null +++ b/selfdrive/clearpilot/settings/settings.cc @@ -0,0 +1,176 @@ +#include "selfdrive/ui/qt/offroad/settings.h" + +#include +#include +#include +#include +#include + +#include +#include + +#include "selfdrive/ui/qt/network/networking.h" + +#include "common/params.h" +#include "common/watchdog.h" +#include "common/util.h" +#include "system/hardware/hw.h" +#include "selfdrive/ui/qt/widgets/controls.h" +#include "selfdrive/ui/qt/widgets/input.h" +#include "selfdrive/ui/qt/widgets/scrollview.h" +#include "selfdrive/ui/qt/widgets/ssh_keys.h" +#include "selfdrive/ui/qt/widgets/toggle.h" +#include "selfdrive/ui/ui.h" +#include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/qt/qt_window.h" + +#include "selfdrive/frogpilot/navigation/ui/navigation_settings.h" +#include "selfdrive/frogpilot/ui/control_settings.h" +#include "selfdrive/oscarpilot/settings/basic.h" +#include "selfdrive/frogpilot/ui/visual_settings.h" + +#include "selfdrive/oscarpilot/settings/settings.h" + + +void OscarSettingsWindow::showEvent(QShowEvent *event) { + setCurrentPanel(0); +} + +void OscarSettingsWindow::setCurrentPanel(int index, const QString ¶m) { + panel_widget->setCurrentIndex(index); + nav_btns->buttons()[index]->setChecked(true); + if (!param.isEmpty()) { + emit expandToggleDescription(param); + } +} + +OscarSettingsWindow::OscarSettingsWindow(QWidget *parent) : QFrame(parent) { + + // setup two main layouts + sidebar_widget = new QWidget; + QVBoxLayout *sidebar_layout = new QVBoxLayout(sidebar_widget); + sidebar_layout->setMargin(0); + panel_widget = new QStackedWidget(); + + // close button + QPushButton *close_btn = new QPushButton(tr("← Back")); + close_btn->setStyleSheet(R"( + QPushButton { + font-size: 50px; + padding-bottom: 0px; + border 1px grey solid; + border-radius: 25px; + background-color: #292929; + font-weight: 500; + } + QPushButton:pressed { + background-color: #3B3B3B; + } + )"); + close_btn->setFixedSize(300, 125); + sidebar_layout->addSpacing(10); + sidebar_layout->addWidget(close_btn, 0, Qt::AlignRight); + QObject::connect(close_btn, &QPushButton::clicked, [this]() { + if (frogPilotTogglesOpen) { + frogPilotTogglesOpen = false; + this->closeParentToggle(); + } else { + this->closeSettings(); + } + }); + + FrogPilotControlsPanel *frogpilotControls = new FrogPilotControlsPanel(this); + QObject::connect(frogpilotControls, &FrogPilotControlsPanel::closeParentToggle, this, [this]() {frogPilotTogglesOpen = false;}); + QObject::connect(frogpilotControls, &FrogPilotControlsPanel::openParentToggle, this, [this]() {frogPilotTogglesOpen = true;}); + + // DevicePanel *device = new DevicePanel(this); + // QObject::connect(device, &DevicePanel::reviewTrainingGuide, this, &SettingsWindow::reviewTrainingGuide); + // QObject::connect(device, &DevicePanel::showDriverView, this, &SettingsWindow::showDriverView); + + QList> panels = { + {tr("Basic"), new OscarPilotBasicPanel(this)}, + {tr("Advanced"), frogpilotControls}, + {tr("Network"), new Networking(this)}, + {tr("Software"), new SoftwarePanel(this)}, + // {tr("Device"), new DevicePanel(this)}, + // FrogPilotControlsPanel + // {tr("OscarCloud"), basic}, + // {tr("Logging"), basic}, // Log / Upload driver cam, Routes + // {tr("System"), new OscarPilotBasicPanel(this)}, // Debugging + // {tr("Status"), basic}, // Report on stuff like connectivity, free space, detected features + // {tr("Extra"), basic}, // Custom cloud services, QOL automations + }; + + nav_btns = new QButtonGroup(this); + for (auto &[name, panel] : panels) { + QPushButton *btn = new QPushButton(name); + btn->setCheckable(true); + btn->setChecked(nav_btns->buttons().size() == 0); + btn->setStyleSheet(R"( + QPushButton { + color: grey; + border: none; + background: none; + font-size: 65px; + font-weight: 500; + } + QPushButton:checked { + color: white; + } + QPushButton:pressed { + color: #ADADAD; + } + )"); + btn->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); + nav_btns->addButton(btn); + sidebar_layout->addWidget(btn, 0, Qt::AlignRight); + + const int lr_margin = name != tr("Network") ? 50 : 0; // Network panel handles its own margins + panel->setContentsMargins(lr_margin, 25, lr_margin, 25); + + ScrollView *panel_frame = new ScrollView(panel, this); + panel_widget->addWidget(panel_frame); + + if (name == tr("Controls") || name == tr("Visuals")) { + QScrollBar *scrollbar = panel_frame->verticalScrollBar(); + + QObject::connect(scrollbar, &QScrollBar::valueChanged, this, [this](int value) { + if (!frogPilotTogglesOpen) { + previousScrollPosition = value; + } + }); + + QObject::connect(scrollbar, &QScrollBar::rangeChanged, this, [this, panel_frame]() { + panel_frame->restorePosition(previousScrollPosition); + }); + } + + QObject::connect(btn, &QPushButton::clicked, [=, w = panel_frame]() { + previousScrollPosition = 0; + btn->setChecked(true); + panel_widget->setCurrentWidget(w); + }); + } + sidebar_layout->setContentsMargins(50, 50, 100, 50); + + // main settings layout, sidebar + main panel + QHBoxLayout *main_layout = new QHBoxLayout(this); + + sidebar_widget->setFixedWidth(500); + main_layout->addWidget(sidebar_widget); + main_layout->addWidget(panel_widget); + + setStyleSheet(R"( + * { + color: white; + font-size: 50px; + } + OscarSettingsWindow { + background-color: black; + } + QStackedWidget, ScrollView { + background-color: #292929; + border-radius: 30px; + } + )"); +} diff --git a/selfdrive/clearpilot/settings/settings.h b/selfdrive/clearpilot/settings/settings.h new file mode 100644 index 0000000..5f5b3a9 --- /dev/null +++ b/selfdrive/clearpilot/settings/settings.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "selfdrive/ui/qt/util.h" +#include "selfdrive/ui/qt/widgets/controls.h" + +// ********** settings window + top-level panels ********** +class OscarSettingsWindow : public QFrame { + Q_OBJECT + +public: + explicit OscarSettingsWindow(QWidget *parent = 0); + void setCurrentPanel(int index, const QString ¶m = ""); + +protected: + void showEvent(QShowEvent *event) override; + +signals: + void closeSettings(); + void showDriverView(); + void expandToggleDescription(const QString ¶m); + + // FrogPilot signals + void closeParentToggle(); +private: + QWidget *sidebar_widget; + QButtonGroup *nav_btns; + QStackedWidget *panel_widget; + + // FrogPilot variables + bool frogPilotTogglesOpen; + int previousScrollPosition; +}; + diff --git a/selfdrive/clearpilot/settings/style.cc b/selfdrive/clearpilot/settings/style.cc new file mode 100644 index 0000000..6ccf74a --- /dev/null +++ b/selfdrive/clearpilot/settings/style.cc @@ -0,0 +1,42 @@ +#include + +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/ui/ui.h" + +bool FrogPilotConfirmationDialog::toggle(const QString &prompt_text, const QString &confirm_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, confirm_text, tr("Reboot Later"), false, parent); + return d.exec(); +} + +bool FrogPilotConfirmationDialog::toggleAlert(const QString &prompt_text, const QString &button_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, button_text, "", false, parent); + return d.exec(); +} + +bool FrogPilotConfirmationDialog::yesorno(const QString &prompt_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, tr("Yes"), tr("No"), false, parent); + return d.exec(); +} + +FrogPilotButtonIconControl::FrogPilotButtonIconControl(const QString &title, const QString &text, const QString &desc, const QString &icon, QWidget *parent) : AbstractControl(title, desc, icon, parent) { + btn.setText(text); + btn.setStyleSheet(R"( + QPushButton { + padding: 0; + border-radius: 50px; + font-size: 35px; + font-weight: 500; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + QPushButton:disabled { + color: #33E4E4E4; + } + )"); + btn.setFixedSize(250, 100); + QObject::connect(&btn, &QPushButton::clicked, this, &FrogPilotButtonIconControl::clicked); + hlayout->addWidget(&btn); +} diff --git a/selfdrive/clearpilot/settings/style.h b/selfdrive/clearpilot/settings/style.h new file mode 100644 index 0000000..0d2161a --- /dev/null +++ b/selfdrive/clearpilot/settings/style.h @@ -0,0 +1,16 @@ + +const button_style = R"( + QPushButton { + color: grey; + border: none; + background: none; + font-size: 65px; + font-weight: 500; + } + QPushButton:checked { + color: white; + } + QPushButton:pressed { + color: #ADADAD; + } +)"; \ No newline at end of file diff --git a/selfdrive/clearpilot/settings_sync.py b/selfdrive/clearpilot/settings_sync.py new file mode 100644 index 0000000..e69de29 diff --git a/selfdrive/clearpilot/stocklong.py b/selfdrive/clearpilot/stocklong.py new file mode 100644 index 0000000..e69de29 diff --git a/selfdrive/clearpilot/theme/images/button_flag.png b/selfdrive/clearpilot/theme/images/button_flag.png new file mode 100644 index 0000000000000000000000000000000000000000..f942d76594fbb0e50d487fc676e3932ed6fe0ede GIT binary patch literal 12051 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

>oS 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 literal 0 HcmV?d00001 diff --git a/selfdrive/clearpilot/theme/images/button_home.png b/selfdrive/clearpilot/theme/images/button_home.png new file mode 100644 index 0000000000000000000000000000000000000000..bcfd02df082da574c13b580cd3ee8addfd050b26 GIT binary patch literal 10723 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 bSKB!wXfd6$&++0A;7?jyL9ANDDDZy(EW)RG literal 0 HcmV?d00001 diff --git a/selfdrive/clearpilot/theme/images/turn_signal_1_red.png b/selfdrive/clearpilot/theme/images/turn_signal_1_red.png new file mode 100644 index 0000000000000000000000000000000000000000..7c102456e6efb6c985ec6d4b6963366f1399a9cd GIT binary patch literal 38001 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 ZOu~d2mZQ;Ck`4#^s3~bHw#eH={~yMK+lc@G literal 0 HcmV?d00001 diff --git a/selfdrive/clearpilot/theme/images/turn_signal_2.png b/selfdrive/clearpilot/theme/images/turn_signal_2.png new file mode 100644 index 0000000000000000000000000000000000000000..e8e147976b7330cca51b7dc7dc66c63df871cf81 GIT binary patch literal 77793 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

48nGMXSmpF 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 literal 0 HcmV?d00001 diff --git a/selfdrive/clearpilot/theme/images/turn_signal_3.png b/selfdrive/clearpilot/theme/images/turn_signal_3.png new file mode 100644 index 0000000000000000000000000000000000000000..b59b003f95eb2fbf69700cd5419e0d39a8b7a688 GIT binary patch literal 84999 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%0DCsQvsBqC~5VoON^WjDhhVf z`qNhg-QO8{c>6j|>7i`J>)U)SSKzV(;S+!ETOW1zc=GGP)mMDqo;`Ko=YU_L)A6v` z@1jppI8BJncZ>5v=DyWp-_p8lkc<$Z=l6v1ImH5#c!q3|!?H=7A?bx}N8X+un(AH3 z6ac!uSOf;AL|Nx(7(XPgF3PI3$ZD%>(eY8b;EFYwek95k*K9mmxlyNBnGIUCYOTeX zCP?we5vLVhR^3;X(9!;gS+&WUV|syjb~dRzw!|)$mH3L!RC7^Mq%V7?16M4;j8V4Se^u6C3X2t%=%v0m6%2V; zSg``*=HB*STc|WGyB3gjMU{aox;#S1>ROwbAgmI$)yNEwfF`YHKBiPdjR1?dz<8PGP4aJlhRlo#mXxpo?q+^i^47f{j7nAL&YULuAxe0JG7q%KVS zC0i+j?hQiJXbp#D!){%%OclEFDP6e0OOP~8Ms84zL*aY{o2_8J|B_a0Is=q?g;g${ z0NC1N6}x0^N{p_|2VHTSanSR8ga~BPN#YJ?sk1u8be_tb%lE=15E8tlCD`&KOmVR) zm$=jy-1(1Z+PeHpTfJyxfn|M7+f?>^!i;M^kR-_% z=A&tqDFB+*qqz|Q$(Vp`vJ45@Tnl|otZcPCm!TUt7kqQW_hu{WQ{NJpdrrXu`u zK-gY6_xAz4=rwhb8?+NaBiz(ugv|7oKYDU8G7zx|Fmoza*#tt{e1@zF)kmiVL95PD z6TloYVCgCAAqq*la*$OG;-r+$A)}_amUPn5x$WWStRAEVnktndY&eWCFxpefXLKSL zFp~qbDnraeMy=Yxwvv)|ExQz~#*K$9E7gEHT7qm@h}430Am_rI{}Qa@B8AT`34xp1 zScVrnKK2h{9E?q6NV9K`Gg1R=ZB&U#a%lzsQsGL{&=D`g+W(N()9JL zEuO}GvHX%s(6Ifqs^i?ELeTNhb=foxkRrt-K0r3F(Q*55n^39mjiu5C0kTzAqFDk% zAW_!jAt0(-OKaH7HmQ|rd4{}(;>8R@ zCP|YOJ)dhk+v_4N$z-)~`qY8iu@Sh*3KEy0RxZ(o zR9lb)THROLrBO0TYq3VkyrIXK&)~vv*u$C1p=Qq9lp~fV5Hbz-A|A*|k&wBRPZMZX zY)rSPP^H`?nT_WghZ5b4N}=!T08;oo4sS<-NQF+|VH9-5IGTwZLiDdK#9YUeJVqCO z(0NEecwr@|mGNrc-&b-8J~$Az&v)ot)2=_+EDB6o$csAg&;m|!`WUxFFf7GP+Y5nV zK#@&H4o6JaU{yUwf_vs?#h{$SV_s8j`?>87ay>;S2xcmlaJ>q>j*kI42<0l^I`UP7 zoXTPkF&KYEcNiWr2-N(X#ADQ$9k6nDWOivGOQ>1otX3;h0wxPP3A43o2M!}+l8?ls zTF9W=q(!W_@kli(kE1hHyW*(dgO@cZXYrS|Ecaalr}__{x$VQWOuLBov*7sSj zz~xg?4{5bPyjV!&(uv^F=wcui zS7$NB-XuYsvvTs)0*o7;Lx0Q!Wtk!Dc-ZbROQ9nxHRk`)35ukKZ+FDQlkG)rKDA@= z`Ah_oR3*kAQyQLPWPM20SBH?cIx#@N7TyZO@j_B%>-wSfA0M;DOK#SjRk7u1BAG~N zVbX?Mqu=jJ)j?7A1alnJ2bj-tRJjg$Y7U@8H|Uxfs-dPPUdrn)4LPI0Ia_m&OU zeb2{U^?|!C?^d;b^z{l{z7@FaK=}Q)eSd#GsGm2EtXJd_o}AhXcu|9@T!{ZhZRg@6 zI_P(#g>?nC20Ns9`Gz;S`5u4P2F?Io3QuWa@tzL20} zY_LQ}Smi=y*zQwPMoG4XeN1tH1I#9=jAK|G3mHP>2CE;L0a|IBO6I#%F^A9JZf;6E zk#-#!wM#*|NdA{s*MouJrM>*jjBr_T8-k2fo0{n-M+n-HkpN>e$st2k#!`uM-k0Z` zuUQxlHxSPfAv;B3fW>?YJE*WV9AXOtnYFSC+{ZrVWL?%StXiE~#5&EqhSq#d=B|ur z5(_mcfj}0jW|L6z!o!RP0<%S}fx{je0UR=bDaTPWbjh1UgS<+lnsvQKDovTZ za>3QC3i;-3c!7nyoWQmcgkg@IaEK8G^4Zbj_8elIo5hlqu~_6dIK8jt_0fht7Ed

WebSocket Test Page

+ + diff --git a/system/clearpilot/shell/watcher.js b/system/clearpilot/shell/watcher.js new file mode 100644 index 0000000..0e4d376 --- /dev/null +++ b/system/clearpilot/shell/watcher.js @@ -0,0 +1,247 @@ +const net = require('net'); +const fs = require('fs'); +const socketPath = '/tmp/oscar_watcher.sock'; + +// from openpilot.common.watcher import Watcher +// Watcher.log_watch("LastGPSPosition", location) + +//// UNIXSOCKET SERVER //// + +let progvars = {}; + +// Remove the socket file if it already exists +if (fs.existsSync( socketPath )) { + try { + fs.unlinkSync(socketPath); + } catch (err) { + if (err.code !== 'ENOENT') { + console.error('Error removing existing socket file:', err); + process.exit(1); + } + } +} + +const unix_socket_server = net.createServer((connection) => { + // console.log('UnixSocket Client connected.'); + + let buffer = ''; + + connection.on('data', (data) => { + buffer += data.toString(); + let boundary = buffer.indexOf('\n'); + while (boundary !== -1) { + const message = buffer.substring(0, boundary); + buffer = buffer.substring(boundary + 1); + processMessage(message); + boundary = buffer.indexOf('\n'); + } + }); + + connection.on('end', () => { + // console.log('UnixSocket Client disconnected.'); + }); +}); + +unix_socket_server.listen(socketPath, () => { + console.log(`UnixSocket Server listening on ${socketPath}`); +}); + +function processMessage(message) { + console.log(message); + try { + msg = JSON.parse(message); + console.log(msg); + let variable = msg[0]; + let value = msg[1]; + console.log({var: variable, val: value}); + const diff = calculateDiff(variable, progvars[variable], value); + console.log({diff: diff}) + send_ws_message(diff); + progvars[variable] = value; + + const timestamp = new Date().toISOString(); + const logEntry = `log_time="${timestamp}";\n${diff}\n`; + + fs.writeFile('/data/openpilot/logs/watcher.log', logEntry, { flag: 'a' }, (err) => { + if (err) { + console.error('Error writing to log file:', err); + } + }); + } catch (err) { + console.error('Error processing message:', err); + } +} + +function calculateDiff(provVarsVariable, oldValue, newValue) { + const changes = []; + + function findChanges(path, oldVal, newVal) { + // Check if both values are objects (and not null), otherwise compare directly + if (!(typeof oldVal === 'object' && oldVal !== null) || + !(typeof newVal === 'object' && newVal !== null)) { + if (oldVal !== newVal) { + changes.push(`${path} = ${JSON.stringify(newVal)};`); + } + return oldVal !== newVal ? 1 : 0; + } + + const oldKeys = Object.keys(oldVal); + const newKeys = Object.keys(newVal); + const allKeys = new Set([...oldKeys, ...newKeys]); + let changedCount = 0; + + allKeys.forEach(key => { + const oldKeyValue = oldVal[key]; + const newKeyValue = newVal[key]; + const currentPath = path ? `${path}[${JSON.stringify(key)}]` : `[${JSON.stringify(key)}]`; + + if (!oldVal || !(key in oldVal)) { + // New key added + changes.push(`${currentPath} = ${JSON.stringify(newKeyValue)};`); + changedCount++; + } else if (typeof oldKeyValue === 'object' && oldKeyValue !== null && typeof newKeyValue === 'object' && newKeyValue !== null) { + // Recursive diff for objects + const subChanges = findChanges(currentPath, oldKeyValue, newKeyValue); + if (subChanges > 0) changedCount += subChanges; + } else if (oldKeyValue !== newKeyValue) { + // Direct value change + changes.push(`${currentPath} = ${JSON.stringify(newKeyValue)};`); + changedCount++; + } + }); + + // If more than 1/3 of the properties have been changed, replace the entire node + if (changedCount > 0 && changedCount > oldKeys.length / 3) { + // Clear individual changes as we replace the entire node + changes.splice(-changedCount); + // Replace the node + changes.push(`${path} = ${JSON.stringify(newVal)};`); + return 0; + } + + return changedCount; + } + + // Adjust initial call to handle non-object types + if ((typeof oldValue === 'object' && oldValue !== null) && (typeof newValue === 'object' && newValue !== null)) { + findChanges('progvars['+JSON.stringify(provVarsVariable)+']', oldValue, newValue); + } else if (oldValue !== newValue) { + changes.push(`progvars[${JSON.stringify(provVarsVariable)}] = ${JSON.stringify(newValue)};`); + } + + return changes.join('\n'); +} + + +//// HTTP SERVER //// + +const WebSocket = require('ws'); +const http = require('http'); +const url = require('url'); +const path = require('path'); +const hostname = '0.0.0.0'; +const port = 1024; + +const server = http.createServer((req, res) => { + if(req.url === '/') { + // Serve the HTML file + fs.readFile(path.join(__dirname, 'watcher.html'), (err, data) => { + if(err) { + res.writeHead(500); + res.end('Error loading watcher.html'); + return; + } + res.writeHead(200, {'Content-Type': 'text/html'}); + res.end(data); + }); + } else { + // Handle 404 + res.writeHead(404); + res.end('Not found'); + } +}); + +server.listen(port, hostname, () => { + console.log(`Web Server running at http://${hostname}:${port}/`); +}); + + +//// WEBSOCKET SERVER //// +ws_port = port + 1; + +// Attach WebSocket server to the HTTP server +const wss = new WebSocket.Server({ port: ws_port }); + +console.log(`WebSocket Server running at http://${hostname}:${ws_port}/`); + +wss.on('connection', function connection(ws) { + console.log('WebSocket client connected'); + + // Send initial state + ws.send(calculateDiff({}, progvars)); + ws.send("progvars = "+JSON.stringify(progvars)+";"); + + ws.on('message', function incoming(message) { + console.log('received: %s', message); + }); + + ws.on('close', function close() { + console.log('WebSocket client disconnected'); + }); +}); + +// Handle upgrade of the request +wss.on('upgrade', function upgrade(request, socket, head) { + const { pathname } = url.parse(request.url); + + if (pathname === '/ws') { + wss.handleUpgrade(request, socket, head, function done(ws) { + wss.emit('connection', ws, request); + }); + } else { + socket.destroy(); + } +}); + +// Function to send a message to all connected WebSocket clients +function send_ws_message(message) { + wss.clients.forEach(function each(client) { + if (client.readyState === WebSocket.OPEN) { + client.send(message); + } + }); +} + + +//// Exit when low disk space ///// + +const { exec } = require('child_process'); + +// Function to check disk space +function checkDiskSpace() { + exec('df -BG /data | tail -n 1 | awk \'{print $4}\'', (error, stdout, stderr) => { + if (error) { + console.error(`exec error: ${error}`); + return; + } + if (stderr) { + console.error(`stderr: ${stderr}`); + return; + } + + // Extract the number of GBs available + const freeSpaceGB = parseInt(stdout.trim().replace('G', '')); + + // Check if free space is less than 10GB + if (freeSpaceGB < 9) { + console.log('Less than 9GB of free space on /data. Exiting.'); + process.exit(1); + } + }); +} + +// Check disk space every 10 seconds +setInterval(checkDiskSpace, 10000); + +// Perform an initial check +checkDiskSpace(); diff --git a/system/clearpilot/shell/watcher_run_loop.sh b/system/clearpilot/shell/watcher_run_loop.sh new file mode 100644 index 0000000..0c4054e --- /dev/null +++ b/system/clearpilot/shell/watcher_run_loop.sh @@ -0,0 +1,20 @@ +cd /data/openpilot/shell + +while true +do + + nodejs watcher.js + + # Get free space on /data in GB + free_space=$(df -BG /data | tail -n 1 | awk '{print $4}' | sed 's/G//') + + # Check if free space is less than 10GB + if [ "$free_space" -lt 10 ]; then + echo "Less than 10GB of free space on /data. Exiting." + exit 1 + fi + + echo crashed, waiting 30 seconds + sleep 30 + +done diff --git a/system/clearpilot/startup_logo/bg.jpg b/system/clearpilot/startup_logo/bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..19ac03752e724b0a7b5d1c206886bb643d911c46 GIT binary patch literal 45240 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 literal 0 HcmV?d00001 diff --git a/system/clearpilot/startup_logo/revert_logo.sh b/system/clearpilot/startup_logo/revert_logo.sh new file mode 100644 index 0000000..a50b2ed --- /dev/null +++ b/system/clearpilot/startup_logo/revert_logo.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Check if /data/openpilot/shell/bg.jpg does not exist +if [ ! -f /data/openpilot/shell/bg.jpg ]; then + # Check if /usr/comma/bg.org does exist + if [ -f /usr/comma/bg.org ]; then + sudo mount -o remount,rw / + # Copy /usr/comma/bg.org to /usr/comma/bg.jpg + sudo mv -f /usr/comma/bg.org /usr/comma/bg.jpg + # Remove /usr/comma/bg.org + # sudo rm /usr/comma/bg.org + if [ -f /usr/comma/comma.org ]; then + sudo mv -f /usr/comma/comma.org /usr/comma/comma.sh + fi + echo Reverted custom logo for comma boot sequence + sudo sync + sleep 2 + sudo reboot + while true; do + sleep 1 + done + fi +fi \ No newline at end of file diff --git a/system/clearpilot/startup_logo/set_logo.sh b/system/clearpilot/startup_logo/set_logo.sh new file mode 100644 index 0000000..e0cc12e --- /dev/null +++ b/system/clearpilot/startup_logo/set_logo.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +set -x + +# Test: sudo mount -o remount,rw /; cp /usr/comma/bg.org /usr/comma/bg.jpg; bash shell/set_logo.sh + +# Check if md5sum of /usr/comma/bg.jpg is not equal to md5sum of /data/openpilot/shell/bg.jpg +if [ "$(md5sum /usr/comma/bg.jpg | awk '{print $1}')" != "$(md5sum /data/openpilot/shell/bg.jpg | awk '{print $1}')" ]; then + + # If /usr/comma/bg.org does not exist + if [ ! -f /usr/comma/bg.org ]; then + if [[ "$(md5sum /usr/comma/bg.jpg | awk '{print $1}')" == "642380ba4c0f00b16e9cf6e613f43eec" ]]; then + sudo mount -o remount,rw / + sudo cp /usr/comma/bg.jpg /usr/comma/bg.org + fi + fi + + if [[ "$(md5sum /usr/comma/bg.org | awk '{print $1}')" != "642380ba4c0f00b16e9cf6e613f43eec" ]]; then + sudo mount -o remount,ro / + echo failed to backup the correct picture + exit + fi + + sudo mount -o remount,rw / + + # If /usr/comma/bg.org does exist + if [ -f /usr/comma/bg.org ]; then + sudo cp -f /data/openpilot/shell/bg.jpg /usr/comma/bg.jpg + fi + + # If file /usr/comma/revert_logo.sh does not exist + if [ "$(md5sum /data/openpilot/shell/revert_logo.sh | awk '{print $1}')" != "$(md5sum /usr/comma/revert_logo.sh | awk '{print $1}')" ]; then + sudo cp /data/openpilot/shell/revert_logo.sh /usr/comma/revert_logo.sh + fi + + if [ "$(md5sum md5sum /usr/comma/comma.sh | awk '{print $1}')" != "$(md5sum /data/openpilot/shell/usr_comma_comma.sh | awk '{print $1}')" ]; then + if [[ "$(md5sum /usr/comma/comma.sh | awk '{print $1}')" == "ddbac0b46dd02efd672a0ef31ca426cf" ]]; then + if [ ! -f /usr/comma/comma.org ]; then + sudo cp /usr/comma/comma.sh /usr/comma/comma.org + fi + fi + if [-f /usr/comma/comma.org ]; then + sudo cp /data/openpilot/shell/usr_comma_comma.sh /usr/comma/comma.sh + echo updated comma.sh + fi + fi + + echo Applied custom logo for comma boot sequence + sudo sync + sleep 2 + sudo mount -o remount,ro / + sudo sync + sleep 2 +fi diff --git a/system/clearpilot/tools/remount_ro.sh b/system/clearpilot/tools/remount_ro.sh new file mode 100644 index 0000000..f4c166f --- /dev/null +++ b/system/clearpilot/tools/remount_ro.sh @@ -0,0 +1 @@ +sudo mount -o remount,ro / diff --git a/system/clearpilot/tools/remount_rw.sh b/system/clearpilot/tools/remount_rw.sh new file mode 100644 index 0000000..f819cb8 --- /dev/null +++ b/system/clearpilot/tools/remount_rw.sh @@ -0,0 +1 @@ +sudo mount -o remount,rw / diff --git a/system/clearpilot/tools/shell_wayland.py b/system/clearpilot/tools/shell_wayland.py new file mode 100644 index 0000000..351a1fc --- /dev/null +++ b/system/clearpilot/tools/shell_wayland.py @@ -0,0 +1,90 @@ +import os +import sys +import signal +import logging +import platform +from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QScrollBar, QGraphicsView, QGraphicsScene, QGraphicsProxyWidget +from PyQt5.QtCore import Qt, QCoreApplication +from PyQt5.QtGui import QFont, QScreen + +import termqt +from termqt import Terminal, TerminalPOSIXExecIO + +class ExitOnMessageHandler(logging.Handler): + def emit(self, record): + if "Spawned process has been killed" in record.getMessage(): + QApplication.quit() # Exit the application gracefully + +def setup_logger(): + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + handler = logging.StreamHandler() + formatter = logging.Formatter("[%(asctime)s] > [%(filename)s:%(lineno)d] %(message)s") + handler.setFormatter(formatter) + logger.addHandler(handler) + handler2 = ExitOnMessageHandler() + logger.addHandler(handler2) + return logger + +def create_terminal_app(): + os.environ["XDG_RUNTIME_DIR"] = "/var/tmp/weston" + os.environ["WAYLAND_DISPLAY"] = "wayland-0" + os.environ["QT_QPA_PLATFORM"] = "wayland" + os.environ["QT_WAYLAND_SHELL_INTEGRATION"] = "wl-shell" + + + QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling) + app = QApplication(sys.argv) + desktop = QApplication.desktop() + ag = desktop.availableGeometry(desktop.primaryScreen()) + print (ag.width()) + print (ag.height()) + + window = QWidget() + window.setWindowTitle("termqt on {}".format(platform.system())) + window.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) + window.setGeometry(0,0, ag.width(), ag.height()) + window.setStyleSheet("background-color: black;") + window.showFullScreen() + + scene = QGraphicsScene() + view = QGraphicsView(scene, window) + print (window.width()) + print (window.height()) + view.setGeometry(0, 0, window.width(), window.height()) + view.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + view.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + + layout = QHBoxLayout() + terminal = Terminal(window.width(), window.height(), logger=setup_logger(), font_size=32) + + proxy_terminal = scene.addWidget(terminal) + view.setScene(scene) + view.rotate(90) # Rotate the view by 90 degrees clockwise + + window_layout = QHBoxLayout(window) + window_layout.addWidget(view) + window_layout.setContentsMargins(0,0,0,0) + window.setLayout(window_layout) + + return app, window, terminal + +def main(): + signal.signal(signal.SIGINT, signal.SIG_DFL) # Enable Ctrl+C + if len(sys.argv) < 2: + print("Usage: python start.py ''") + return + + command = "bash -c '{}'".format(sys.argv[1]) + app, window, terminal = create_terminal_app() + platform_name = platform.system() + terminal_io = TerminalPOSIXExecIO(terminal.col_len, terminal.row_len, command, os.environ, setup_logger()) + terminal_io.stdout_callback = terminal.stdout + terminal.stdin_callback = terminal_io.write + terminal.resize_callback = terminal_io.resize + terminal_io.spawn() + exit_code = app.exec_() + sys.exit(exit_code) + +if __name__ == "__main__": + main() \ No newline at end of file

~L(Y?U44XQmT7sXlbH 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 I$eD%wKhFYN#sB~S literal 0 HcmV?d00001 diff --git a/selfdrive/clearpilot/theme/images/turn_signal_4.png b/selfdrive/clearpilot/theme/images/turn_signal_4.png new file mode 100644 index 0000000000000000000000000000000000000000..c3c1d204e6837572096cc6a10fc11c554b060af3 GIT binary patch literal 87564 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 z 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 literal 0 HcmV?d00001 diff --git a/selfdrive/clearpilot/theme/sounds/prompt_distracted.wav b/selfdrive/clearpilot/theme/sounds/prompt_distracted.wav new file mode 100644 index 0000000000000000000000000000000000000000..c3d4475caa70ceeafec4cc26185c2f62101e0f60 GIT binary patch literal 85662 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%0AyQVhYu{{CccQg0 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 literal 0 HcmV?d00001 diff --git a/selfdrive/clearpilot/theme/sounds/warning_immediate.wav b/selfdrive/clearpilot/theme/sounds/warning_immediate.wav new file mode 100644 index 0000000000000000000000000000000000000000..a8c778fa926361947806ab75f3773ef7ad1db9f7 GIT binary patch literal 68306 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 Xy~cQ82D;ZA;^-d8@> controlToggles { + {"AdjustablePersonalities", "Adjustable Personalities", "Use the 'Distance' button on the steering wheel or the onroad UI to switch between openpilot's driving personalities.\n\n1 bar = Aggressive\n2 bars = Standard\n3 bars = Relaxed", "../frogpilot/assets/toggle_icons/icon_distance.png"}, + {"AlwaysOnLateral", "Always on Lateral", "Maintain openpilot lateral control when the brake or gas pedals are used.\n\nDeactivation occurs only through the 'Cruise Control' button.", "../frogpilot/assets/toggle_icons/icon_always_on_lateral.png"}, + + {"ConditionalExperimental", "Conditional Experimental Mode", "Automatically switches to 'Experimental Mode' under predefined conditions.", "../frogpilot/assets/toggle_icons/icon_conditional.png"}, + {"CECurves", "Curve Detected Ahead", "Switch to 'Experimental Mode' when a curve is detected.", ""}, + {"CENavigation", "Navigation Based", "Switch to 'Experimental Mode' based on navigation data. (i.e. Intersections, stop signs, etc.)", ""}, + {"CESlowerLead", "Slower Lead Detected Ahead", "Switch to 'Experimental Mode' when a slower lead vehicle is detected ahead.", ""}, + // {"CEStopLights", "Stop Lights and Stop Signs", "Switch to 'Experimental Mode' when a stop light or stop sign is detected.", ""}, + {"CESignal", "Turn Signal When Below Highway Speeds", "Switch to 'Experimental Mode' when using turn signals below highway speeds to help assit with turns.", ""}, + {"CSLCEnabled", "Custom Stock Longitudinal Control", "Use cruise control button spamming to adjust cruise set speed based on MTSC, VTSC, and SLC", "../frogpilot/assets/toggle_icons/icon_custom.png"}, + {"CustomPersonalities", "Custom Driving Personalities", "Customize the driving personality profiles to your driving style.", "../frogpilot/assets/toggle_icons/icon_custom.png"}, + {"DeviceShutdown", "Device Shutdown Timer", "Configure the timer for automatic device shutdown when offroad conserving energy and preventing battery drain.", "../frogpilot/assets/toggle_icons/icon_time.png"}, + {"ExperimentalModeActivation", "Experimental Mode Via", "Toggle Experimental Mode by double-clicking the 'Lane Departure'/'LKAS' button or double tapping screen.\n\nOverrides 'Conditional Experimental Mode'.", "../assets/img_experimental_white.svg"}, + + {"FireTheBabysitter", "Fire the Babysitter", "Deactivate some of openpilot's 'Babysitter' protocols for more user autonomy.", "../frogpilot/assets/toggle_icons/icon_babysitter.png"}, + {"NoLogging", "Disable All Logging", "Turn off all data tracking to enhance privacy or reduce thermal load.\n\nWARNING: This action will prevent drive recording and data cannot be recovered!", ""}, + {"MuteDoor", "Mute Door Open Alert", "Disable alerts for open doors.", ""}, + {"MuteDM", "Mute Driver Monitoring", "Disable driver monitoring.", ""}, + {"MuteOverheated", "Mute Overheated System Alert", "Disable alerts for the device being overheated.", ""}, + {"MuteSeatbelt", "Mute Seatbelt Unlatched Alert", "Disable alerts for unlatched seatbelts.", ""}, + {"OfflineMode", "Offline Mode", "Allow the device to be offline indefinitely.", ""}, + + {"LateralTune", "Lateral Tuning", "Modify openpilot's steering behavior.", "../frogpilot/assets/toggle_icons/icon_lateral_tune.png"}, + {"AverageCurvature", "Average Desired Curvature", "Use Pfeiferj's distance-based curvature adjustment for improved curve handling.", ""}, + {"NNFF", "NNFF - Neural Network Feedforward", "Use Twilsonco's Neural Network Feedforward for enhanced precision in lateral control.", ""}, + {"SteerRatio", steerRatioStock != 0 ? QString("Steer Ratio (Default: %1)").arg(steerRatioStock, 0, 'f', 2) : "Steer Ratio", "Set a custom steer ratio for your vehicle controls.", ""}, + + {"LongitudinalTune", "Longitudinal Tuning", "Modify openpilot's acceleration and braking behavior.", "../frogpilot/assets/toggle_icons/icon_longitudinal_tune.png"}, + {"AccelerationProfile", "Acceleration Profile", "Change the acceleration rate to be either sporty or eco-friendly.", ""}, + {"AggressiveAcceleration", "Aggressive Acceleration With Lead", "Increase acceleration aggressiveness when following a lead vehicle from a stop.", ""}, + {"StoppingDistance", "Increased Stopping Distance", "Increase the stopping distance for a more comfortable stop.", ""}, + {"SmoothBraking", "Smoother Braking Behind Lead", "Smoothen out the braking behavior when approaching slower vehicles.", ""}, + + {"Model", "Model Selector", "Choose your preferred openpilot model.", "../assets/offroad/icon_calibration.png"}, + + {"MTSCEnabled", "Map Turn Speed Control", "Slow down for anticipated curves detected by your downloaded maps.", "../frogpilot/assets/toggle_icons/icon_speed_map.png"}, + + {"NudgelessLaneChange", "Nudgeless Lane Change", "Enable lane changes without manual steering input.", "../frogpilot/assets/toggle_icons/icon_lane.png"}, + {"LaneChangeTime", "Lane Change Timer", "Specify a delay before executing a nudgeless lane change.", ""}, + {"LaneDetection", "Lane Detection", "Block nudgeless lane changes when a lane isn't detected.", ""}, + {"OneLaneChange", "One Lane Change Per Signal", "Limit to one nudgeless lane change per turn signal activation.", ""}, + + {"QOLControls", "Quality of Life", "Miscellaneous quality of life changes to improve your overall openpilot experience.", "../frogpilot/assets/toggle_icons/quality_of_life.png"}, + {"DisableOnroadUploads", "Disable Onroad Uploads", "Prevent large data uploads when onroad.", ""}, + {"HigherBitrate", "Higher Bitrate Recording", "Increases the quality of the footage uploaded to comma connect.", ""}, + {"PauseLateralOnSignal", "Pause Lateral On Turn Signal Below", "Temporarily disable lateral control during turn signal use below the set speed.", ""}, + {"ReverseCruise", "Reverse Cruise Increase", "Reverses the 'long press' functionality when increasing the max set speed. Useful to increase the max speed quickly.", ""}, + {"SetSpeedOffset", "Set Speed Offset", "Set an offset for your desired set speed.", ""}, + + {"SpeedLimitController", "Speed Limit Controller", "Automatically adjust vehicle speed to match speed limits using 'Open Street Map's, 'Navigate On openpilot', or your car's dashboard (TSS2 Toyotas only).", "../assets/offroad/icon_speed_limit.png"}, + {"Offset1", "Speed Limit Offset (0-34 mph)", "Speed limit offset for speed limits between 0-34 mph.", ""}, + {"Offset2", "Speed Limit Offset (35-54 mph)", "Speed limit offset for speed limits between 35-54 mph.", ""}, + {"Offset3", "Speed Limit Offset (55-64 mph)", "Speed limit offset for speed limits between 55-64 mph.", ""}, + {"Offset4", "Speed Limit Offset (65-99 mph)", "Speed limit offset for speed limits between 65-99 mph.", ""}, + {"SLCFallback", "Fallback Method", "Choose your fallback method for when there are no speed limits currently being obtained from Navigation, OSM, and the car's dashboard.", ""}, + {"SLCOverride", "Override Method", "Choose your preferred method to override the current speed limit.", ""}, + {"SLCPriority", "Priority Order", "Determine the priority order for what speed limits to use.", ""}, + + {"TurnDesires", "Use Turn Desires", "Use turn desires for enhanced precision in turns below the minimum lane change speed.", "../assets/navigation/direction_continue_right.png"}, + + {"VisionTurnControl", "Vision Turn Speed Controller", "Slow down for detected road curvature for smoother curve handling.", "../frogpilot/assets/toggle_icons/icon_vtc.png"}, + {"CurveSensitivity", "Curve Detection Sensitivity", "Set curve detection sensitivity. Higher values prompt earlier responses, lower values lead to smoother but later reactions.", ""}, + {"TurnAggressiveness", "Turn Speed Aggressiveness", "Set turn speed aggressiveness. Higher values result in faster turns, lower values yield gentler turns.", ""}, + }; + + for (const auto &[param, title, desc, icon] : controlToggles) { + ParamControl *toggle; + + if (param == "AdjustablePersonalities") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 3, {{0, "None"}, {1, "Steering Wheel"}, {2, "Onroad UI Button"}, {3, "Wheel + Button"}}, this, true); + + } else if (param == "AlwaysOnLateral") { + std::vector aolToggles{"AlwaysOnLateralMain"}; + std::vector aolToggleNames{tr("Enable On Cruise Main")}; + toggle = new FrogPilotParamToggleControl(param, title, desc, icon, aolToggles, aolToggleNames); + + QObject::connect(static_cast(toggle), &FrogPilotParamToggleControl::buttonClicked, [this](const bool checked) { + if (checked) { + FrogPilotConfirmationDialog::toggleAlert("WARNING: This is very experimental and isn't guaranteed to work. If you run into any issues, please report it in the FrogPilot Discord!", + "I understand the risks.", this); + } + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + }); + + } else if (param == "ConditionalExperimental") { + FrogPilotParamManageControl *conditionalExperimentalToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(conditionalExperimentalToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + conditionalSpeedsImperial->setVisible(!isMetric); + conditionalSpeedsMetric->setVisible(isMetric); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(conditionalExperimentalKeys.find(key.c_str()) != conditionalExperimentalKeys.end()); + } + }); + toggle = conditionalExperimentalToggle; + } else if (param == "CECurves") { + FrogPilotParamValueControl *CESpeedImperial = new FrogPilotParamValueControl("CESpeed", "Below", "Switch to 'Experimental Mode' below this speed in absence of a lead vehicle.", "", 0, 99, + std::map(), this, false, " mph"); + FrogPilotParamValueControl *CESpeedLeadImperial = new FrogPilotParamValueControl("CESpeedLead", " w/Lead", "Switch to 'Experimental Mode' below this speed when following a lead vehicle.", "", 0, 99, + std::map(), this, false, " mph"); + conditionalSpeedsImperial = new FrogPilotDualParamControl(CESpeedImperial, CESpeedLeadImperial, this); + addItem(conditionalSpeedsImperial); + + FrogPilotParamValueControl *CESpeedMetric = new FrogPilotParamValueControl("CESpeed", "Below", "Switch to 'Experimental Mode' below this speed in absence of a lead vehicle.", "", 0, 150, + std::map(), this, false, " kph"); + FrogPilotParamValueControl *CESpeedLeadMetric = new FrogPilotParamValueControl("CESpeedLead", " w/Lead", "Switch to 'Experimental Mode' below this speed when following a lead vehicle.", "", 0, 150, + std::map(), this, false, " kph"); + conditionalSpeedsMetric = new FrogPilotDualParamControl(CESpeedMetric, CESpeedLeadMetric, this); + addItem(conditionalSpeedsMetric); + + std::vector curveToggles{"CECurvesLead"}; + std::vector curveToggleNames{tr("With Lead")}; + toggle = new FrogPilotParamToggleControl(param, title, desc, icon, curveToggles, curveToggleNames); + } else if (param == "CEStopLights") { + std::vector stopLightToggles{"CEStopLightsLead"}; + std::vector stopLightToggleNames{tr("With Lead")}; + toggle = new FrogPilotParamToggleControl(param, title, desc, icon, stopLightToggles, stopLightToggleNames); + + } else if (param == "CustomPersonalities") { + FrogPilotParamManageControl *customPersonalitiesToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(customPersonalitiesToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(false); + } + aggressiveProfile->setVisible(true); + standardProfile->setVisible(true); + relaxedProfile->setVisible(true); + }); + toggle = customPersonalitiesToggle; + + FrogPilotParamValueControl *aggressiveFollow = new FrogPilotParamValueControl("AggressiveFollow", "Follow", + "Set the 'Aggressive' personality' following distance. Represents seconds to follow behind the lead vehicle.\n\nStock: 1.25 seconds.", "../frogpilot/assets/other_images/aggressive.png", + 10, 50, std::map(), this, false, " sec", 10); + FrogPilotParamValueControl *aggressiveJerk = new FrogPilotParamValueControl("AggressiveJerk", " Jerk", + "Configure brake/gas pedal responsiveness for the 'Aggressive' personality. Higher values yield a more 'relaxed' response.\n\nStock: 0.5.", "", 1, 50, + std::map(), this, false, "", 10); + aggressiveProfile = new FrogPilotDualParamControl(aggressiveFollow, aggressiveJerk, this, true); + addItem(aggressiveProfile); + + FrogPilotParamValueControl *standardFollow = new FrogPilotParamValueControl("StandardFollow", "Follow", + "Set the 'Standard' personality following distance. Represents seconds to follow behind the lead vehicle.\n\nStock: 1.45 seconds.", "../frogpilot/assets/other_images/standard.png", + 10, 50, std::map(), this, false, " sec", 10); + FrogPilotParamValueControl *standardJerk = new FrogPilotParamValueControl("StandardJerk", " Jerk", + "Adjust brake/gas pedal responsiveness for the 'Standard' personality. Higher values yield a more 'relaxed' response.\n\nStock: 1.0.", "", 1, 50, + std::map(), this, false, "", 10); + standardProfile = new FrogPilotDualParamControl(standardFollow, standardJerk, this, true); + addItem(standardProfile); + + FrogPilotParamValueControl *relaxedFollow = new FrogPilotParamValueControl("RelaxedFollow", "Follow", + "Set the 'Relaxed' personality following distance. Represents seconds to follow behind the lead vehicle.\n\nStock: 1.75 seconds.", "../frogpilot/assets/other_images/relaxed.png", + 10, 50, std::map(), this, false, " sec", 10); + FrogPilotParamValueControl *relaxedJerk = new FrogPilotParamValueControl("RelaxedJerk", " Jerk", + "Set brake/gas pedal responsiveness for the 'Relaxed' personality. Higher values yield a more 'relaxed' response.\n\nStock: 1.0.", "", 1, 50, + std::map(), this, false, "", 10); + relaxedProfile = new FrogPilotDualParamControl(relaxedFollow, relaxedJerk, this, true); + addItem(relaxedProfile); + + } else if (param == "DeviceShutdown") { + std::map shutdownLabels; + for (int i = 0; i <= 33; ++i) { + shutdownLabels[i] = i == 0 ? "Instant" : i <= 3 ? QString::number(i * 15) + " mins" : QString::number(i - 3) + (i == 4 ? " hour" : " hours"); + } + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 33, shutdownLabels, this, false); + + } else if (param == "ExperimentalModeActivation") { + std::vector experimentalModeToggles{"ExperimentalModeViaLKAS", "ExperimentalModeViaScreen"}; + std::vector experimentalModeNames{tr("LKAS Button"), tr("Screen")}; + toggle = new FrogPilotParamToggleControl(param, title, desc, icon, experimentalModeToggles, experimentalModeNames); + + } else if (param == "FireTheBabysitter") { + FrogPilotParamManageControl *fireTheBabysitterToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(fireTheBabysitterToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(fireTheBabysitterKeys.find(key.c_str()) != fireTheBabysitterKeys.end()); + } + }); + toggle = fireTheBabysitterToggle; + + } else if (param == "LateralTune") { + FrogPilotParamManageControl *lateralTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(lateralTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(lateralTuneKeys.find(key.c_str()) != lateralTuneKeys.end()); + } + }); + toggle = lateralTuneToggle; + } else if (param == "SteerRatio") { + toggle = new FrogPilotParamValueControlFloat(param, title, desc, icon, steerRatioStock * 0.75, steerRatioStock * 1.25, std::map(), this, false, "", 10.0); + + } else if (param == "LongitudinalTune") { + FrogPilotParamManageControl *longitudinalTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(longitudinalTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(longitudinalTuneKeys.find(key.c_str()) != longitudinalTuneKeys.end()); + } + }); + toggle = longitudinalTuneToggle; + } else if (param == "AccelerationProfile") { + std::vector profileOptions{tr("Standard"), tr("Eco"), tr("Sport"), tr("Sport+")}; + FrogPilotButtonParamControl *profileSelection = new FrogPilotButtonParamControl(param, title, desc, icon, profileOptions); + toggle = profileSelection; + + QObject::connect(static_cast(toggle), &FrogPilotButtonParamControl::buttonClicked, [this](int id) { + if (id == 3) { + FrogPilotConfirmationDialog::toggleAlert("WARNING: This maxes out openpilot's acceleration from 2.0 m/s to 4.0 m/s and may cause oscillations when accelerating!", + "I understand the risks.", this); + } + }); + } else if (param == "StoppingDistance") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, std::map(), this, false, " feet"); + + } else if (param == "Model") { + modelSelectorButton = new FrogPilotButtonIconControl(title, tr("SELECT"), desc, icon); + QStringList models = {"New Delhi (Default)", "Blue Diamond V1", "Blue Diamond V2", "Farmville", "New Lemon Pie"}; + QObject::connect(modelSelectorButton, &FrogPilotButtonIconControl::clicked, this, [this, models]() { + int currentModel = params.getInt("Model"); + QString currentModelLabel = models[currentModel]; + + QString selection = MultiOptionDialog::getSelection(tr("Select a driving model"), models, currentModelLabel, this); + if (!selection.isEmpty()) { + int selectedModel = models.indexOf(selection); + params.putInt("Model", selectedModel); + params.remove("CalibrationParams"); + params.remove("LiveTorqueParameters"); + modelSelectorButton->setValue(selection); + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + } + }); + modelSelectorButton->setValue(models[params.getInt("Model")]); + addItem(modelSelectorButton); + + } else if (param == "NudgelessLaneChange") { + FrogPilotParamManageControl *laneChangeToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(laneChangeToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(laneChangeKeys.find(key.c_str()) != laneChangeKeys.end()); + } + }); + toggle = laneChangeToggle; + } else if (param == "LaneChangeTime") { + std::map laneChangeTimeLabels; + for (int i = 0; i <= 10; ++i) { + laneChangeTimeLabels[i] = i == 0 ? "Instant" : QString::number(i / 2.0) + " seconds"; + } + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, laneChangeTimeLabels, this, false); + + } else if (param == "QOLControls") { + FrogPilotParamManageControl *qolToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(qolToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(qolKeys.find(key.c_str()) != qolKeys.end()); + } + }); + toggle = qolToggle; + } else if (param == "PauseLateralOnSignal") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, std::map(), this, false, " mph"); + } else if (param == "SetSpeedOffset") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, std::map(), this, false, " mph"); + + } else if (param == "SpeedLimitController") { + FrogPilotParamManageControl *speedLimitControllerToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(speedLimitControllerToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(speedLimitControllerKeys.find(key.c_str()) != speedLimitControllerKeys.end()); + } + slscPriorityButton->setVisible(true); + }); + toggle = speedLimitControllerToggle; + } else if (param == "Offset1" || param == "Offset2" || param == "Offset3" || param == "Offset4") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, std::map(), this, false, " mph"); + } else if (param == "SLCFallback") { + std::vector fallbackOptions{tr("None"), tr("Experimental Mode"), tr("Previous Limit")}; + FrogPilotButtonParamControl *fallbackSelection = new FrogPilotButtonParamControl(param, title, desc, icon, fallbackOptions); + toggle = fallbackSelection; + } else if (param == "SLCOverride") { + std::vector overrideOptions{tr("None"), tr("Manual Set Speed"), tr("Max Set Speed")}; + FrogPilotButtonParamControl *overrideSelection = new FrogPilotButtonParamControl(param, title, desc, icon, overrideOptions); + toggle = overrideSelection; + } else if (param == "SLCPriority") { + const QStringList priorities { + "Navigation, Dashboard, Offline Maps", + "Navigation, Offline Maps, Dashboard", + "Navigation, Offline Maps", + "Navigation, Dashboard", + "Navigation", + "Offline Maps, Dashboard, Navigation", + "Offline Maps, Navigation, Dashboard", + "Offline Maps, Navigation", + "Offline Maps, Dashboard", + "Offline Maps", + "Dashboard, Navigation, Offline Maps", + "Dashboard, Offline Maps, Navigation", + "Dashboard, Offline Maps", + "Dashboard, Navigation", + "Dashboard", + "Highest", + "Lowest", + "", + }; + + slscPriorityButton = new ButtonControl(title, tr("SELECT"), desc); + QObject::connect(slscPriorityButton, &ButtonControl::clicked, this, [this, priorities]() { + QStringList availablePriorities = {"Dashboard", "Navigation", "Offline Maps", "Highest", "Lowest", "None"}; + QStringList selectedPriorities; + int priorityValue = -1; + + QStringList priorityPrompts = {tr("Select your primary priority"), tr("Select your secondary priority"), tr("Select your tertiary priority")}; + + for (int i = 0; i < 3; ++i) { + QString selection = MultiOptionDialog::getSelection(priorityPrompts[i], availablePriorities, "", this); + if (selection.isEmpty()) break; + + if (selection == "None") { + priorityValue = 17; + break; + } else if (selection == "Highest") { + priorityValue = 15; + break; + } else if (selection == "Lowest") { + priorityValue = 16; + break; + } else { + selectedPriorities.append(selection); + availablePriorities.removeAll(selection); + availablePriorities.removeAll("Highest"); + availablePriorities.removeAll("Lowest"); + } + } + + if (priorityValue == -1 && !selectedPriorities.isEmpty()) { + QString priorityString = selectedPriorities.join(", "); + priorityValue = priorities.indexOf(priorityString); + } + + if (priorityValue != -1) { + slscPriorityButton->setValue(priorities[priorityValue]); + params.putInt("SLCPriority", priorityValue); + updateToggles(); + } + }); + slscPriorityButton->setValue(priorities[params.getInt("SLCPriority")]); + addItem(slscPriorityButton); + + } else if (param == "VisionTurnControl") { + FrogPilotParamManageControl *visionTurnControlToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(visionTurnControlToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(visionTurnControlKeys.find(key.c_str()) != visionTurnControlKeys.end()); + } + }); + toggle = visionTurnControlToggle; + } else if (param == "CurveSensitivity" || param == "TurnAggressiveness") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 200, std::map(), this, false, "%"); + + } else { + toggle = new ParamControl(param, title, desc, icon, this); + } + + addItem(toggle); + toggles[param.toStdString()] = toggle; + + QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() { + updateToggles(); + }); + + QObject::connect(static_cast(toggle), &FrogPilotParamValueControl::buttonPressed, [this]() { + updateToggles(); + }); + + QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() { + update(); + }); + + QObject::connect(static_cast(toggle), &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + update(); + }); + } + + std::set rebootKeys = {"AlwaysOnLateral", "FireTheBabysitter", "HigherBitrate", "MuteDM", "NNFF"}; + for (const std::string &key : rebootKeys) { + QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() { + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + }); + } + + conditionalExperimentalKeys = {"CECurves", "CECurvesLead", "CESlowerLead", "CENavigation", "CEStopLights", "CESignal"}; + fireTheBabysitterKeys = {"NoLogging", "MuteDM", "MuteDoor", "MuteOverheated", "MuteSeatbelt", "OfflineMode"}; + laneChangeKeys = {"LaneChangeTime", "LaneDetection", "OneLaneChange"}; + lateralTuneKeys = {"AverageCurvature", "NNFF", "SteerRatio"}; + longitudinalTuneKeys = {"AccelerationProfile", "AggressiveAcceleration", "SmoothBraking", "StoppingDistance"}; + mtscKeys = {"MTSCAggressiveness"}; + qolKeys = {"DisableOnroadUploads", "HigherBitrate", "PauseLateralOnSignal", "ReverseCruise", "SetSpeedOffset"}; + speedLimitControllerKeys = {"Offset1", "Offset2", "Offset3", "Offset4", "SLCFallback", "SLCOverride", "SLCPriority"}; + visionTurnControlKeys = {"CurveSensitivity", "TurnAggressiveness"}; + + QObject::connect(uiState(), &UIState::offroadTransition, this, [this](bool offroad) { + if (!offroad) { + updateCarToggles(); + } + }); + + QObject::connect(device(), &Device::interactiveTimeout, this, &FrogPilotControlsPanel::hideSubToggles); + QObject::connect(parent, &OscarSettingsWindow::closeParentToggle, this, &FrogPilotControlsPanel::hideSubToggles); + // QObject::connect(parent, &OscarSettingsWindow::updateMetric, this, &FrogPilotControlsPanel::updateMetric); + + hideSubToggles(); + // updateMetric(); +} + +void FrogPilotControlsPanel::updateCarToggles() { + FrogPilotParamValueControlFloat *steerRatioToggle = static_cast(toggles["SteerRatio"]); + steerRatioStock = params.getFloat("SteerRatioStock"); + steerRatioToggle->setTitle(steerRatioStock != 0 ? QString("Steer Ratio (Default: %1)").arg(steerRatioStock, 0, 'f', 2) : QString("Steer Ratio")); + steerRatioToggle->updateControl(steerRatioStock * 0.75, steerRatioStock * 1.25, "", 10.0); + steerRatioToggle->refresh(); +} + +void FrogPilotControlsPanel::updateToggles() { + std::thread([this]() { + paramsMemory.putBool("FrogPilotTogglesUpdated", true); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + paramsMemory.putBool("FrogPilotTogglesUpdated", false); + }).detach(); +} + +void FrogPilotControlsPanel::updateMetric() { + bool previousIsMetric = isMetric; + isMetric = params.getBool("IsMetric"); + + if (isMetric != previousIsMetric) { + double distanceConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT; + double speedConversion = isMetric ? MILE_TO_KM : KM_TO_MILE; + params.putInt("CESpeed", std::nearbyint(params.getInt("CESpeed") * speedConversion)); + params.putInt("CESpeedLead", std::nearbyint(params.getInt("CESpeedLead") * speedConversion)); + params.putInt("Offset1", std::nearbyint(params.getInt("Offset1") * speedConversion)); + params.putInt("Offset2", std::nearbyint(params.getInt("Offset2") * speedConversion)); + params.putInt("Offset3", std::nearbyint(params.getInt("Offset3") * speedConversion)); + params.putInt("Offset4", std::nearbyint(params.getInt("Offset4") * speedConversion)); + params.putInt("PauseLateralOnSignal", std::nearbyint(params.getInt("PauseLateralOnSignal") * speedConversion)); + params.putInt("SetSpeedOffset", std::nearbyint(params.getInt("SetSpeedOffset") * speedConversion)); + params.putInt("StoppingDistance", std::nearbyint(params.getInt("StoppingDistance") * distanceConversion)); + } + + FrogPilotParamValueControl *offset1Toggle = static_cast(toggles["Offset1"]); + FrogPilotParamValueControl *offset2Toggle = static_cast(toggles["Offset2"]); + FrogPilotParamValueControl *offset3Toggle = static_cast(toggles["Offset3"]); + FrogPilotParamValueControl *offset4Toggle = static_cast(toggles["Offset4"]); + FrogPilotParamValueControl *pauseLateralToggle = static_cast(toggles["PauseLateralOnSignal"]); + FrogPilotParamValueControl *setSpeedOffsetToggle = static_cast(toggles["SetSpeedOffset"]); + FrogPilotParamValueControl *stoppingDistanceToggle = static_cast(toggles["StoppingDistance"]); + + if (isMetric) { + offset1Toggle->setTitle("Speed Limit Offset (0-34 kph)"); + offset2Toggle->setTitle("Speed Limit Offset (35-54 kph)"); + offset3Toggle->setTitle("Speed Limit Offset (55-64 kph)"); + offset4Toggle->setTitle("Speed Limit Offset (65-99 kph)"); + + offset1Toggle->setDescription("Set speed limit offset for limits between 0-34 kph."); + offset2Toggle->setDescription("Set speed limit offset for limits between 35-54 kph."); + offset3Toggle->setDescription("Set speed limit offset for limits between 55-64 kph."); + offset4Toggle->setDescription("Set speed limit offset for limits between 65-99 kph."); + + offset1Toggle->updateControl(0, 150, " kph"); + offset2Toggle->updateControl(0, 150, " kph"); + offset3Toggle->updateControl(0, 150, " kph"); + offset4Toggle->updateControl(0, 150, " kph"); + pauseLateralToggle->updateControl(0, 150, " kph"); + setSpeedOffsetToggle->updateControl(0, 150, " kph"); + stoppingDistanceToggle->updateControl(0, 5, " meters"); + } else { + offset1Toggle->setTitle("Speed Limit Offset (0-34 mph)"); + offset2Toggle->setTitle("Speed Limit Offset (35-54 mph)"); + offset3Toggle->setTitle("Speed Limit Offset (55-64 mph)"); + offset4Toggle->setTitle("Speed Limit Offset (65-99 mph)"); + + offset1Toggle->setDescription("Set speed limit offset for limits between 0-34 mph."); + offset2Toggle->setDescription("Set speed limit offset for limits between 35-54 mph."); + offset3Toggle->setDescription("Set speed limit offset for limits between 55-64 mph."); + offset4Toggle->setDescription("Set speed limit offset for limits between 65-99 mph."); + + offset1Toggle->updateControl(0, 99, " mph"); + offset2Toggle->updateControl(0, 99, " mph"); + offset3Toggle->updateControl(0, 99, " mph"); + offset4Toggle->updateControl(0, 99, " mph"); + pauseLateralToggle->updateControl(0, 99, " mph"); + setSpeedOffsetToggle->updateControl(0, 99, " mph"); + stoppingDistanceToggle->updateControl(0, 10, " feet"); + } + + offset1Toggle->refresh(); + offset2Toggle->refresh(); + offset3Toggle->refresh(); + offset4Toggle->refresh(); + pauseLateralToggle->refresh(); + setSpeedOffsetToggle->refresh(); + stoppingDistanceToggle->refresh(); + + previousIsMetric = isMetric; +} + +void FrogPilotControlsPanel::parentToggleClicked() { + aggressiveProfile->setVisible(false); + conditionalSpeedsImperial->setVisible(false); + conditionalSpeedsMetric->setVisible(false); + modelSelectorButton->setVisible(false); + slscPriorityButton->setVisible(false); + standardProfile->setVisible(false); + relaxedProfile->setVisible(false); + + this->openParentToggle(); +} + +void FrogPilotControlsPanel::hideSubToggles() { + aggressiveProfile->setVisible(false); + conditionalSpeedsImperial->setVisible(false); + conditionalSpeedsMetric->setVisible(false); + modelSelectorButton->setVisible(true); + slscPriorityButton->setVisible(false); + standardProfile->setVisible(false); + relaxedProfile->setVisible(false); + + for (auto &[key, toggle] : toggles) { + bool subToggles = conditionalExperimentalKeys.find(key.c_str()) != conditionalExperimentalKeys.end() || + fireTheBabysitterKeys.find(key.c_str()) != fireTheBabysitterKeys.end() || + laneChangeKeys.find(key.c_str()) != laneChangeKeys.end() || + lateralTuneKeys.find(key.c_str()) != lateralTuneKeys.end() || + longitudinalTuneKeys.find(key.c_str()) != longitudinalTuneKeys.end() || + mtscKeys.find(key.c_str()) != mtscKeys.end() || + qolKeys.find(key.c_str()) != qolKeys.end() || + speedLimitControllerKeys.find(key.c_str()) != speedLimitControllerKeys.end() || + visionTurnControlKeys.find(key.c_str()) != visionTurnControlKeys.end(); + toggle->setVisible(!subToggles); + } + + this->closeParentToggle(); +} + +void FrogPilotControlsPanel::hideEvent(QHideEvent *event) { + hideSubToggles(); +} diff --git a/selfdrive/clearpilot/ui/control_settings.cc.org b/selfdrive/clearpilot/ui/control_settings.cc.org new file mode 100644 index 0000000..da081a6 --- /dev/null +++ b/selfdrive/clearpilot/ui/control_settings.cc.org @@ -0,0 +1,559 @@ +#include "selfdrive/frogpilot/ui/control_settings.h" +#include "selfdrive/ui/ui.h" + +FrogPilotControlsPanel::FrogPilotControlsPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) { + const std::vector> controlToggles { + {"AdjustablePersonalities", "Adjustable Personalities", "Use the 'Distance' button on the steering wheel or the onroad UI to switch between openpilot's driving personalities.\n\n1 bar = Aggressive\n2 bars = Standard\n3 bars = Relaxed", "../frogpilot/assets/toggle_icons/icon_distance.png"}, + {"AlwaysOnLateral", "Always on Lateral", "Maintain openpilot lateral control when the brake or gas pedals are used.\n\nDeactivation occurs only through the 'Cruise Control' button.", "../frogpilot/assets/toggle_icons/icon_always_on_lateral.png"}, + + {"ConditionalExperimental", "Conditional Experimental Mode", "Automatically switches to 'Experimental Mode' under predefined conditions.", "../frogpilot/assets/toggle_icons/icon_conditional.png"}, + {"CECurves", "Curve Detected Ahead", "Switch to 'Experimental Mode' when a curve is detected.", ""}, + {"CENavigation", "Navigation Based", "Switch to 'Experimental Mode' based on navigation data. (i.e. Intersections, stop signs, etc.)", ""}, + {"CESlowerLead", "Slower Lead Detected Ahead", "Switch to 'Experimental Mode' when a slower lead vehicle is detected ahead.", ""}, + // {"CEStopLights", "Stop Lights and Stop Signs", "Switch to 'Experimental Mode' when a stop light or stop sign is detected.", ""}, + {"CESignal", "Turn Signal When Below Highway Speeds", "Switch to 'Experimental Mode' when using turn signals below highway speeds to help assit with turns.", ""}, + {"CSLCEnabled", "Custom Stock Longitudinal Control", "Use cruise control button spamming to adjust cruise set speed based on MTSC, VTSC, and SLC", "../frogpilot/assets/toggle_icons/icon_custom.png"}, + {"CustomPersonalities", "Custom Driving Personalities", "Customize the driving personality profiles to your driving style.", "../frogpilot/assets/toggle_icons/icon_custom.png"}, + {"DeviceShutdown", "Device Shutdown Timer", "Configure the timer for automatic device shutdown when offroad conserving energy and preventing battery drain.", "../frogpilot/assets/toggle_icons/icon_time.png"}, + {"ExperimentalModeActivation", "Experimental Mode Via", "Toggle Experimental Mode by double-clicking the 'Lane Departure'/'LKAS' button or double tapping screen.\n\nOverrides 'Conditional Experimental Mode'.", "../assets/img_experimental_white.svg"}, + + {"FireTheBabysitter", "Fire the Babysitter", "Deactivate some of openpilot's 'Babysitter' protocols for more user autonomy.", "../frogpilot/assets/toggle_icons/icon_babysitter.png"}, + {"NoLogging", "Disable All Logging", "Turn off all data tracking to enhance privacy or reduce thermal load.\n\nWARNING: This action will prevent drive recording and data cannot be recovered!", ""}, + {"MuteDoor", "Mute Door Open Alert", "Disable alerts for open doors.", ""}, + {"MuteDM", "Mute Driver Monitoring", "Disable driver monitoring.", ""}, + {"MuteOverheated", "Mute Overheated System Alert", "Disable alerts for the device being overheated.", ""}, + {"MuteSeatbelt", "Mute Seatbelt Unlatched Alert", "Disable alerts for unlatched seatbelts.", ""}, + {"OfflineMode", "Offline Mode", "Allow the device to be offline indefinitely.", ""}, + + {"LateralTune", "Lateral Tuning", "Modify openpilot's steering behavior.", "../frogpilot/assets/toggle_icons/icon_lateral_tune.png"}, + {"AverageCurvature", "Average Desired Curvature", "Use Pfeiferj's distance-based curvature adjustment for improved curve handling.", ""}, + {"NNFF", "NNFF - Neural Network Feedforward", "Use Twilsonco's Neural Network Feedforward for enhanced precision in lateral control.", ""}, + {"SteerRatio", steerRatioStock != 0 ? QString("Steer Ratio (Default: %1)").arg(steerRatioStock, 0, 'f', 2) : "Steer Ratio", "Set a custom steer ratio for your vehicle controls.", ""}, + + {"LongitudinalTune", "Longitudinal Tuning", "Modify openpilot's acceleration and braking behavior.", "../frogpilot/assets/toggle_icons/icon_longitudinal_tune.png"}, + {"AccelerationProfile", "Acceleration Profile", "Change the acceleration rate to be either sporty or eco-friendly.", ""}, + {"AggressiveAcceleration", "Aggressive Acceleration With Lead", "Increase acceleration aggressiveness when following a lead vehicle from a stop.", ""}, + {"StoppingDistance", "Increased Stopping Distance", "Increase the stopping distance for a more comfortable stop.", ""}, + {"SmoothBraking", "Smoother Braking Behind Lead", "Smoothen out the braking behavior when approaching slower vehicles.", ""}, + + {"Model", "Model Selector", "Choose your preferred openpilot model.", "../assets/offroad/icon_calibration.png"}, + + {"MTSCEnabled", "Map Turn Speed Control", "Slow down for anticipated curves detected by your downloaded maps.", "../frogpilot/assets/toggle_icons/icon_speed_map.png"}, + + {"NudgelessLaneChange", "Nudgeless Lane Change", "Enable lane changes without manual steering input.", "../frogpilot/assets/toggle_icons/icon_lane.png"}, + {"LaneChangeTime", "Lane Change Timer", "Specify a delay before executing a nudgeless lane change.", ""}, + {"LaneDetection", "Lane Detection", "Block nudgeless lane changes when a lane isn't detected.", ""}, + {"OneLaneChange", "One Lane Change Per Signal", "Limit to one nudgeless lane change per turn signal activation.", ""}, + + {"QOLControls", "Quality of Life", "Miscellaneous quality of life changes to improve your overall openpilot experience.", "../frogpilot/assets/toggle_icons/quality_of_life.png"}, + {"DisableOnroadUploads", "Disable Onroad Uploads", "Prevent large data uploads when onroad.", ""}, + {"HigherBitrate", "Higher Bitrate Recording", "Increases the quality of the footage uploaded to comma connect.", ""}, + {"PauseLateralOnSignal", "Pause Lateral On Turn Signal Below", "Temporarily disable lateral control during turn signal use below the set speed.", ""}, + {"ReverseCruise", "Reverse Cruise Increase", "Reverses the 'long press' functionality when increasing the max set speed. Useful to increase the max speed quickly.", ""}, + {"SetSpeedOffset", "Set Speed Offset", "Set an offset for your desired set speed.", ""}, + + {"SpeedLimitController", "Speed Limit Controller", "Automatically adjust vehicle speed to match speed limits using 'Open Street Map's, 'Navigate On openpilot', or your car's dashboard (TSS2 Toyotas only).", "../assets/offroad/icon_speed_limit.png"}, + {"Offset1", "Speed Limit Offset (0-34 mph)", "Speed limit offset for speed limits between 0-34 mph.", ""}, + {"Offset2", "Speed Limit Offset (35-54 mph)", "Speed limit offset for speed limits between 35-54 mph.", ""}, + {"Offset3", "Speed Limit Offset (55-64 mph)", "Speed limit offset for speed limits between 55-64 mph.", ""}, + {"Offset4", "Speed Limit Offset (65-99 mph)", "Speed limit offset for speed limits between 65-99 mph.", ""}, + {"SLCFallback", "Fallback Method", "Choose your fallback method for when there are no speed limits currently being obtained from Navigation, OSM, and the car's dashboard.", ""}, + {"SLCOverride", "Override Method", "Choose your preferred method to override the current speed limit.", ""}, + {"SLCPriority", "Priority Order", "Determine the priority order for what speed limits to use.", ""}, + + {"TurnDesires", "Use Turn Desires", "Use turn desires for enhanced precision in turns below the minimum lane change speed.", "../assets/navigation/direction_continue_right.png"}, + + {"VisionTurnControl", "Vision Turn Speed Controller", "Slow down for detected road curvature for smoother curve handling.", "../frogpilot/assets/toggle_icons/icon_vtc.png"}, + {"CurveSensitivity", "Curve Detection Sensitivity", "Set curve detection sensitivity. Higher values prompt earlier responses, lower values lead to smoother but later reactions.", ""}, + {"TurnAggressiveness", "Turn Speed Aggressiveness", "Set turn speed aggressiveness. Higher values result in faster turns, lower values yield gentler turns.", ""}, + }; + + for (const auto &[param, title, desc, icon] : controlToggles) { + ParamControl *toggle; + + if (param == "AdjustablePersonalities") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 3, {{0, "None"}, {1, "Steering Wheel"}, {2, "Onroad UI Button"}, {3, "Wheel + Button"}}, this, true); + + } else if (param == "AlwaysOnLateral") { + std::vector aolToggles{"AlwaysOnLateralMain"}; + std::vector aolToggleNames{tr("Enable On Cruise Main")}; + toggle = new FrogPilotParamToggleControl(param, title, desc, icon, aolToggles, aolToggleNames); + + QObject::connect(static_cast(toggle), &FrogPilotParamToggleControl::buttonClicked, [this](const bool checked) { + if (checked) { + FrogPilotConfirmationDialog::toggleAlert("WARNING: This is very experimental and isn't guaranteed to work. If you run into any issues, please report it in the FrogPilot Discord!", + "I understand the risks.", this); + } + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + }); + + } else if (param == "ConditionalExperimental") { + FrogPilotParamManageControl *conditionalExperimentalToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(conditionalExperimentalToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + conditionalSpeedsImperial->setVisible(!isMetric); + conditionalSpeedsMetric->setVisible(isMetric); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(conditionalExperimentalKeys.find(key.c_str()) != conditionalExperimentalKeys.end()); + } + }); + toggle = conditionalExperimentalToggle; + } else if (param == "CECurves") { + FrogPilotParamValueControl *CESpeedImperial = new FrogPilotParamValueControl("CESpeed", "Below", "Switch to 'Experimental Mode' below this speed in absence of a lead vehicle.", "", 0, 99, + std::map(), this, false, " mph"); + FrogPilotParamValueControl *CESpeedLeadImperial = new FrogPilotParamValueControl("CESpeedLead", " w/Lead", "Switch to 'Experimental Mode' below this speed when following a lead vehicle.", "", 0, 99, + std::map(), this, false, " mph"); + conditionalSpeedsImperial = new FrogPilotDualParamControl(CESpeedImperial, CESpeedLeadImperial, this); + addItem(conditionalSpeedsImperial); + + FrogPilotParamValueControl *CESpeedMetric = new FrogPilotParamValueControl("CESpeed", "Below", "Switch to 'Experimental Mode' below this speed in absence of a lead vehicle.", "", 0, 150, + std::map(), this, false, " kph"); + FrogPilotParamValueControl *CESpeedLeadMetric = new FrogPilotParamValueControl("CESpeedLead", " w/Lead", "Switch to 'Experimental Mode' below this speed when following a lead vehicle.", "", 0, 150, + std::map(), this, false, " kph"); + conditionalSpeedsMetric = new FrogPilotDualParamControl(CESpeedMetric, CESpeedLeadMetric, this); + addItem(conditionalSpeedsMetric); + + std::vector curveToggles{"CECurvesLead"}; + std::vector curveToggleNames{tr("With Lead")}; + toggle = new FrogPilotParamToggleControl(param, title, desc, icon, curveToggles, curveToggleNames); + } else if (param == "CEStopLights") { + std::vector stopLightToggles{"CEStopLightsLead"}; + std::vector stopLightToggleNames{tr("With Lead")}; + toggle = new FrogPilotParamToggleControl(param, title, desc, icon, stopLightToggles, stopLightToggleNames); + + } else if (param == "CustomPersonalities") { + FrogPilotParamManageControl *customPersonalitiesToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(customPersonalitiesToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(false); + } + aggressiveProfile->setVisible(true); + standardProfile->setVisible(true); + relaxedProfile->setVisible(true); + }); + toggle = customPersonalitiesToggle; + + FrogPilotParamValueControl *aggressiveFollow = new FrogPilotParamValueControl("AggressiveFollow", "Follow", + "Set the 'Aggressive' personality' following distance. Represents seconds to follow behind the lead vehicle.\n\nStock: 1.25 seconds.", "../frogpilot/assets/other_images/aggressive.png", + 10, 50, std::map(), this, false, " sec", 10); + FrogPilotParamValueControl *aggressiveJerk = new FrogPilotParamValueControl("AggressiveJerk", " Jerk", + "Configure brake/gas pedal responsiveness for the 'Aggressive' personality. Higher values yield a more 'relaxed' response.\n\nStock: 0.5.", "", 1, 50, + std::map(), this, false, "", 10); + aggressiveProfile = new FrogPilotDualParamControl(aggressiveFollow, aggressiveJerk, this, true); + addItem(aggressiveProfile); + + FrogPilotParamValueControl *standardFollow = new FrogPilotParamValueControl("StandardFollow", "Follow", + "Set the 'Standard' personality following distance. Represents seconds to follow behind the lead vehicle.\n\nStock: 1.45 seconds.", "../frogpilot/assets/other_images/standard.png", + 10, 50, std::map(), this, false, " sec", 10); + FrogPilotParamValueControl *standardJerk = new FrogPilotParamValueControl("StandardJerk", " Jerk", + "Adjust brake/gas pedal responsiveness for the 'Standard' personality. Higher values yield a more 'relaxed' response.\n\nStock: 1.0.", "", 1, 50, + std::map(), this, false, "", 10); + standardProfile = new FrogPilotDualParamControl(standardFollow, standardJerk, this, true); + addItem(standardProfile); + + FrogPilotParamValueControl *relaxedFollow = new FrogPilotParamValueControl("RelaxedFollow", "Follow", + "Set the 'Relaxed' personality following distance. Represents seconds to follow behind the lead vehicle.\n\nStock: 1.75 seconds.", "../frogpilot/assets/other_images/relaxed.png", + 10, 50, std::map(), this, false, " sec", 10); + FrogPilotParamValueControl *relaxedJerk = new FrogPilotParamValueControl("RelaxedJerk", " Jerk", + "Set brake/gas pedal responsiveness for the 'Relaxed' personality. Higher values yield a more 'relaxed' response.\n\nStock: 1.0.", "", 1, 50, + std::map(), this, false, "", 10); + relaxedProfile = new FrogPilotDualParamControl(relaxedFollow, relaxedJerk, this, true); + addItem(relaxedProfile); + + } else if (param == "DeviceShutdown") { + std::map shutdownLabels; + for (int i = 0; i <= 33; ++i) { + shutdownLabels[i] = i == 0 ? "Instant" : i <= 3 ? QString::number(i * 15) + " mins" : QString::number(i - 3) + (i == 4 ? " hour" : " hours"); + } + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 33, shutdownLabels, this, false); + + } else if (param == "ExperimentalModeActivation") { + std::vector experimentalModeToggles{"ExperimentalModeViaLKAS", "ExperimentalModeViaScreen"}; + std::vector experimentalModeNames{tr("LKAS Button"), tr("Screen")}; + toggle = new FrogPilotParamToggleControl(param, title, desc, icon, experimentalModeToggles, experimentalModeNames); + + } else if (param == "FireTheBabysitter") { + FrogPilotParamManageControl *fireTheBabysitterToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(fireTheBabysitterToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(fireTheBabysitterKeys.find(key.c_str()) != fireTheBabysitterKeys.end()); + } + }); + toggle = fireTheBabysitterToggle; + + } else if (param == "LateralTune") { + FrogPilotParamManageControl *lateralTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(lateralTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(lateralTuneKeys.find(key.c_str()) != lateralTuneKeys.end()); + } + }); + toggle = lateralTuneToggle; + } else if (param == "SteerRatio") { + toggle = new FrogPilotParamValueControlFloat(param, title, desc, icon, steerRatioStock * 0.75, steerRatioStock * 1.25, std::map(), this, false, "", 10.0); + + } else if (param == "LongitudinalTune") { + FrogPilotParamManageControl *longitudinalTuneToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(longitudinalTuneToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(longitudinalTuneKeys.find(key.c_str()) != longitudinalTuneKeys.end()); + } + }); + toggle = longitudinalTuneToggle; + } else if (param == "AccelerationProfile") { + std::vector profileOptions{tr("Standard"), tr("Eco"), tr("Sport"), tr("Sport+")}; + FrogPilotButtonParamControl *profileSelection = new FrogPilotButtonParamControl(param, title, desc, icon, profileOptions); + toggle = profileSelection; + + QObject::connect(static_cast(toggle), &FrogPilotButtonParamControl::buttonClicked, [this](int id) { + if (id == 3) { + FrogPilotConfirmationDialog::toggleAlert("WARNING: This maxes out openpilot's acceleration from 2.0 m/s to 4.0 m/s and may cause oscillations when accelerating!", + "I understand the risks.", this); + } + }); + } else if (param == "StoppingDistance") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, std::map(), this, false, " feet"); + + } else if (param == "Model") { + modelSelectorButton = new FrogPilotButtonIconControl(title, tr("SELECT"), desc, icon); + QStringList models = {"New Delhi (Default)", "Blue Diamond V1", "Blue Diamond V2", "Farmville", "New Lemon Pie"}; + QObject::connect(modelSelectorButton, &FrogPilotButtonIconControl::clicked, this, [this, models]() { + int currentModel = params.getInt("Model"); + QString currentModelLabel = models[currentModel]; + + QString selection = MultiOptionDialog::getSelection(tr("Select a driving model"), models, currentModelLabel, this); + if (!selection.isEmpty()) { + int selectedModel = models.indexOf(selection); + params.putInt("Model", selectedModel); + params.remove("CalibrationParams"); + params.remove("LiveTorqueParameters"); + modelSelectorButton->setValue(selection); + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + } + }); + modelSelectorButton->setValue(models[params.getInt("Model")]); + addItem(modelSelectorButton); + + } else if (param == "NudgelessLaneChange") { + FrogPilotParamManageControl *laneChangeToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(laneChangeToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(laneChangeKeys.find(key.c_str()) != laneChangeKeys.end()); + } + }); + toggle = laneChangeToggle; + } else if (param == "LaneChangeTime") { + std::map laneChangeTimeLabels; + for (int i = 0; i <= 10; ++i) { + laneChangeTimeLabels[i] = i == 0 ? "Instant" : QString::number(i / 2.0) + " seconds"; + } + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 10, laneChangeTimeLabels, this, false); + + } else if (param == "QOLControls") { + FrogPilotParamManageControl *qolToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(qolToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(qolKeys.find(key.c_str()) != qolKeys.end()); + } + }); + toggle = qolToggle; + } else if (param == "PauseLateralOnSignal") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, std::map(), this, false, " mph"); + } else if (param == "SetSpeedOffset") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, std::map(), this, false, " mph"); + + } else if (param == "SpeedLimitController") { + FrogPilotParamManageControl *speedLimitControllerToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(speedLimitControllerToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(speedLimitControllerKeys.find(key.c_str()) != speedLimitControllerKeys.end()); + } + slscPriorityButton->setVisible(true); + }); + toggle = speedLimitControllerToggle; + } else if (param == "Offset1" || param == "Offset2" || param == "Offset3" || param == "Offset4") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 99, std::map(), this, false, " mph"); + } else if (param == "SLCFallback") { + std::vector fallbackOptions{tr("None"), tr("Experimental Mode"), tr("Previous Limit")}; + FrogPilotButtonParamControl *fallbackSelection = new FrogPilotButtonParamControl(param, title, desc, icon, fallbackOptions); + toggle = fallbackSelection; + } else if (param == "SLCOverride") { + std::vector overrideOptions{tr("None"), tr("Manual Set Speed"), tr("Max Set Speed")}; + FrogPilotButtonParamControl *overrideSelection = new FrogPilotButtonParamControl(param, title, desc, icon, overrideOptions); + toggle = overrideSelection; + } else if (param == "SLCPriority") { + const QStringList priorities { + "Navigation, Dashboard, Offline Maps", + "Navigation, Offline Maps, Dashboard", + "Navigation, Offline Maps", + "Navigation, Dashboard", + "Navigation", + "Offline Maps, Dashboard, Navigation", + "Offline Maps, Navigation, Dashboard", + "Offline Maps, Navigation", + "Offline Maps, Dashboard", + "Offline Maps", + "Dashboard, Navigation, Offline Maps", + "Dashboard, Offline Maps, Navigation", + "Dashboard, Offline Maps", + "Dashboard, Navigation", + "Dashboard", + "Highest", + "Lowest", + "", + }; + + slscPriorityButton = new ButtonControl(title, tr("SELECT"), desc); + QObject::connect(slscPriorityButton, &ButtonControl::clicked, this, [this, priorities]() { + QStringList availablePriorities = {"Dashboard", "Navigation", "Offline Maps", "Highest", "Lowest", "None"}; + QStringList selectedPriorities; + int priorityValue = -1; + + QStringList priorityPrompts = {tr("Select your primary priority"), tr("Select your secondary priority"), tr("Select your tertiary priority")}; + + for (int i = 0; i < 3; ++i) { + QString selection = MultiOptionDialog::getSelection(priorityPrompts[i], availablePriorities, "", this); + if (selection.isEmpty()) break; + + if (selection == "None") { + priorityValue = 17; + break; + } else if (selection == "Highest") { + priorityValue = 15; + break; + } else if (selection == "Lowest") { + priorityValue = 16; + break; + } else { + selectedPriorities.append(selection); + availablePriorities.removeAll(selection); + availablePriorities.removeAll("Highest"); + availablePriorities.removeAll("Lowest"); + } + } + + if (priorityValue == -1 && !selectedPriorities.isEmpty()) { + QString priorityString = selectedPriorities.join(", "); + priorityValue = priorities.indexOf(priorityString); + } + + if (priorityValue != -1) { + slscPriorityButton->setValue(priorities[priorityValue]); + params.putInt("SLCPriority", priorityValue); + updateToggles(); + } + }); + slscPriorityButton->setValue(priorities[params.getInt("SLCPriority")]); + addItem(slscPriorityButton); + + } else if (param == "VisionTurnControl") { + FrogPilotParamManageControl *visionTurnControlToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(visionTurnControlToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(visionTurnControlKeys.find(key.c_str()) != visionTurnControlKeys.end()); + } + }); + toggle = visionTurnControlToggle; + } else if (param == "CurveSensitivity" || param == "TurnAggressiveness") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 1, 200, std::map(), this, false, "%"); + + } else { + toggle = new ParamControl(param, title, desc, icon, this); + } + + addItem(toggle); + toggles[param.toStdString()] = toggle; + + QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() { + updateToggles(); + }); + + QObject::connect(static_cast(toggle), &FrogPilotParamValueControl::buttonPressed, [this]() { + updateToggles(); + }); + + QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() { + update(); + }); + + QObject::connect(static_cast(toggle), &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + update(); + }); + } + + std::set rebootKeys = {"AlwaysOnLateral", "FireTheBabysitter", "HigherBitrate", "MuteDM", "NNFF"}; + for (const std::string &key : rebootKeys) { + QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() { + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + }); + } + + conditionalExperimentalKeys = {"CECurves", "CECurvesLead", "CESlowerLead", "CENavigation", "CEStopLights", "CESignal"}; + fireTheBabysitterKeys = {"NoLogging", "MuteDM", "MuteDoor", "MuteOverheated", "MuteSeatbelt", "OfflineMode"}; + laneChangeKeys = {"LaneChangeTime", "LaneDetection", "OneLaneChange"}; + lateralTuneKeys = {"AverageCurvature", "NNFF", "SteerRatio"}; + longitudinalTuneKeys = {"AccelerationProfile", "AggressiveAcceleration", "SmoothBraking", "StoppingDistance"}; + mtscKeys = {"MTSCAggressiveness"}; + qolKeys = {"DisableOnroadUploads", "HigherBitrate", "PauseLateralOnSignal", "ReverseCruise", "SetSpeedOffset"}; + speedLimitControllerKeys = {"Offset1", "Offset2", "Offset3", "Offset4", "SLCFallback", "SLCOverride", "SLCPriority"}; + visionTurnControlKeys = {"CurveSensitivity", "TurnAggressiveness"}; + + QObject::connect(uiState(), &UIState::offroadTransition, this, [this](bool offroad) { + if (!offroad) { + updateCarToggles(); + } + }); + + QObject::connect(device(), &Device::interactiveTimeout, this, &FrogPilotControlsPanel::hideSubToggles); + QObject::connect(parent, &SettingsWindow::closeParentToggle, this, &FrogPilotControlsPanel::hideSubToggles); + QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotControlsPanel::updateMetric); + + hideSubToggles(); + updateMetric(); +} + +void FrogPilotControlsPanel::updateCarToggles() { + FrogPilotParamValueControlFloat *steerRatioToggle = static_cast(toggles["SteerRatio"]); + steerRatioStock = params.getFloat("SteerRatioStock"); + steerRatioToggle->setTitle(steerRatioStock != 0 ? QString("Steer Ratio (Default: %1)").arg(steerRatioStock, 0, 'f', 2) : QString("Steer Ratio")); + steerRatioToggle->updateControl(steerRatioStock * 0.75, steerRatioStock * 1.25, "", 10.0); + steerRatioToggle->refresh(); +} + +void FrogPilotControlsPanel::updateToggles() { + std::thread([this]() { + paramsMemory.putBool("FrogPilotTogglesUpdated", true); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + paramsMemory.putBool("FrogPilotTogglesUpdated", false); + }).detach(); +} + +void FrogPilotControlsPanel::updateMetric() { + bool previousIsMetric = isMetric; + isMetric = params.getBool("IsMetric"); + + if (isMetric != previousIsMetric) { + double distanceConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT; + double speedConversion = isMetric ? MILE_TO_KM : KM_TO_MILE; + params.putInt("CESpeed", std::nearbyint(params.getInt("CESpeed") * speedConversion)); + params.putInt("CESpeedLead", std::nearbyint(params.getInt("CESpeedLead") * speedConversion)); + params.putInt("Offset1", std::nearbyint(params.getInt("Offset1") * speedConversion)); + params.putInt("Offset2", std::nearbyint(params.getInt("Offset2") * speedConversion)); + params.putInt("Offset3", std::nearbyint(params.getInt("Offset3") * speedConversion)); + params.putInt("Offset4", std::nearbyint(params.getInt("Offset4") * speedConversion)); + params.putInt("PauseLateralOnSignal", std::nearbyint(params.getInt("PauseLateralOnSignal") * speedConversion)); + params.putInt("SetSpeedOffset", std::nearbyint(params.getInt("SetSpeedOffset") * speedConversion)); + params.putInt("StoppingDistance", std::nearbyint(params.getInt("StoppingDistance") * distanceConversion)); + } + + FrogPilotParamValueControl *offset1Toggle = static_cast(toggles["Offset1"]); + FrogPilotParamValueControl *offset2Toggle = static_cast(toggles["Offset2"]); + FrogPilotParamValueControl *offset3Toggle = static_cast(toggles["Offset3"]); + FrogPilotParamValueControl *offset4Toggle = static_cast(toggles["Offset4"]); + FrogPilotParamValueControl *pauseLateralToggle = static_cast(toggles["PauseLateralOnSignal"]); + FrogPilotParamValueControl *setSpeedOffsetToggle = static_cast(toggles["SetSpeedOffset"]); + FrogPilotParamValueControl *stoppingDistanceToggle = static_cast(toggles["StoppingDistance"]); + + if (isMetric) { + offset1Toggle->setTitle("Speed Limit Offset (0-34 kph)"); + offset2Toggle->setTitle("Speed Limit Offset (35-54 kph)"); + offset3Toggle->setTitle("Speed Limit Offset (55-64 kph)"); + offset4Toggle->setTitle("Speed Limit Offset (65-99 kph)"); + + offset1Toggle->setDescription("Set speed limit offset for limits between 0-34 kph."); + offset2Toggle->setDescription("Set speed limit offset for limits between 35-54 kph."); + offset3Toggle->setDescription("Set speed limit offset for limits between 55-64 kph."); + offset4Toggle->setDescription("Set speed limit offset for limits between 65-99 kph."); + + offset1Toggle->updateControl(0, 150, " kph"); + offset2Toggle->updateControl(0, 150, " kph"); + offset3Toggle->updateControl(0, 150, " kph"); + offset4Toggle->updateControl(0, 150, " kph"); + pauseLateralToggle->updateControl(0, 150, " kph"); + setSpeedOffsetToggle->updateControl(0, 150, " kph"); + stoppingDistanceToggle->updateControl(0, 5, " meters"); + } else { + offset1Toggle->setTitle("Speed Limit Offset (0-34 mph)"); + offset2Toggle->setTitle("Speed Limit Offset (35-54 mph)"); + offset3Toggle->setTitle("Speed Limit Offset (55-64 mph)"); + offset4Toggle->setTitle("Speed Limit Offset (65-99 mph)"); + + offset1Toggle->setDescription("Set speed limit offset for limits between 0-34 mph."); + offset2Toggle->setDescription("Set speed limit offset for limits between 35-54 mph."); + offset3Toggle->setDescription("Set speed limit offset for limits between 55-64 mph."); + offset4Toggle->setDescription("Set speed limit offset for limits between 65-99 mph."); + + offset1Toggle->updateControl(0, 99, " mph"); + offset2Toggle->updateControl(0, 99, " mph"); + offset3Toggle->updateControl(0, 99, " mph"); + offset4Toggle->updateControl(0, 99, " mph"); + pauseLateralToggle->updateControl(0, 99, " mph"); + setSpeedOffsetToggle->updateControl(0, 99, " mph"); + stoppingDistanceToggle->updateControl(0, 10, " feet"); + } + + offset1Toggle->refresh(); + offset2Toggle->refresh(); + offset3Toggle->refresh(); + offset4Toggle->refresh(); + pauseLateralToggle->refresh(); + setSpeedOffsetToggle->refresh(); + stoppingDistanceToggle->refresh(); + + previousIsMetric = isMetric; +} + +void FrogPilotControlsPanel::parentToggleClicked() { + aggressiveProfile->setVisible(false); + conditionalSpeedsImperial->setVisible(false); + conditionalSpeedsMetric->setVisible(false); + modelSelectorButton->setVisible(false); + slscPriorityButton->setVisible(false); + standardProfile->setVisible(false); + relaxedProfile->setVisible(false); + + this->openParentToggle(); +} + +void FrogPilotControlsPanel::hideSubToggles() { + aggressiveProfile->setVisible(false); + conditionalSpeedsImperial->setVisible(false); + conditionalSpeedsMetric->setVisible(false); + modelSelectorButton->setVisible(true); + slscPriorityButton->setVisible(false); + standardProfile->setVisible(false); + relaxedProfile->setVisible(false); + + for (auto &[key, toggle] : toggles) { + bool subToggles = conditionalExperimentalKeys.find(key.c_str()) != conditionalExperimentalKeys.end() || + fireTheBabysitterKeys.find(key.c_str()) != fireTheBabysitterKeys.end() || + laneChangeKeys.find(key.c_str()) != laneChangeKeys.end() || + lateralTuneKeys.find(key.c_str()) != lateralTuneKeys.end() || + longitudinalTuneKeys.find(key.c_str()) != longitudinalTuneKeys.end() || + mtscKeys.find(key.c_str()) != mtscKeys.end() || + qolKeys.find(key.c_str()) != qolKeys.end() || + speedLimitControllerKeys.find(key.c_str()) != speedLimitControllerKeys.end() || + visionTurnControlKeys.find(key.c_str()) != visionTurnControlKeys.end(); + toggle->setVisible(!subToggles); + } + + this->closeParentToggle(); +} + +void FrogPilotControlsPanel::hideEvent(QHideEvent *event) { + hideSubToggles(); +} diff --git a/selfdrive/clearpilot/ui/control_settings.h b/selfdrive/clearpilot/ui/control_settings.h new file mode 100644 index 0000000..6f80379 --- /dev/null +++ b/selfdrive/clearpilot/ui/control_settings.h @@ -0,0 +1,54 @@ +#pragma once + +#include + +#include "selfdrive/oscarpilot/settings/settings.h" +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/ui/qt/offroad/settings.h" + +class FrogPilotControlsPanel : public FrogPilotListWidget { + Q_OBJECT + +public: + explicit FrogPilotControlsPanel(OscarSettingsWindow *parent); + +signals: + void closeParentToggle(); + void openParentToggle(); + +private: + void hideEvent(QHideEvent *event); + void hideSubToggles(); + void parentToggleClicked(); + void updateCarToggles(); + void updateMetric(); + void updateToggles(); + + ButtonControl *slscPriorityButton; + + FrogPilotButtonIconControl *modelSelectorButton; + + FrogPilotDualParamControl *aggressiveProfile; + FrogPilotDualParamControl *conditionalSpeedsImperial; + FrogPilotDualParamControl *conditionalSpeedsMetric; + FrogPilotDualParamControl *standardProfile; + FrogPilotDualParamControl *relaxedProfile; + + std::set conditionalExperimentalKeys; + std::set fireTheBabysitterKeys; + std::set laneChangeKeys; + std::set lateralTuneKeys; + std::set longitudinalTuneKeys; + std::set mtscKeys; + std::set qolKeys; + std::set speedLimitControllerKeys; + std::set visionTurnControlKeys; + + std::map toggles; + + Params params; + Params paramsMemory{"/dev/shm/params"}; + + bool isMetric = params.getBool("IsMetric"); + float steerRatioStock = params.getFloat("SteerRatioStock"); +}; diff --git a/selfdrive/clearpilot/ui/control_settings.h.org b/selfdrive/clearpilot/ui/control_settings.h.org new file mode 100644 index 0000000..b029249 --- /dev/null +++ b/selfdrive/clearpilot/ui/control_settings.h.org @@ -0,0 +1,53 @@ +#pragma once + +#include + +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/ui/qt/offroad/settings.h" + +class FrogPilotControlsPanel : public FrogPilotListWidget { + Q_OBJECT + +public: + explicit FrogPilotControlsPanel(SettingsWindow *parent); + +signals: + void closeParentToggle(); + void openParentToggle(); + +private: + void hideEvent(QHideEvent *event); + void hideSubToggles(); + void parentToggleClicked(); + void updateCarToggles(); + void updateMetric(); + void updateToggles(); + + ButtonControl *slscPriorityButton; + + FrogPilotButtonIconControl *modelSelectorButton; + + FrogPilotDualParamControl *aggressiveProfile; + FrogPilotDualParamControl *conditionalSpeedsImperial; + FrogPilotDualParamControl *conditionalSpeedsMetric; + FrogPilotDualParamControl *standardProfile; + FrogPilotDualParamControl *relaxedProfile; + + std::set conditionalExperimentalKeys; + std::set fireTheBabysitterKeys; + std::set laneChangeKeys; + std::set lateralTuneKeys; + std::set longitudinalTuneKeys; + std::set mtscKeys; + std::set qolKeys; + std::set speedLimitControllerKeys; + std::set visionTurnControlKeys; + + std::map toggles; + + Params params; + Params paramsMemory{"/dev/shm/params"}; + + bool isMetric = params.getBool("IsMetric"); + float steerRatioStock = params.getFloat("SteerRatioStock"); +}; diff --git a/selfdrive/clearpilot/ui/frogpilot_functions.cc b/selfdrive/clearpilot/ui/frogpilot_functions.cc new file mode 100644 index 0000000..135bd4d --- /dev/null +++ b/selfdrive/clearpilot/ui/frogpilot_functions.cc @@ -0,0 +1,177 @@ +#include + +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/ui/ui.h" + +bool FrogPilotConfirmationDialog::toggle(const QString &prompt_text, const QString &confirm_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, confirm_text, tr("Reboot Later"), false, parent); + return d.exec(); +} + +bool FrogPilotConfirmationDialog::toggleAlert(const QString &prompt_text, const QString &button_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, button_text, "", false, parent); + return d.exec(); +} + +bool FrogPilotConfirmationDialog::yesorno(const QString &prompt_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, tr("Yes"), tr("No"), false, parent); + return d.exec(); +} + +FrogPilotButtonIconControl::FrogPilotButtonIconControl(const QString &title, const QString &text, const QString &desc, const QString &icon, QWidget *parent) : AbstractControl(title, desc, icon, parent) { + btn.setText(text); + btn.setStyleSheet(R"( + QPushButton { + padding: 0; + border-radius: 50px; + font-size: 35px; + font-weight: 500; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + QPushButton:disabled { + color: #33E4E4E4; + } + )"); + btn.setFixedSize(250, 100); + QObject::connect(&btn, &QPushButton::clicked, this, &FrogPilotButtonIconControl::clicked); + hlayout->addWidget(&btn); +} + +void setDefaultParams() { + Params params = Params(); + bool FrogsGoMoo = params.get("DongleId").substr(0, 3) == "be6"; + + bool brianbot = params.get("DongleId").substr(0, 6) == "90bb71"; + + std::map defaultValues { + {"AccelerationPath", brianbot ? "1" : "0"}, + {"AccelerationProfile", brianbot ? "2" : "2"}, + {"AdjacentPath", FrogsGoMoo ? "1" : "0"}, + {"AdjustablePersonalities", "0"}, + {"AggressiveAcceleration", "1"}, + {"AggressiveFollow", FrogsGoMoo ? "10" : "12"}, + {"AggressiveJerk", FrogsGoMoo ? "6" : "5"}, + {"AlwaysOnLateral", "1"}, + {"AlwaysOnLateralMain", brianbot ? "1" : "0"}, + {"AverageCurvature", brianbot ? "1" : "0"}, + {"BlindSpotPath", "1"}, + {"CameraView", FrogsGoMoo ? "1" : "0"}, + {"CECurves", "1"}, + {"CECurvesLead", "0"}, + {"CENavigation", "1"}, + {"CESignal", "1"}, + {"CESlowerLead", "0"}, + {"CESpeed", "0"}, + {"CESpeedLead", "0"}, + {"CEStopLights", "0"}, + {"CEStopLightsLead", FrogsGoMoo ? "0" : "0"}, + {"Compass", FrogsGoMoo ? "1" : "0"}, + {"ConditionalExperimental", "1"}, + {"CurveSensitivity", FrogsGoMoo ? "125" : "100"}, + {"CustomColors", "1"}, + {"CustomIcons", "1"}, + {"CustomPersonalities", "0"}, + {"CustomSignals", "0"}, + {"CustomSounds", "1"}, + {"CustomTheme", "1"}, + {"CustomUI", "0"}, + {"DeviceShutdown", "1"}, + {"DisableOnroadUploads", "1"}, + {"DriverCamera", "0"}, + {"DriveStats", "1"}, + {"EVTable", FrogsGoMoo ? "0" : "1"}, + {"ExperimentalModeActivation", "1"}, + {"ExperimentalModeViaLKAS", "0"}, + {"ExperimentalModeViaScreen", FrogsGoMoo ? "0" : "1"}, + {"Fahrenheit", "0"}, + {"FireTheBabysitter", FrogsGoMoo ? "1" : "0"}, + {"FullMap", "0"}, + {"GasRegenCmd", "0"}, + {"GoatScream", "0"}, + {"GreenLightAlert", "0"}, + {"HideSpeed", "0"}, + {"HigherBitrate", "0"}, + {"LaneChangeTime", "0"}, + {"LaneDetection", "1"}, + {"LaneLinesWidth", "4"}, + {"LateralTune", "1"}, + {"LeadInfo", FrogsGoMoo ? "1" : "0"}, + {"LockDoors", "0"}, + {"LongitudinalTune", "1"}, + {"LongPitch", FrogsGoMoo ? "0" : "1"}, + {"LowerVolt", FrogsGoMoo ? "0" : "1"}, + {"Model", "3"}, + {"ModelUI", "1"}, + {"MTSCEnabled", "1"}, + {"MuteDM", FrogsGoMoo ? "1" : "1"}, + {"MuteDoor", FrogsGoMoo ? "1" : "1"}, + {"MuteOverheated", FrogsGoMoo ? "1" : "0"}, + {"MuteSeatbelt", FrogsGoMoo ? "1" : "0"}, + {"NNFF", FrogsGoMoo ? "1" : "1"}, + {"NoLogging", "1"}, + {"NudgelessLaneChange", "0"}, + {"NumericalTemp", FrogsGoMoo ? "1" : "0"}, + {"Offset1", "3"}, + {"Offset2", FrogsGoMoo ? "7" : "5"}, + {"Offset3", "7"}, + {"Offset4", FrogsGoMoo ? "20" : "7"}, + {"OneLaneChange", "1"}, + {"PathEdgeWidth", "20"}, + {"PathWidth", "61"}, + {"PauseLateralOnSignal", "20"}, + {"PreferredSchedule", "0"}, + {"QOLControls", "1"}, + {"QOLVisuals", "1"}, + {"RandomEvents", FrogsGoMoo ? "1" : "0"}, + {"RelaxedFollow", "30"}, + {"RelaxedJerk", "50"}, + {"ReverseCruise", "0"}, + {"RoadEdgesWidth", "2"}, + {"RoadNameUI", "1"}, + {"RotatingWheel", "1"}, + {"ScreenBrightness", "101"}, + {"SearchInput", "0"}, + {"ShowCPU", FrogsGoMoo ? "1" : "0"}, + {"ShowFPS", FrogsGoMoo ? "1" : "0"}, + {"ShowGPU", "0"}, + {"ShowMemoryUsage", FrogsGoMoo ? "1" : "0"}, + {"Sidebar", FrogsGoMoo ? "1" : "0"}, + {"SilentMode", "0"}, + {"SLCFallback", "2"}, + {"SLCOverride", FrogsGoMoo ? "2" : "1"}, + {"SLCPriority", "1"}, + {"SmoothBraking", "1"}, + {"SNGHack", FrogsGoMoo ? "0" : "1"}, + {"SpeedLimitController", "1"}, + {"StandardFollow", "15"}, + {"StandardJerk", "10"}, + {"StoppingDistance", FrogsGoMoo ? "6" : "0"}, + {"TSS2Tune", "1"}, + {"TurnAggressiveness", FrogsGoMoo ? "150" : "100"}, // Test 90? + {"TurnDesires", "0"}, + {"UnlimitedLength", "1"}, + {"UseSI", FrogsGoMoo ? "1" : "0"}, + {"UseVienna", "0"}, + {"VisionTurnControl", "1"}, + {"WheelIcon", FrogsGoMoo ? "1" : "0"} + }; + + bool rebootRequired = false; + for (const auto &[key, value] : defaultValues) { + if (params.get(key).empty()) { + params.put(key, value); + rebootRequired = true; + } + } + + if (rebootRequired) { + while (!std::filesystem::exists("/data/openpilot/prebuilt")) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + Hardware::reboot(); + } +} diff --git a/selfdrive/clearpilot/ui/frogpilot_functions.cc.org b/selfdrive/clearpilot/ui/frogpilot_functions.cc.org new file mode 100644 index 0000000..135bd4d --- /dev/null +++ b/selfdrive/clearpilot/ui/frogpilot_functions.cc.org @@ -0,0 +1,177 @@ +#include + +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/ui/ui.h" + +bool FrogPilotConfirmationDialog::toggle(const QString &prompt_text, const QString &confirm_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, confirm_text, tr("Reboot Later"), false, parent); + return d.exec(); +} + +bool FrogPilotConfirmationDialog::toggleAlert(const QString &prompt_text, const QString &button_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, button_text, "", false, parent); + return d.exec(); +} + +bool FrogPilotConfirmationDialog::yesorno(const QString &prompt_text, QWidget *parent) { + ConfirmationDialog d = ConfirmationDialog(prompt_text, tr("Yes"), tr("No"), false, parent); + return d.exec(); +} + +FrogPilotButtonIconControl::FrogPilotButtonIconControl(const QString &title, const QString &text, const QString &desc, const QString &icon, QWidget *parent) : AbstractControl(title, desc, icon, parent) { + btn.setText(text); + btn.setStyleSheet(R"( + QPushButton { + padding: 0; + border-radius: 50px; + font-size: 35px; + font-weight: 500; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + QPushButton:disabled { + color: #33E4E4E4; + } + )"); + btn.setFixedSize(250, 100); + QObject::connect(&btn, &QPushButton::clicked, this, &FrogPilotButtonIconControl::clicked); + hlayout->addWidget(&btn); +} + +void setDefaultParams() { + Params params = Params(); + bool FrogsGoMoo = params.get("DongleId").substr(0, 3) == "be6"; + + bool brianbot = params.get("DongleId").substr(0, 6) == "90bb71"; + + std::map defaultValues { + {"AccelerationPath", brianbot ? "1" : "0"}, + {"AccelerationProfile", brianbot ? "2" : "2"}, + {"AdjacentPath", FrogsGoMoo ? "1" : "0"}, + {"AdjustablePersonalities", "0"}, + {"AggressiveAcceleration", "1"}, + {"AggressiveFollow", FrogsGoMoo ? "10" : "12"}, + {"AggressiveJerk", FrogsGoMoo ? "6" : "5"}, + {"AlwaysOnLateral", "1"}, + {"AlwaysOnLateralMain", brianbot ? "1" : "0"}, + {"AverageCurvature", brianbot ? "1" : "0"}, + {"BlindSpotPath", "1"}, + {"CameraView", FrogsGoMoo ? "1" : "0"}, + {"CECurves", "1"}, + {"CECurvesLead", "0"}, + {"CENavigation", "1"}, + {"CESignal", "1"}, + {"CESlowerLead", "0"}, + {"CESpeed", "0"}, + {"CESpeedLead", "0"}, + {"CEStopLights", "0"}, + {"CEStopLightsLead", FrogsGoMoo ? "0" : "0"}, + {"Compass", FrogsGoMoo ? "1" : "0"}, + {"ConditionalExperimental", "1"}, + {"CurveSensitivity", FrogsGoMoo ? "125" : "100"}, + {"CustomColors", "1"}, + {"CustomIcons", "1"}, + {"CustomPersonalities", "0"}, + {"CustomSignals", "0"}, + {"CustomSounds", "1"}, + {"CustomTheme", "1"}, + {"CustomUI", "0"}, + {"DeviceShutdown", "1"}, + {"DisableOnroadUploads", "1"}, + {"DriverCamera", "0"}, + {"DriveStats", "1"}, + {"EVTable", FrogsGoMoo ? "0" : "1"}, + {"ExperimentalModeActivation", "1"}, + {"ExperimentalModeViaLKAS", "0"}, + {"ExperimentalModeViaScreen", FrogsGoMoo ? "0" : "1"}, + {"Fahrenheit", "0"}, + {"FireTheBabysitter", FrogsGoMoo ? "1" : "0"}, + {"FullMap", "0"}, + {"GasRegenCmd", "0"}, + {"GoatScream", "0"}, + {"GreenLightAlert", "0"}, + {"HideSpeed", "0"}, + {"HigherBitrate", "0"}, + {"LaneChangeTime", "0"}, + {"LaneDetection", "1"}, + {"LaneLinesWidth", "4"}, + {"LateralTune", "1"}, + {"LeadInfo", FrogsGoMoo ? "1" : "0"}, + {"LockDoors", "0"}, + {"LongitudinalTune", "1"}, + {"LongPitch", FrogsGoMoo ? "0" : "1"}, + {"LowerVolt", FrogsGoMoo ? "0" : "1"}, + {"Model", "3"}, + {"ModelUI", "1"}, + {"MTSCEnabled", "1"}, + {"MuteDM", FrogsGoMoo ? "1" : "1"}, + {"MuteDoor", FrogsGoMoo ? "1" : "1"}, + {"MuteOverheated", FrogsGoMoo ? "1" : "0"}, + {"MuteSeatbelt", FrogsGoMoo ? "1" : "0"}, + {"NNFF", FrogsGoMoo ? "1" : "1"}, + {"NoLogging", "1"}, + {"NudgelessLaneChange", "0"}, + {"NumericalTemp", FrogsGoMoo ? "1" : "0"}, + {"Offset1", "3"}, + {"Offset2", FrogsGoMoo ? "7" : "5"}, + {"Offset3", "7"}, + {"Offset4", FrogsGoMoo ? "20" : "7"}, + {"OneLaneChange", "1"}, + {"PathEdgeWidth", "20"}, + {"PathWidth", "61"}, + {"PauseLateralOnSignal", "20"}, + {"PreferredSchedule", "0"}, + {"QOLControls", "1"}, + {"QOLVisuals", "1"}, + {"RandomEvents", FrogsGoMoo ? "1" : "0"}, + {"RelaxedFollow", "30"}, + {"RelaxedJerk", "50"}, + {"ReverseCruise", "0"}, + {"RoadEdgesWidth", "2"}, + {"RoadNameUI", "1"}, + {"RotatingWheel", "1"}, + {"ScreenBrightness", "101"}, + {"SearchInput", "0"}, + {"ShowCPU", FrogsGoMoo ? "1" : "0"}, + {"ShowFPS", FrogsGoMoo ? "1" : "0"}, + {"ShowGPU", "0"}, + {"ShowMemoryUsage", FrogsGoMoo ? "1" : "0"}, + {"Sidebar", FrogsGoMoo ? "1" : "0"}, + {"SilentMode", "0"}, + {"SLCFallback", "2"}, + {"SLCOverride", FrogsGoMoo ? "2" : "1"}, + {"SLCPriority", "1"}, + {"SmoothBraking", "1"}, + {"SNGHack", FrogsGoMoo ? "0" : "1"}, + {"SpeedLimitController", "1"}, + {"StandardFollow", "15"}, + {"StandardJerk", "10"}, + {"StoppingDistance", FrogsGoMoo ? "6" : "0"}, + {"TSS2Tune", "1"}, + {"TurnAggressiveness", FrogsGoMoo ? "150" : "100"}, // Test 90? + {"TurnDesires", "0"}, + {"UnlimitedLength", "1"}, + {"UseSI", FrogsGoMoo ? "1" : "0"}, + {"UseVienna", "0"}, + {"VisionTurnControl", "1"}, + {"WheelIcon", FrogsGoMoo ? "1" : "0"} + }; + + bool rebootRequired = false; + for (const auto &[key, value] : defaultValues) { + if (params.get(key).empty()) { + params.put(key, value); + rebootRequired = true; + } + } + + if (rebootRequired) { + while (!std::filesystem::exists("/data/openpilot/prebuilt")) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + Hardware::reboot(); + } +} diff --git a/selfdrive/clearpilot/ui/frogpilot_functions.h b/selfdrive/clearpilot/ui/frogpilot_functions.h new file mode 100644 index 0000000..26bb046 --- /dev/null +++ b/selfdrive/clearpilot/ui/frogpilot_functions.h @@ -0,0 +1,661 @@ +#pragma once + +#include "selfdrive/ui/qt/widgets/controls.h" + +class FrogPilotConfirmationDialog : public ConfirmationDialog { + Q_OBJECT + +public: + explicit FrogPilotConfirmationDialog(const QString &prompt_text, const QString &confirm_text, + const QString &cancel_text, const bool rich, QWidget* parent); + static bool toggle(const QString &prompt_text, const QString &confirm_text, QWidget *parent); + static bool toggleAlert(const QString &prompt_text, const QString &button_text, QWidget *parent); + static bool yesorno(const QString &prompt_text, QWidget *parent); +}; + +class FrogPilotListWidget : public QWidget { + Q_OBJECT +public: + explicit FrogPilotListWidget(QWidget *parent = 0) : QWidget(parent), outer_layout(this) { + outer_layout.setMargin(0); + outer_layout.setSpacing(0); + outer_layout.addLayout(&inner_layout); + inner_layout.setMargin(0); + inner_layout.setSpacing(25); // default spacing is 25 + outer_layout.addStretch(); + } + inline void addItem(QWidget *w) { inner_layout.addWidget(w); } + inline void addItem(QLayout *layout) { inner_layout.addLayout(layout); } + inline void setSpacing(int spacing) { inner_layout.setSpacing(spacing); } + +private: + void paintEvent(QPaintEvent *) override { + QPainter p(this); + p.setPen(Qt::gray); + + int visibleWidgetCount = 0; + std::vector visibleRects; + + for (int i = 0; i < inner_layout.count(); ++i) { + QWidget *widget = inner_layout.itemAt(i)->widget(); + if (widget && widget->isVisible()) { + visibleWidgetCount++; + visibleRects.push_back(inner_layout.itemAt(i)->geometry()); + } + } + + for (int i = 0; i < visibleWidgetCount - 1; ++i) { + int bottom = visibleRects[i].bottom() + inner_layout.spacing() / 2; + p.drawLine(visibleRects[i].left() + 40, bottom, visibleRects[i].right() - 40, bottom); + } + } + QVBoxLayout outer_layout; + QVBoxLayout inner_layout; +}; + +class FrogPilotButtonIconControl : public AbstractControl { + Q_OBJECT + +public: + FrogPilotButtonIconControl(const QString &title, const QString &text, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr); + inline void setText(const QString &text) { btn.setText(text); } + inline QString text() const { return btn.text(); } + +signals: + void clicked(); + +public slots: + void setEnabled(bool enabled) { btn.setEnabled(enabled); } + +private: + QPushButton btn; +}; + +class FrogPilotButtonParamControl : public ParamControl { + Q_OBJECT +public: + FrogPilotButtonParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, + const std::vector &button_texts, const int minimum_button_width = 225) + : ParamControl(param, title, desc, icon) { + const QString style = R"( + QPushButton { + border-radius: 50px; + font-size: 40px; + font-weight: 500; + height:100px; + padding: 0 25 0 25; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + QPushButton:checked:enabled { + background-color: #0048FF; + } + QPushButton:disabled { + color: #33E4E4E4; + } + )"; + + key = param.toStdString(); + int value = atoi(params.get(key).c_str()); + + button_group = new QButtonGroup(this); + button_group->setExclusive(true); + for (size_t i = 0; i < button_texts.size(); i++) { + QPushButton *button = new QPushButton(button_texts[i], this); + button->setCheckable(true); + button->setChecked(i == value); + button->setStyleSheet(style); + button->setMinimumWidth(minimum_button_width); + hlayout->addWidget(button); + button_group->addButton(button, i); + } + + QObject::connect(button_group, QOverload::of(&QButtonGroup::buttonToggled), [=](int id, bool checked) { + if (checked) { + params.put(key, std::to_string(id)); + refresh(); + emit buttonClicked(id); + } + }); + + toggle.hide(); + } + + void setEnabled(bool enable) { + for (auto btn : button_group->buttons()) { + btn->setEnabled(enable); + } + } + +signals: + void buttonClicked(int id); + +private: + std::string key; + Params params; + QButtonGroup *button_group; +}; + +class FrogPilotParamManageControl : public ParamControl { + Q_OBJECT + +public: + FrogPilotParamManageControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr) + : ParamControl(param, title, desc, icon, parent), + key(param.toStdString()), + manageButton(new ButtonControl(tr(""), tr("MANAGE"), tr(""))) { + hlayout->insertWidget(hlayout->indexOf(&toggle) - 1, manageButton); + + connect(this, &ToggleControl::toggleFlipped, this, [this](bool state) { + refresh(); + }); + + connect(manageButton, &ButtonControl::clicked, this, &FrogPilotParamManageControl::manageButtonClicked); + } + + void refresh() { + ParamControl::refresh(); + manageButton->setVisible(params.getBool(key)); + } + + void showEvent(QShowEvent *event) override { + ParamControl::showEvent(event); + refresh(); + } + +signals: + void manageButtonClicked(); + +private: + std::string key; + Params params; + ButtonControl *manageButton; +}; + +class FrogPilotParamToggleControl : public ParamControl { + Q_OBJECT +public: + FrogPilotParamToggleControl(const QString ¶m, const QString &title, const QString &desc, + const QString &icon, const std::vector &button_params, + const std::vector &button_texts, QWidget *parent = nullptr, + const int minimum_button_width = 225) + : ParamControl(param, title, desc, icon, parent) { + + connect(this, &ToggleControl::toggleFlipped, this, [this](bool state) { + refreshButtons(state); + }); + + const QString style = R"( + QPushButton { + border-radius: 50px; + font-size: 40px; + font-weight: 500; + height:100px; + padding: 0 25 0 25; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + QPushButton:checked:enabled { + background-color: #0048FF; + } + QPushButton:disabled { + color: #33E4E4E4; + } + )"; + + button_group = new QButtonGroup(this); + button_group->setExclusive(false); + + std::map paramState; + for (const QString &button_param : button_params) { + paramState[button_param] = params.getBool(button_param.toStdString()); + } + + for (int i = 0; i < button_texts.size(); ++i) { + QPushButton *button = new QPushButton(button_texts[i], this); + button->setCheckable(true); + button->setChecked(paramState[button_params[i]]); + button->setStyleSheet(style); + button->setMinimumWidth(minimum_button_width); + button_group->addButton(button, i); + + connect(button, &QPushButton::clicked, [this, button_params, i](bool checked) { + params.putBool(button_params[i].toStdString(), checked); + button_group->button(i)->setChecked(checked); + emit buttonClicked(checked); + }); + + hlayout->insertWidget(hlayout->indexOf(&toggle), button); + } + } + + void refreshButtons(bool state) { + for (QAbstractButton *button : button_group->buttons()) { + button->setVisible(state); + } + } + +signals: + void buttonClicked(const bool checked); + +private: + Params params; + QButtonGroup *button_group; +}; + +class FrogPilotParamValueControl : public ParamControl { + Q_OBJECT + +public: + FrogPilotParamValueControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, + const int &minValue, const int &maxValue, const std::map &valueLabels, + QWidget *parent = nullptr, const bool &loop = true, const QString &label = "", const int &division = 1) + : ParamControl(param, title, desc, icon, parent), + minValue(minValue), maxValue(maxValue), valueLabelMappings(valueLabels), loop(loop), labelText(label), division(division) { + key = param.toStdString(); + + valueLabel = new QLabel(this); + hlayout->addWidget(valueLabel); + + QPushButton *decrementButton = createButton("-", this); + QPushButton *incrementButton = createButton("+", this); + + hlayout->addWidget(decrementButton); + hlayout->addWidget(incrementButton); + + connect(decrementButton, &QPushButton::clicked, this, [=]() { + updateValue(-1); + }); + + connect(incrementButton, &QPushButton::clicked, this, [=]() { + updateValue(1); + }); + + toggle.hide(); + } + + void updateValue(int increment) { + value = value + increment; + + if (loop) { + if (value < minValue) value = maxValue; + else if (value > maxValue) value = minValue; + } else { + value = std::max(minValue, std::min(maxValue, value)); + } + + params.putInt(key, value); + refresh(); + emit buttonPressed(); + emit valueChanged(value); + } + + void refresh() { + value = params.getInt(key); + + QString text; + auto it = valueLabelMappings.find(value); + if (division > 1) { + text = QString::number(value / (division * 1.0), 'g'); + } else { + text = it != valueLabelMappings.end() ? it->second : QString::number(value); + } + if (!labelText.isEmpty()) { + text += labelText; + } + valueLabel->setText(text); + valueLabel->setStyleSheet("QLabel { color: #E0E879; }"); + } + + void updateControl(int newMinValue, int newMaxValue, const QString &newLabel, int newDivision = 1) { + minValue = newMinValue; + maxValue = newMaxValue; + labelText = newLabel; + division = newDivision; + } + + void showEvent(QShowEvent *event) override { + refresh(); + } + +signals: + void buttonPressed(); + void valueChanged(int value); + +private: + bool loop; + int division; + int maxValue; + int minValue; + int value; + QLabel *valueLabel; + QString labelText; + std::map valueLabelMappings; + std::string key; + Params params; + + QPushButton *createButton(const QString &text, QWidget *parent) { + QPushButton *button = new QPushButton(text, parent); + button->setFixedSize(150, 100); + button->setAutoRepeat(true); + button->setAutoRepeatInterval(150); + button->setStyleSheet(R"( + QPushButton { + border-radius: 50px; + font-size: 50px; + font-weight: 500; + height: 100px; + padding: 0 25 0 25; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + )"); + return button; + } +}; + +class FrogPilotParamValueControlFloat : public ParamControl { + Q_OBJECT + +public: + FrogPilotParamValueControlFloat(const QString ¶m, const QString &title, const QString &desc, const QString &icon, + const float &minValue, const float &maxValue, const std::map &valueLabels, + QWidget *parent = nullptr, const bool &loop = true, const QString &label = "", const float &division = 1.0f) + : ParamControl(param, title, desc, icon, parent), + minValue(minValue), maxValue(maxValue), valueLabelMappings(valueLabels), loop(loop), labelText(label), division(division) { + key = param.toStdString(); + + valueLabel = new QLabel(this); + hlayout->addWidget(valueLabel); + + QPushButton *decrementButton = createButton("-", this); + QPushButton *incrementButton = createButton("+", this); + + hlayout->addWidget(decrementButton); + hlayout->addWidget(incrementButton); + + connect(decrementButton, &QPushButton::clicked, this, [=]() { + updateValue(-1.0f); + }); + + connect(incrementButton, &QPushButton::clicked, this, [=]() { + updateValue(1.0f); + }); + + toggle.hide(); + } + + void updateValue(float increment) { + value += increment * 0.1f; + + if (loop) { + if (value < minValue) value = maxValue; + else if (value > maxValue) value = minValue; + } else { + value = std::max(minValue, std::min(maxValue, value)); + } + + params.putFloat(key, value); + refresh(); + emit buttonPressed(); + emit valueChanged(value); + } + + void refresh() { + value = params.getFloat(key); + + QString text; + auto it = valueLabelMappings.find(value); + if (division > 0.1f) { + text = QString::number(value, 'f', 1); + } else { + text = it != valueLabelMappings.end() ? it->second : QString::number(value, 'f', 1); + } + if (!labelText.isEmpty()) { + text += labelText; + } + valueLabel->setText(text); + valueLabel->setStyleSheet("QLabel { color: #E0E879; }"); + } + + void updateControl(float newMinValue, float newMaxValue, const QString &newLabel, float newDivision = 1.0f) { + minValue = newMinValue; + maxValue = newMaxValue; + labelText = newLabel; + division = newDivision; + } + + void showEvent(QShowEvent *event) override { + refresh(); + } + +signals: + void buttonPressed(); + void valueChanged(float value); + +private: + bool loop; + float division; + float maxValue; + float minValue; + float value; + QLabel *valueLabel; + QString labelText; + std::map valueLabelMappings; + std::string key; + Params params; + + QPushButton *createButton(const QString &text, QWidget *parent) { + QPushButton *button = new QPushButton(text, parent); + button->setFixedSize(150, 100); + button->setAutoRepeat(true); + button->setAutoRepeatInterval(150); + button->setStyleSheet(R"( + QPushButton { + border-radius: 50px; + font-size: 50px; + font-weight: 500; + height: 100px; + padding: 0 25 0 25; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + )"); + return button; + } +}; + +class FrogPilotDualParamControl : public QFrame { + Q_OBJECT + +public: + FrogPilotDualParamControl(ParamControl *control1, ParamControl *control2, QWidget *parent = nullptr, bool split=false) + : QFrame(parent) { + QHBoxLayout *hlayout = new QHBoxLayout(this); + + control1->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); + control1->setMaximumWidth(split ? 800 : 700); + + control2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + control2->setMaximumWidth(800); + + hlayout->addWidget(control1); + hlayout->addWidget(control2); + } +}; + +class FrogPilotParamValueToggleControl : public ParamControl { + Q_OBJECT + +public: + FrogPilotParamValueToggleControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, + const int &minValue, const int &maxValue, const std::map &valueLabels, + QWidget *parent = nullptr, const bool &loop = true, const QString &label = "", const int &division = 1, + const std::vector &button_params = std::vector(), const std::vector &button_texts = std::vector(), + const int minimum_button_width = 225) + : ParamControl(param, title, desc, icon, parent), + minValue(minValue), maxValue(maxValue), valueLabelMappings(valueLabels), loop(loop), labelText(label), division(division) { + key = param.toStdString(); + + const QString style = R"( + QPushButton { + border-radius: 50px; + font-size: 40px; + font-weight: 500; + height:100px; + padding: 0 25 0 25; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + QPushButton:checked:enabled { + background-color: #0048FF; + } + QPushButton:disabled { + color: #33E4E4E4; + } + )"; + + button_group = new QButtonGroup(this); + button_group->setExclusive(false); + + std::map paramState; + for (const QString &button_param : button_params) { + paramState[button_param] = params.getBool(button_param.toStdString()); + } + + for (int i = 0; i < button_texts.size(); ++i) { + QPushButton *button = new QPushButton(button_texts[i], this); + button->setCheckable(true); + button->setChecked(paramState[button_params[i]]); + button->setStyleSheet(style); + button->setMinimumWidth(minimum_button_width); + button_group->addButton(button, i); + + connect(button, &QPushButton::clicked, [this, button_params, i](bool checked) { + params.putBool(button_params[i].toStdString(), checked); + button_group->button(i)->setChecked(checked); + }); + + hlayout->addWidget(button); + } + + valueLabel = new QLabel(this); + hlayout->addWidget(valueLabel); + + QPushButton *decrementButton = createButton("-", this); + QPushButton *incrementButton = createButton("+", this); + + hlayout->addWidget(decrementButton); + hlayout->addWidget(incrementButton); + + connect(decrementButton, &QPushButton::clicked, this, [=]() { + updateValue(-1); + }); + + connect(incrementButton, &QPushButton::clicked, this, [=]() { + updateValue(1); + }); + + toggle.hide(); + } + + void updateValue(int increment) { + value = value + increment; + + if (loop) { + if (value < minValue) value = maxValue; + else if (value > maxValue) value = minValue; + } else { + value = std::max(minValue, std::min(maxValue, value)); + } + + params.putInt(key, value); + refresh(); + emit buttonPressed(); + emit valueChanged(value); + } + + void refresh() { + value = params.getInt(key); + + QString text; + auto it = valueLabelMappings.find(value); + if (division > 1) { + text = QString::number(value / (division * 1.0), 'g'); + } else { + text = it != valueLabelMappings.end() ? it->second : QString::number(value); + } + if (!labelText.isEmpty()) { + text += labelText; + } + valueLabel->setText(text); + valueLabel->setStyleSheet("QLabel { color: #E0E879; }"); + } + + void updateControl(int newMinValue, int newMaxValue, const QString &newLabel, int newDivision) { + minValue = newMinValue; + maxValue = newMaxValue; + labelText = newLabel; + division = newDivision; + } + + void showEvent(QShowEvent *event) override { + refresh(); + } + +signals: + void buttonPressed(); + void valueChanged(int value); + +private: + bool loop; + int division; + int maxValue; + int minValue; + int value; + QButtonGroup *button_group; + QLabel *valueLabel; + QString labelText; + std::map valueLabelMappings; + std::string key; + Params params; + + QPushButton *createButton(const QString &text, QWidget *parent) { + QPushButton *button = new QPushButton(text, parent); + button->setFixedSize(150, 100); + button->setAutoRepeat(true); + button->setAutoRepeatInterval(150); + button->setStyleSheet(R"( + QPushButton { + border-radius: 50px; + font-size: 50px; + font-weight: 500; + height: 100px; + padding: 0 25 0 25; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + )"); + return button; + } +}; + +void setDefaultParams(); diff --git a/selfdrive/clearpilot/ui/frogpilot_functions.h.org b/selfdrive/clearpilot/ui/frogpilot_functions.h.org new file mode 100644 index 0000000..26bb046 --- /dev/null +++ b/selfdrive/clearpilot/ui/frogpilot_functions.h.org @@ -0,0 +1,661 @@ +#pragma once + +#include "selfdrive/ui/qt/widgets/controls.h" + +class FrogPilotConfirmationDialog : public ConfirmationDialog { + Q_OBJECT + +public: + explicit FrogPilotConfirmationDialog(const QString &prompt_text, const QString &confirm_text, + const QString &cancel_text, const bool rich, QWidget* parent); + static bool toggle(const QString &prompt_text, const QString &confirm_text, QWidget *parent); + static bool toggleAlert(const QString &prompt_text, const QString &button_text, QWidget *parent); + static bool yesorno(const QString &prompt_text, QWidget *parent); +}; + +class FrogPilotListWidget : public QWidget { + Q_OBJECT +public: + explicit FrogPilotListWidget(QWidget *parent = 0) : QWidget(parent), outer_layout(this) { + outer_layout.setMargin(0); + outer_layout.setSpacing(0); + outer_layout.addLayout(&inner_layout); + inner_layout.setMargin(0); + inner_layout.setSpacing(25); // default spacing is 25 + outer_layout.addStretch(); + } + inline void addItem(QWidget *w) { inner_layout.addWidget(w); } + inline void addItem(QLayout *layout) { inner_layout.addLayout(layout); } + inline void setSpacing(int spacing) { inner_layout.setSpacing(spacing); } + +private: + void paintEvent(QPaintEvent *) override { + QPainter p(this); + p.setPen(Qt::gray); + + int visibleWidgetCount = 0; + std::vector visibleRects; + + for (int i = 0; i < inner_layout.count(); ++i) { + QWidget *widget = inner_layout.itemAt(i)->widget(); + if (widget && widget->isVisible()) { + visibleWidgetCount++; + visibleRects.push_back(inner_layout.itemAt(i)->geometry()); + } + } + + for (int i = 0; i < visibleWidgetCount - 1; ++i) { + int bottom = visibleRects[i].bottom() + inner_layout.spacing() / 2; + p.drawLine(visibleRects[i].left() + 40, bottom, visibleRects[i].right() - 40, bottom); + } + } + QVBoxLayout outer_layout; + QVBoxLayout inner_layout; +}; + +class FrogPilotButtonIconControl : public AbstractControl { + Q_OBJECT + +public: + FrogPilotButtonIconControl(const QString &title, const QString &text, const QString &desc = "", const QString &icon = "", QWidget *parent = nullptr); + inline void setText(const QString &text) { btn.setText(text); } + inline QString text() const { return btn.text(); } + +signals: + void clicked(); + +public slots: + void setEnabled(bool enabled) { btn.setEnabled(enabled); } + +private: + QPushButton btn; +}; + +class FrogPilotButtonParamControl : public ParamControl { + Q_OBJECT +public: + FrogPilotButtonParamControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, + const std::vector &button_texts, const int minimum_button_width = 225) + : ParamControl(param, title, desc, icon) { + const QString style = R"( + QPushButton { + border-radius: 50px; + font-size: 40px; + font-weight: 500; + height:100px; + padding: 0 25 0 25; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + QPushButton:checked:enabled { + background-color: #0048FF; + } + QPushButton:disabled { + color: #33E4E4E4; + } + )"; + + key = param.toStdString(); + int value = atoi(params.get(key).c_str()); + + button_group = new QButtonGroup(this); + button_group->setExclusive(true); + for (size_t i = 0; i < button_texts.size(); i++) { + QPushButton *button = new QPushButton(button_texts[i], this); + button->setCheckable(true); + button->setChecked(i == value); + button->setStyleSheet(style); + button->setMinimumWidth(minimum_button_width); + hlayout->addWidget(button); + button_group->addButton(button, i); + } + + QObject::connect(button_group, QOverload::of(&QButtonGroup::buttonToggled), [=](int id, bool checked) { + if (checked) { + params.put(key, std::to_string(id)); + refresh(); + emit buttonClicked(id); + } + }); + + toggle.hide(); + } + + void setEnabled(bool enable) { + for (auto btn : button_group->buttons()) { + btn->setEnabled(enable); + } + } + +signals: + void buttonClicked(int id); + +private: + std::string key; + Params params; + QButtonGroup *button_group; +}; + +class FrogPilotParamManageControl : public ParamControl { + Q_OBJECT + +public: + FrogPilotParamManageControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, QWidget *parent = nullptr) + : ParamControl(param, title, desc, icon, parent), + key(param.toStdString()), + manageButton(new ButtonControl(tr(""), tr("MANAGE"), tr(""))) { + hlayout->insertWidget(hlayout->indexOf(&toggle) - 1, manageButton); + + connect(this, &ToggleControl::toggleFlipped, this, [this](bool state) { + refresh(); + }); + + connect(manageButton, &ButtonControl::clicked, this, &FrogPilotParamManageControl::manageButtonClicked); + } + + void refresh() { + ParamControl::refresh(); + manageButton->setVisible(params.getBool(key)); + } + + void showEvent(QShowEvent *event) override { + ParamControl::showEvent(event); + refresh(); + } + +signals: + void manageButtonClicked(); + +private: + std::string key; + Params params; + ButtonControl *manageButton; +}; + +class FrogPilotParamToggleControl : public ParamControl { + Q_OBJECT +public: + FrogPilotParamToggleControl(const QString ¶m, const QString &title, const QString &desc, + const QString &icon, const std::vector &button_params, + const std::vector &button_texts, QWidget *parent = nullptr, + const int minimum_button_width = 225) + : ParamControl(param, title, desc, icon, parent) { + + connect(this, &ToggleControl::toggleFlipped, this, [this](bool state) { + refreshButtons(state); + }); + + const QString style = R"( + QPushButton { + border-radius: 50px; + font-size: 40px; + font-weight: 500; + height:100px; + padding: 0 25 0 25; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + QPushButton:checked:enabled { + background-color: #0048FF; + } + QPushButton:disabled { + color: #33E4E4E4; + } + )"; + + button_group = new QButtonGroup(this); + button_group->setExclusive(false); + + std::map paramState; + for (const QString &button_param : button_params) { + paramState[button_param] = params.getBool(button_param.toStdString()); + } + + for (int i = 0; i < button_texts.size(); ++i) { + QPushButton *button = new QPushButton(button_texts[i], this); + button->setCheckable(true); + button->setChecked(paramState[button_params[i]]); + button->setStyleSheet(style); + button->setMinimumWidth(minimum_button_width); + button_group->addButton(button, i); + + connect(button, &QPushButton::clicked, [this, button_params, i](bool checked) { + params.putBool(button_params[i].toStdString(), checked); + button_group->button(i)->setChecked(checked); + emit buttonClicked(checked); + }); + + hlayout->insertWidget(hlayout->indexOf(&toggle), button); + } + } + + void refreshButtons(bool state) { + for (QAbstractButton *button : button_group->buttons()) { + button->setVisible(state); + } + } + +signals: + void buttonClicked(const bool checked); + +private: + Params params; + QButtonGroup *button_group; +}; + +class FrogPilotParamValueControl : public ParamControl { + Q_OBJECT + +public: + FrogPilotParamValueControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, + const int &minValue, const int &maxValue, const std::map &valueLabels, + QWidget *parent = nullptr, const bool &loop = true, const QString &label = "", const int &division = 1) + : ParamControl(param, title, desc, icon, parent), + minValue(minValue), maxValue(maxValue), valueLabelMappings(valueLabels), loop(loop), labelText(label), division(division) { + key = param.toStdString(); + + valueLabel = new QLabel(this); + hlayout->addWidget(valueLabel); + + QPushButton *decrementButton = createButton("-", this); + QPushButton *incrementButton = createButton("+", this); + + hlayout->addWidget(decrementButton); + hlayout->addWidget(incrementButton); + + connect(decrementButton, &QPushButton::clicked, this, [=]() { + updateValue(-1); + }); + + connect(incrementButton, &QPushButton::clicked, this, [=]() { + updateValue(1); + }); + + toggle.hide(); + } + + void updateValue(int increment) { + value = value + increment; + + if (loop) { + if (value < minValue) value = maxValue; + else if (value > maxValue) value = minValue; + } else { + value = std::max(minValue, std::min(maxValue, value)); + } + + params.putInt(key, value); + refresh(); + emit buttonPressed(); + emit valueChanged(value); + } + + void refresh() { + value = params.getInt(key); + + QString text; + auto it = valueLabelMappings.find(value); + if (division > 1) { + text = QString::number(value / (division * 1.0), 'g'); + } else { + text = it != valueLabelMappings.end() ? it->second : QString::number(value); + } + if (!labelText.isEmpty()) { + text += labelText; + } + valueLabel->setText(text); + valueLabel->setStyleSheet("QLabel { color: #E0E879; }"); + } + + void updateControl(int newMinValue, int newMaxValue, const QString &newLabel, int newDivision = 1) { + minValue = newMinValue; + maxValue = newMaxValue; + labelText = newLabel; + division = newDivision; + } + + void showEvent(QShowEvent *event) override { + refresh(); + } + +signals: + void buttonPressed(); + void valueChanged(int value); + +private: + bool loop; + int division; + int maxValue; + int minValue; + int value; + QLabel *valueLabel; + QString labelText; + std::map valueLabelMappings; + std::string key; + Params params; + + QPushButton *createButton(const QString &text, QWidget *parent) { + QPushButton *button = new QPushButton(text, parent); + button->setFixedSize(150, 100); + button->setAutoRepeat(true); + button->setAutoRepeatInterval(150); + button->setStyleSheet(R"( + QPushButton { + border-radius: 50px; + font-size: 50px; + font-weight: 500; + height: 100px; + padding: 0 25 0 25; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + )"); + return button; + } +}; + +class FrogPilotParamValueControlFloat : public ParamControl { + Q_OBJECT + +public: + FrogPilotParamValueControlFloat(const QString ¶m, const QString &title, const QString &desc, const QString &icon, + const float &minValue, const float &maxValue, const std::map &valueLabels, + QWidget *parent = nullptr, const bool &loop = true, const QString &label = "", const float &division = 1.0f) + : ParamControl(param, title, desc, icon, parent), + minValue(minValue), maxValue(maxValue), valueLabelMappings(valueLabels), loop(loop), labelText(label), division(division) { + key = param.toStdString(); + + valueLabel = new QLabel(this); + hlayout->addWidget(valueLabel); + + QPushButton *decrementButton = createButton("-", this); + QPushButton *incrementButton = createButton("+", this); + + hlayout->addWidget(decrementButton); + hlayout->addWidget(incrementButton); + + connect(decrementButton, &QPushButton::clicked, this, [=]() { + updateValue(-1.0f); + }); + + connect(incrementButton, &QPushButton::clicked, this, [=]() { + updateValue(1.0f); + }); + + toggle.hide(); + } + + void updateValue(float increment) { + value += increment * 0.1f; + + if (loop) { + if (value < minValue) value = maxValue; + else if (value > maxValue) value = minValue; + } else { + value = std::max(minValue, std::min(maxValue, value)); + } + + params.putFloat(key, value); + refresh(); + emit buttonPressed(); + emit valueChanged(value); + } + + void refresh() { + value = params.getFloat(key); + + QString text; + auto it = valueLabelMappings.find(value); + if (division > 0.1f) { + text = QString::number(value, 'f', 1); + } else { + text = it != valueLabelMappings.end() ? it->second : QString::number(value, 'f', 1); + } + if (!labelText.isEmpty()) { + text += labelText; + } + valueLabel->setText(text); + valueLabel->setStyleSheet("QLabel { color: #E0E879; }"); + } + + void updateControl(float newMinValue, float newMaxValue, const QString &newLabel, float newDivision = 1.0f) { + minValue = newMinValue; + maxValue = newMaxValue; + labelText = newLabel; + division = newDivision; + } + + void showEvent(QShowEvent *event) override { + refresh(); + } + +signals: + void buttonPressed(); + void valueChanged(float value); + +private: + bool loop; + float division; + float maxValue; + float minValue; + float value; + QLabel *valueLabel; + QString labelText; + std::map valueLabelMappings; + std::string key; + Params params; + + QPushButton *createButton(const QString &text, QWidget *parent) { + QPushButton *button = new QPushButton(text, parent); + button->setFixedSize(150, 100); + button->setAutoRepeat(true); + button->setAutoRepeatInterval(150); + button->setStyleSheet(R"( + QPushButton { + border-radius: 50px; + font-size: 50px; + font-weight: 500; + height: 100px; + padding: 0 25 0 25; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + )"); + return button; + } +}; + +class FrogPilotDualParamControl : public QFrame { + Q_OBJECT + +public: + FrogPilotDualParamControl(ParamControl *control1, ParamControl *control2, QWidget *parent = nullptr, bool split=false) + : QFrame(parent) { + QHBoxLayout *hlayout = new QHBoxLayout(this); + + control1->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); + control1->setMaximumWidth(split ? 800 : 700); + + control2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + control2->setMaximumWidth(800); + + hlayout->addWidget(control1); + hlayout->addWidget(control2); + } +}; + +class FrogPilotParamValueToggleControl : public ParamControl { + Q_OBJECT + +public: + FrogPilotParamValueToggleControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, + const int &minValue, const int &maxValue, const std::map &valueLabels, + QWidget *parent = nullptr, const bool &loop = true, const QString &label = "", const int &division = 1, + const std::vector &button_params = std::vector(), const std::vector &button_texts = std::vector(), + const int minimum_button_width = 225) + : ParamControl(param, title, desc, icon, parent), + minValue(minValue), maxValue(maxValue), valueLabelMappings(valueLabels), loop(loop), labelText(label), division(division) { + key = param.toStdString(); + + const QString style = R"( + QPushButton { + border-radius: 50px; + font-size: 40px; + font-weight: 500; + height:100px; + padding: 0 25 0 25; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + QPushButton:checked:enabled { + background-color: #0048FF; + } + QPushButton:disabled { + color: #33E4E4E4; + } + )"; + + button_group = new QButtonGroup(this); + button_group->setExclusive(false); + + std::map paramState; + for (const QString &button_param : button_params) { + paramState[button_param] = params.getBool(button_param.toStdString()); + } + + for (int i = 0; i < button_texts.size(); ++i) { + QPushButton *button = new QPushButton(button_texts[i], this); + button->setCheckable(true); + button->setChecked(paramState[button_params[i]]); + button->setStyleSheet(style); + button->setMinimumWidth(minimum_button_width); + button_group->addButton(button, i); + + connect(button, &QPushButton::clicked, [this, button_params, i](bool checked) { + params.putBool(button_params[i].toStdString(), checked); + button_group->button(i)->setChecked(checked); + }); + + hlayout->addWidget(button); + } + + valueLabel = new QLabel(this); + hlayout->addWidget(valueLabel); + + QPushButton *decrementButton = createButton("-", this); + QPushButton *incrementButton = createButton("+", this); + + hlayout->addWidget(decrementButton); + hlayout->addWidget(incrementButton); + + connect(decrementButton, &QPushButton::clicked, this, [=]() { + updateValue(-1); + }); + + connect(incrementButton, &QPushButton::clicked, this, [=]() { + updateValue(1); + }); + + toggle.hide(); + } + + void updateValue(int increment) { + value = value + increment; + + if (loop) { + if (value < minValue) value = maxValue; + else if (value > maxValue) value = minValue; + } else { + value = std::max(minValue, std::min(maxValue, value)); + } + + params.putInt(key, value); + refresh(); + emit buttonPressed(); + emit valueChanged(value); + } + + void refresh() { + value = params.getInt(key); + + QString text; + auto it = valueLabelMappings.find(value); + if (division > 1) { + text = QString::number(value / (division * 1.0), 'g'); + } else { + text = it != valueLabelMappings.end() ? it->second : QString::number(value); + } + if (!labelText.isEmpty()) { + text += labelText; + } + valueLabel->setText(text); + valueLabel->setStyleSheet("QLabel { color: #E0E879; }"); + } + + void updateControl(int newMinValue, int newMaxValue, const QString &newLabel, int newDivision) { + minValue = newMinValue; + maxValue = newMaxValue; + labelText = newLabel; + division = newDivision; + } + + void showEvent(QShowEvent *event) override { + refresh(); + } + +signals: + void buttonPressed(); + void valueChanged(int value); + +private: + bool loop; + int division; + int maxValue; + int minValue; + int value; + QButtonGroup *button_group; + QLabel *valueLabel; + QString labelText; + std::map valueLabelMappings; + std::string key; + Params params; + + QPushButton *createButton(const QString &text, QWidget *parent) { + QPushButton *button = new QPushButton(text, parent); + button->setFixedSize(150, 100); + button->setAutoRepeat(true); + button->setAutoRepeatInterval(150); + button->setStyleSheet(R"( + QPushButton { + border-radius: 50px; + font-size: 50px; + font-weight: 500; + height: 100px; + padding: 0 25 0 25; + color: #E4E4E4; + background-color: #393939; + } + QPushButton:pressed { + background-color: #4a4a4a; + } + )"); + return button; + } +}; + +void setDefaultParams(); diff --git a/selfdrive/clearpilot/ui/vehicle_settings.cc b/selfdrive/clearpilot/ui/vehicle_settings.cc new file mode 100644 index 0000000..b658218 --- /dev/null +++ b/selfdrive/clearpilot/ui/vehicle_settings.cc @@ -0,0 +1,185 @@ +#include +#include +#include + +#include "selfdrive/frogpilot/ui/vehicle_settings.h" +#include "selfdrive/ui/ui.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["subaru"] = "subaru"; + makeMap["tesla"] = "tesla"; + makeMap["toyota"] = "toyota"; + makeMap["volkswagen"] = "volkswagen"; + makeMap["skoda"] = "volkswagen"; + + QString dirPath = "../../selfdrive/car"; + QDir dir(dirPath); + QString targetFolder = makeMap.value(carMake, carMake); + QStringList names; + + foreach (const QString &folder, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { + if (folder == targetFolder) { + QFile file(dirPath + "/" + folder + "/values.py"); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QRegularExpression regex("class CAR\\(StrEnum\\):([\\s\\S]*?)(?=^\\w)", QRegularExpression::MultilineOption); + QRegularExpressionMatch match = regex.match(QTextStream(&file).readAll()); + file.close(); + + if (match.hasMatch()) { + QRegularExpression nameRegex("=\\s*\"([^\"]+)\""); + QRegularExpressionMatchIterator it = nameRegex.globalMatch(match.captured(1)); + while (it.hasNext()) { + names << it.next().captured(1); + } + } + } + } + } + + 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]() { + std::string currentMake = params.get("CarMake"); + 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", "Subaru", "Tesla", "Toyota", "Volkswagen", "Volvo", "Škoda", + }; + + QString newMakeSelection = MultiOptionDialog::getSelection(tr("Select a Make"), makes, QString::fromStdString(currentMake), this); + if (!newMakeSelection.isEmpty()) { + carMake = newMakeSelection; + params.put("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]() { + std::string currentModel = params.get("CarModel"); + QString newModelSelection = MultiOptionDialog::getSelection(tr("Select a Model"), models, QString::fromStdString(currentModel), this); + if (!newModelSelection.isEmpty()) { + params.put("CarModel", newModelSelection.toStdString()); + selectModelButton->setValue(newModelSelection); + } + }); + selectModelButton->setValue(modelSelection); + addItem(selectModelButton); + selectModelButton->setVisible(false); + + std::vector> vehicleToggles { + {"EVTable", "EV Lookup Tables", "Smoothen out the gas and brake controls for EV vehicles.", ""}, + {"GasRegenCmd", "Gas Regen Cmd", "", ""}, + {"LongPitch", "Long Pitch Compensation", "Reduce speed and acceleration error for greater passenger comfort and improved vehicle efficiency.", ""}, + {"LowerVolt", "Lower Volt Enable Speed", "Lower the Volt's minimum enable speed to enable openpilot at any speed.", ""}, + + {"LockDoors", "Lock Doors In Drive", "Automatically lock the doors when in drive and unlock when in park.", ""}, + {"SNGHack", "Stop and Go Hack", "Enable the 'Stop and Go' hack for vehicles without stock stop and go functionality.", ""}, + {"TSS2Tune", "TSS2 Tune", "Tuning profile based on the tuning profile from DragonPilot for TSS2 vehicles.", ""} + }; + + for (auto &[param, title, desc, icon] : vehicleToggles) { + ParamControl *toggle = new ParamControl(param, title, desc, icon, this); + + addItem(toggle); + toggle->setVisible(false); + toggles[param.toStdString()] = toggle; + + QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() { + updateToggles(); + }); + } + + gmKeys = {"EVTable", "GasRegenCmd", "LongPitch", "LowerVolt"}; + toyotaKeys = {"LockDoors", "SNGHack", "TSS2Tune"}; + + std::set rebootKeys = {"EVTable", "GasRegenCmd", "LongPitch", "LowerVolt", "TSS2Tune"}; + for (const std::string &key : rebootKeys) { + QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() { + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + }); + } + + QObject::connect(uiState(), &UIState::offroadTransition, this, [this](bool offroad) { + if (!offroad) { + std::thread([this]() { + while (carMake.isEmpty()) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + carMake = QString::fromStdString(params.get("CarMake")); + } + setModels(); + }).detach(); + } + }); + + carMake = QString::fromStdString(params.get("CarMake")); + if (!carMake.isEmpty()) { + setModels(); + } +} + +void FrogPilotVehiclesPanel::updateToggles() { + std::thread([this]() { + paramsMemory.putBool("FrogPilotTogglesUpdated", true); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + paramsMemory.putBool("FrogPilotTogglesUpdated", false); + }).detach(); +} + +void FrogPilotVehiclesPanel::setModels() { + models = getCarNames(carMake.toLower()); + setToggles(); +} + +void FrogPilotVehiclesPanel::setToggles() { + selectMakeButton->setValue(carMake); + selectModelButton->setVisible(!carMake.isEmpty()); + + bool gm = carMake == "Buick" || carMake == "Cadillac" || carMake == "Chevrolet" || carMake == "GM" || carMake == "GMC"; + bool toyota = carMake == "Lexus" || carMake == "Toyota"; + + for (auto &[key, toggle] : toggles) { + toggle->setVisible(false); + + if (gm) { + toggle->setVisible(gmKeys.find(key.c_str()) != gmKeys.end()); + } else if (toyota) { + toggle->setVisible(toyotaKeys.find(key.c_str()) != toyotaKeys.end()); + } + } + + update(); +} diff --git a/selfdrive/clearpilot/ui/vehicle_settings.cc.org b/selfdrive/clearpilot/ui/vehicle_settings.cc.org new file mode 100644 index 0000000..b658218 --- /dev/null +++ b/selfdrive/clearpilot/ui/vehicle_settings.cc.org @@ -0,0 +1,185 @@ +#include +#include +#include + +#include "selfdrive/frogpilot/ui/vehicle_settings.h" +#include "selfdrive/ui/ui.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["subaru"] = "subaru"; + makeMap["tesla"] = "tesla"; + makeMap["toyota"] = "toyota"; + makeMap["volkswagen"] = "volkswagen"; + makeMap["skoda"] = "volkswagen"; + + QString dirPath = "../../selfdrive/car"; + QDir dir(dirPath); + QString targetFolder = makeMap.value(carMake, carMake); + QStringList names; + + foreach (const QString &folder, dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { + if (folder == targetFolder) { + QFile file(dirPath + "/" + folder + "/values.py"); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QRegularExpression regex("class CAR\\(StrEnum\\):([\\s\\S]*?)(?=^\\w)", QRegularExpression::MultilineOption); + QRegularExpressionMatch match = regex.match(QTextStream(&file).readAll()); + file.close(); + + if (match.hasMatch()) { + QRegularExpression nameRegex("=\\s*\"([^\"]+)\""); + QRegularExpressionMatchIterator it = nameRegex.globalMatch(match.captured(1)); + while (it.hasNext()) { + names << it.next().captured(1); + } + } + } + } + } + + 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]() { + std::string currentMake = params.get("CarMake"); + 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", "Subaru", "Tesla", "Toyota", "Volkswagen", "Volvo", "Škoda", + }; + + QString newMakeSelection = MultiOptionDialog::getSelection(tr("Select a Make"), makes, QString::fromStdString(currentMake), this); + if (!newMakeSelection.isEmpty()) { + carMake = newMakeSelection; + params.put("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]() { + std::string currentModel = params.get("CarModel"); + QString newModelSelection = MultiOptionDialog::getSelection(tr("Select a Model"), models, QString::fromStdString(currentModel), this); + if (!newModelSelection.isEmpty()) { + params.put("CarModel", newModelSelection.toStdString()); + selectModelButton->setValue(newModelSelection); + } + }); + selectModelButton->setValue(modelSelection); + addItem(selectModelButton); + selectModelButton->setVisible(false); + + std::vector> vehicleToggles { + {"EVTable", "EV Lookup Tables", "Smoothen out the gas and brake controls for EV vehicles.", ""}, + {"GasRegenCmd", "Gas Regen Cmd", "", ""}, + {"LongPitch", "Long Pitch Compensation", "Reduce speed and acceleration error for greater passenger comfort and improved vehicle efficiency.", ""}, + {"LowerVolt", "Lower Volt Enable Speed", "Lower the Volt's minimum enable speed to enable openpilot at any speed.", ""}, + + {"LockDoors", "Lock Doors In Drive", "Automatically lock the doors when in drive and unlock when in park.", ""}, + {"SNGHack", "Stop and Go Hack", "Enable the 'Stop and Go' hack for vehicles without stock stop and go functionality.", ""}, + {"TSS2Tune", "TSS2 Tune", "Tuning profile based on the tuning profile from DragonPilot for TSS2 vehicles.", ""} + }; + + for (auto &[param, title, desc, icon] : vehicleToggles) { + ParamControl *toggle = new ParamControl(param, title, desc, icon, this); + + addItem(toggle); + toggle->setVisible(false); + toggles[param.toStdString()] = toggle; + + QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() { + updateToggles(); + }); + } + + gmKeys = {"EVTable", "GasRegenCmd", "LongPitch", "LowerVolt"}; + toyotaKeys = {"LockDoors", "SNGHack", "TSS2Tune"}; + + std::set rebootKeys = {"EVTable", "GasRegenCmd", "LongPitch", "LowerVolt", "TSS2Tune"}; + for (const std::string &key : rebootKeys) { + QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() { + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + }); + } + + QObject::connect(uiState(), &UIState::offroadTransition, this, [this](bool offroad) { + if (!offroad) { + std::thread([this]() { + while (carMake.isEmpty()) { + std::this_thread::sleep_for(std::chrono::seconds(1)); + carMake = QString::fromStdString(params.get("CarMake")); + } + setModels(); + }).detach(); + } + }); + + carMake = QString::fromStdString(params.get("CarMake")); + if (!carMake.isEmpty()) { + setModels(); + } +} + +void FrogPilotVehiclesPanel::updateToggles() { + std::thread([this]() { + paramsMemory.putBool("FrogPilotTogglesUpdated", true); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + paramsMemory.putBool("FrogPilotTogglesUpdated", false); + }).detach(); +} + +void FrogPilotVehiclesPanel::setModels() { + models = getCarNames(carMake.toLower()); + setToggles(); +} + +void FrogPilotVehiclesPanel::setToggles() { + selectMakeButton->setValue(carMake); + selectModelButton->setVisible(!carMake.isEmpty()); + + bool gm = carMake == "Buick" || carMake == "Cadillac" || carMake == "Chevrolet" || carMake == "GM" || carMake == "GMC"; + bool toyota = carMake == "Lexus" || carMake == "Toyota"; + + for (auto &[key, toggle] : toggles) { + toggle->setVisible(false); + + if (gm) { + toggle->setVisible(gmKeys.find(key.c_str()) != gmKeys.end()); + } else if (toyota) { + toggle->setVisible(toyotaKeys.find(key.c_str()) != toyotaKeys.end()); + } + } + + update(); +} diff --git a/selfdrive/clearpilot/ui/vehicle_settings.h b/selfdrive/clearpilot/ui/vehicle_settings.h new file mode 100644 index 0000000..d8d8a32 --- /dev/null +++ b/selfdrive/clearpilot/ui/vehicle_settings.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include + +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/ui/qt/offroad/settings.h" + +class FrogPilotVehiclesPanel : public FrogPilotListWidget { + Q_OBJECT + +public: + explicit FrogPilotVehiclesPanel(SettingsWindow *parent); + +private: + void setModels(); + void setToggles(); + void updateToggles(); + + ButtonControl *selectMakeButton; + ButtonControl *selectModelButton; + + QString carMake; + QStringList models; + + std::map toggles; + + std::set gmKeys; + std::set toyotaKeys; + + Params params; + Params paramsMemory{"/dev/shm/params"}; +}; diff --git a/selfdrive/clearpilot/ui/vehicle_settings.h.org b/selfdrive/clearpilot/ui/vehicle_settings.h.org new file mode 100644 index 0000000..d8d8a32 --- /dev/null +++ b/selfdrive/clearpilot/ui/vehicle_settings.h.org @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include + +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/ui/qt/offroad/settings.h" + +class FrogPilotVehiclesPanel : public FrogPilotListWidget { + Q_OBJECT + +public: + explicit FrogPilotVehiclesPanel(SettingsWindow *parent); + +private: + void setModels(); + void setToggles(); + void updateToggles(); + + ButtonControl *selectMakeButton; + ButtonControl *selectModelButton; + + QString carMake; + QStringList models; + + std::map toggles; + + std::set gmKeys; + std::set toyotaKeys; + + Params params; + Params paramsMemory{"/dev/shm/params"}; +}; diff --git a/selfdrive/clearpilot/ui/visual_settings.cc b/selfdrive/clearpilot/ui/visual_settings.cc new file mode 100644 index 0000000..3bad476 --- /dev/null +++ b/selfdrive/clearpilot/ui/visual_settings.cc @@ -0,0 +1,242 @@ +#include "selfdrive/frogpilot/ui/visual_settings.h" +#include "selfdrive/ui/ui.h" + +FrogPilotVisualsPanel::FrogPilotVisualsPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) { + const std::vector> visualToggles { + {"CustomTheme", "Custom Themes", "Enable the ability to use custom themes.", "../frogpilot/assets/wheel_images/frog.png"}, + {"CustomColors", "Color Theme", "Switch out the standard openpilot color scheme with a custom color scheme.\n\nWant to submit your own color scheme? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + {"CustomIcons", "Icon Pack", "Switch out the standard openpilot icons with a set of custom icons.\n\nWant to submit your own icon pack? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + {"CustomSignals", "Turn Signals", "Add custom animations for your turn signals for a personal touch!\n\nWant to submit your own turn signal animation? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + {"CustomSounds", "Sound Pack", "Switch out the standard openpilot sounds with a set of custom sounds.\n\nWant to submit your own sound pack? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + + {"CameraView", "Camera View", "Choose your preferred camera view for the onroad UI. This is a visual change only and doesn't impact openpilot.", "../frogpilot/assets/toggle_icons/icon_camera.png"}, + {"Compass", "Compass", "Add a compass to your onroad UI.", "../frogpilot/assets/toggle_icons/icon_compass.png"}, + + {"CustomUI", "Custom Onroad UI", "Customize the Onroad UI with some additional visual functions.", "../assets/offroad/icon_road.png"}, + {"AdjacentPath", "Adjacent Paths", "Display paths to the left and right of your car, visualizing where the model detects lanes.", ""}, + {"BlindSpotPath", "Blind Spot Path", "Visualize your blind spots with a red path when another vehicle is detected nearby.", ""}, + {"ShowFPS", "FPS Counter", "Display the Frames Per Second (FPS) of your onroad UI for monitoring system performance.", ""}, + {"LeadInfo", "Lead Info and Logics", "Get detailed information about the vehicle ahead, including speed and distance, and the logic behind your following distance.", ""}, + {"RoadNameUI", "Road Name", "See the name of the road you're on at the bottom of your screen. Sourced from OpenStreetMap.", ""}, + {"UseVienna", "Use Vienna Speed Limit Signs", "Use the Vienna (EU) speed limit style signs as opposed to MUTCD (US).", ""}, + + {"DriverCamera", "Driver Camera On Reverse", "Show the driver's camera feed when you shift to reverse.", "../assets/img_driver_face_static.png"}, + {"GreenLightAlert", "Green Light Alert", "Get an alert when a traffic light changes from red to green.", "../frogpilot/assets/toggle_icons/icon_green_light.png"}, + + {"ModelUI", "Model UI", "Personalize how the model's visualizations appear on your screen.", "../assets/offroad/icon_calibration.png"}, + {"AccelerationPath", "Acceleration Path", "Visualize the car's intended acceleration or deceleration with a color-coded path.", ""}, + {"LaneLinesWidth", "Lane Lines", "Adjust the visual thickness of lane lines on your display.\n\nDefault matches the MUTCD average of 4 inches.", ""}, + {"PathEdgeWidth", "Path Edges", "Adjust the width of the path edges shown on your UI to represent different driving modes and statuses.\n\nDefault is 20% of the total path.\n\nBlue = Navigation\nLight Blue = Always On Lateral\nGreen = Default with 'FrogPilot Colors'\nLight Green = Default with stock colors\nOrange = Experimental Mode Active\nYellow = Conditional Overriden", ""}, + {"PathWidth", "Path Width", "Customize the width of the driving path shown on your UI.\n\nDefault matches the width of a 2019 Lexus ES 350.", ""}, + {"RoadEdgesWidth", "Road Edges", "Adjust the visual thickness of road edges on your display.\n\nDefault is 1/2 of the MUTCD average lane line width of 4 inches.", ""}, + {"UnlimitedLength", "'Unlimited' Road UI Length", "Extend the display of the path, lane lines, and road edges as far as the system can detect, providing a more expansive view of the road ahead.", ""}, + + {"QOLVisuals", "Quality of Life", "Miscellaneous quality of life changes to improve your overall openpilot experience.", "../frogpilot/assets/toggle_icons/quality_of_life.png"}, + {"DriveStats", "Drive Stats In Home Screen", "Display your device's drive stats in the home screen.", ""}, + {"HideSpeed", "Hide Speed", "Hide the speed indicator in the onroad UI.", ""}, + {"ShowSLCOffset", "Show Speed Limit Offset", "Show the speed limit offset seperated from the speed limit in the onroad UI when using 'Speed Limit Controller'.", ""}, + + {"RandomEvents", "Random Events", "Enjoy a bit of unpredictability with random events that can occur during certain driving conditions.", "../frogpilot/assets/toggle_icons/icon_random.png"}, + {"ScreenBrightness", "Screen Brightness", "Customize your screen brightness.", "../frogpilot/assets/toggle_icons/icon_light.png"}, + {"SilentMode", "Silent Mode", "Mute openpilot sounds for a quieter driving experience.", "../frogpilot/assets/toggle_icons/icon_mute.png"}, + {"WheelIcon", "Steering Wheel Icon", "Replace the default steering wheel icon with a custom design, adding a unique touch to your interface.", "../assets/offroad/icon_openpilot.png"}, + }; + + for (const auto &[param, title, desc, icon] : visualToggles) { + ParamControl *toggle; + + if (param == "CameraView") { + std::vector cameraOptions{tr("Auto"), tr("Standard"), tr("Wide"), tr("Driver")}; + FrogPilotButtonParamControl *preferredCamera = new FrogPilotButtonParamControl(param, title, desc, icon, cameraOptions); + toggle = preferredCamera; + + } else if (param == "CustomTheme") { + FrogPilotParamManageControl *customThemeToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(customThemeToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(customThemeKeys.find(key.c_str()) != customThemeKeys.end()); + } + }); + toggle = customThemeToggle; + } else if (param == "CustomColors" || param == "CustomIcons" || param == "CustomSignals" || param == "CustomSounds") { + std::vector themeOptions{tr("Stock"), tr("Frog"), tr("Tesla"), tr("Stalin")}; + FrogPilotButtonParamControl *themeSelection = new FrogPilotButtonParamControl(param, title, desc, icon, themeOptions); + toggle = themeSelection; + + if (param == "CustomSounds") { + QObject::connect(static_cast(toggle), &FrogPilotButtonParamControl::buttonClicked, [this](int id) { + if (id == 1) { + if (FrogPilotConfirmationDialog::yesorno("Do you want to enable the bonus 'Goat' sound effect?", this)) { + params.putBool("GoatScream", true); + } else { + params.putBool("GoatScream", false); + } + } + }); + } + + } else if (param == "CustomUI") { + FrogPilotParamManageControl *customUIToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(customUIToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end()); + } + }); + toggle = customUIToggle; + } else if (param == "LeadInfo") { + std::vector leadInfoToggles{tr("UseSI")}; + std::vector leadInfoToggleNames{tr("Use SI Values")}; + toggle = new FrogPilotParamToggleControl(param, title, desc, icon, leadInfoToggles, leadInfoToggleNames); + + } else if (param == "ModelUI") { + FrogPilotParamManageControl *modelUIToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(modelUIToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(modelUIKeys.find(key.c_str()) != modelUIKeys.end()); + } + }); + toggle = modelUIToggle; + } else if (param == "LaneLinesWidth" || param == "RoadEdgesWidth") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 24, std::map(), this, false, " inches"); + } else if (param == "PathEdgeWidth") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, std::map(), this, false, "%"); + } else if (param == "PathWidth") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, std::map(), this, false, " feet", 10); + + } else if (param == "QOLVisuals") { + FrogPilotParamManageControl *qolToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(qolToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(qolKeys.find(key.c_str()) != qolKeys.end()); + } + }); + toggle = qolToggle; + + } else if (param == "ScreenBrightness") { + std::map brightnessLabels; + for (int i = 0; i <= 101; ++i) { + brightnessLabels[i] = i == 0 ? "Screen Off" : i == 101 ? "Auto" : QString::number(i) + "%"; + } + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 101, brightnessLabels, this, false); + + } else if (param == "WheelIcon") { + std::vector wheelToggles{"RotatingWheel"}; + std::vector wheelToggleNames{tr("Rotating")}; + std::map steeringWheelLabels = {{0, "Stock"}, {1, "Lexus"}, {2, "Toyota"}, {3, "Frog"}, {4, "Rocket"}, {5, "Hyundai"}, {6, "Stalin"}}; + toggle = new FrogPilotParamValueToggleControl(param, title, desc, icon, 0, 6, steeringWheelLabels, this, true, "", 1, wheelToggles, wheelToggleNames); + + } else { + toggle = new ParamControl(param, title, desc, icon, this); + } + + addItem(toggle); + toggles[param.toStdString()] = toggle; + + QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() { + updateToggles(); + }); + + QObject::connect(static_cast(toggle), &FrogPilotParamValueControl::buttonPressed, [this]() { + updateToggles(); + }); + + QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() { + update(); + }); + + QObject::connect(static_cast(toggle), &FrogPilotParamManageControl::manageButtonClicked, [this]() { + update(); + }); + } + + std::set rebootKeys = {"DriveStats"}; + for (const std::string &key : rebootKeys) { + QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() { + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + }); + } + + customOnroadUIKeys = {"AdjacentPath", "BlindSpotPath", "ShowFPS", "LeadInfo", "RoadNameUI", "UseVienna"}; + customThemeKeys = {"CustomColors", "CustomIcons", "CustomSignals", "CustomSounds"}; + modelUIKeys = {"AccelerationPath", "LaneLinesWidth", "PathEdgeWidth", "PathWidth", "RoadEdgesWidth", "UnlimitedLength"}; + qolKeys = {"DriveStats", "HideSpeed", "ShowSLCOffset"}; + + QObject::connect(device(), &Device::interactiveTimeout, this, &FrogPilotVisualsPanel::hideSubToggles); + QObject::connect(parent, &SettingsWindow::closeParentToggle, this, &FrogPilotVisualsPanel::hideSubToggles); + QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotVisualsPanel::updateMetric); + + hideSubToggles(); + updateMetric(); +} + +void FrogPilotVisualsPanel::updateToggles() { + std::thread([this]() { + paramsMemory.putBool("FrogPilotTogglesUpdated", true); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + paramsMemory.putBool("FrogPilotTogglesUpdated", false); + }).detach(); +} + +void FrogPilotVisualsPanel::updateMetric() { + bool previousIsMetric = isMetric; + isMetric = params.getBool("IsMetric"); + + if (isMetric != previousIsMetric) { + double distanceConversion = isMetric ? INCH_TO_CM : CM_TO_INCH; + double speedConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT; + params.putInt("LaneLinesWidth", std::nearbyint(params.getInt("LaneLinesWidth") * distanceConversion)); + params.putInt("RoadEdgesWidth", std::nearbyint(params.getInt("RoadEdgesWidth") * distanceConversion)); + params.putInt("PathWidth", std::nearbyint(params.getInt("PathWidth") * speedConversion)); + } + + FrogPilotParamValueControl *laneLinesWidthToggle = static_cast(toggles["LaneLinesWidth"]); + FrogPilotParamValueControl *roadEdgesWidthToggle = static_cast(toggles["RoadEdgesWidth"]); + FrogPilotParamValueControl *pathWidthToggle = static_cast(toggles["PathWidth"]); + + if (isMetric) { + laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the Vienna average of 10 centimeters."); + roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the Vienna average lane line width of 10 centimeters."); + + laneLinesWidthToggle->updateControl(0, 60, " centimeters"); + roadEdgesWidthToggle->updateControl(0, 60, " centimeters"); + pathWidthToggle->updateControl(0, 30, " meters"); + } else { + laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the MUTCD average of 4 inches."); + roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the MUTCD average lane line width of 4 inches."); + + laneLinesWidthToggle->updateControl(0, 24, " inches"); + roadEdgesWidthToggle->updateControl(0, 24, " inches"); + pathWidthToggle->updateControl(0, 100, " feet"); + } + + laneLinesWidthToggle->refresh(); + roadEdgesWidthToggle->refresh(); + + previousIsMetric = isMetric; +} + +void FrogPilotVisualsPanel::parentToggleClicked() { + this->openParentToggle(); +} + +void FrogPilotVisualsPanel::hideSubToggles() { + for (auto &[key, toggle] : toggles) { + bool subToggles = modelUIKeys.find(key.c_str()) != modelUIKeys.end() || + customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end() || + customThemeKeys.find(key.c_str()) != customThemeKeys.end() || + qolKeys.find(key.c_str()) != qolKeys.end(); + toggle->setVisible(!subToggles); + } + + this->closeParentToggle(); +} + +void FrogPilotVisualsPanel::hideEvent(QHideEvent *event) { + hideSubToggles(); +} diff --git a/selfdrive/clearpilot/ui/visual_settings.cc.org b/selfdrive/clearpilot/ui/visual_settings.cc.org new file mode 100644 index 0000000..3bad476 --- /dev/null +++ b/selfdrive/clearpilot/ui/visual_settings.cc.org @@ -0,0 +1,242 @@ +#include "selfdrive/frogpilot/ui/visual_settings.h" +#include "selfdrive/ui/ui.h" + +FrogPilotVisualsPanel::FrogPilotVisualsPanel(SettingsWindow *parent) : FrogPilotListWidget(parent) { + const std::vector> visualToggles { + {"CustomTheme", "Custom Themes", "Enable the ability to use custom themes.", "../frogpilot/assets/wheel_images/frog.png"}, + {"CustomColors", "Color Theme", "Switch out the standard openpilot color scheme with a custom color scheme.\n\nWant to submit your own color scheme? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + {"CustomIcons", "Icon Pack", "Switch out the standard openpilot icons with a set of custom icons.\n\nWant to submit your own icon pack? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + {"CustomSignals", "Turn Signals", "Add custom animations for your turn signals for a personal touch!\n\nWant to submit your own turn signal animation? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + {"CustomSounds", "Sound Pack", "Switch out the standard openpilot sounds with a set of custom sounds.\n\nWant to submit your own sound pack? Post it in the 'feature-request' channel in the FrogPilot Discord!", ""}, + + {"CameraView", "Camera View", "Choose your preferred camera view for the onroad UI. This is a visual change only and doesn't impact openpilot.", "../frogpilot/assets/toggle_icons/icon_camera.png"}, + {"Compass", "Compass", "Add a compass to your onroad UI.", "../frogpilot/assets/toggle_icons/icon_compass.png"}, + + {"CustomUI", "Custom Onroad UI", "Customize the Onroad UI with some additional visual functions.", "../assets/offroad/icon_road.png"}, + {"AdjacentPath", "Adjacent Paths", "Display paths to the left and right of your car, visualizing where the model detects lanes.", ""}, + {"BlindSpotPath", "Blind Spot Path", "Visualize your blind spots with a red path when another vehicle is detected nearby.", ""}, + {"ShowFPS", "FPS Counter", "Display the Frames Per Second (FPS) of your onroad UI for monitoring system performance.", ""}, + {"LeadInfo", "Lead Info and Logics", "Get detailed information about the vehicle ahead, including speed and distance, and the logic behind your following distance.", ""}, + {"RoadNameUI", "Road Name", "See the name of the road you're on at the bottom of your screen. Sourced from OpenStreetMap.", ""}, + {"UseVienna", "Use Vienna Speed Limit Signs", "Use the Vienna (EU) speed limit style signs as opposed to MUTCD (US).", ""}, + + {"DriverCamera", "Driver Camera On Reverse", "Show the driver's camera feed when you shift to reverse.", "../assets/img_driver_face_static.png"}, + {"GreenLightAlert", "Green Light Alert", "Get an alert when a traffic light changes from red to green.", "../frogpilot/assets/toggle_icons/icon_green_light.png"}, + + {"ModelUI", "Model UI", "Personalize how the model's visualizations appear on your screen.", "../assets/offroad/icon_calibration.png"}, + {"AccelerationPath", "Acceleration Path", "Visualize the car's intended acceleration or deceleration with a color-coded path.", ""}, + {"LaneLinesWidth", "Lane Lines", "Adjust the visual thickness of lane lines on your display.\n\nDefault matches the MUTCD average of 4 inches.", ""}, + {"PathEdgeWidth", "Path Edges", "Adjust the width of the path edges shown on your UI to represent different driving modes and statuses.\n\nDefault is 20% of the total path.\n\nBlue = Navigation\nLight Blue = Always On Lateral\nGreen = Default with 'FrogPilot Colors'\nLight Green = Default with stock colors\nOrange = Experimental Mode Active\nYellow = Conditional Overriden", ""}, + {"PathWidth", "Path Width", "Customize the width of the driving path shown on your UI.\n\nDefault matches the width of a 2019 Lexus ES 350.", ""}, + {"RoadEdgesWidth", "Road Edges", "Adjust the visual thickness of road edges on your display.\n\nDefault is 1/2 of the MUTCD average lane line width of 4 inches.", ""}, + {"UnlimitedLength", "'Unlimited' Road UI Length", "Extend the display of the path, lane lines, and road edges as far as the system can detect, providing a more expansive view of the road ahead.", ""}, + + {"QOLVisuals", "Quality of Life", "Miscellaneous quality of life changes to improve your overall openpilot experience.", "../frogpilot/assets/toggle_icons/quality_of_life.png"}, + {"DriveStats", "Drive Stats In Home Screen", "Display your device's drive stats in the home screen.", ""}, + {"HideSpeed", "Hide Speed", "Hide the speed indicator in the onroad UI.", ""}, + {"ShowSLCOffset", "Show Speed Limit Offset", "Show the speed limit offset seperated from the speed limit in the onroad UI when using 'Speed Limit Controller'.", ""}, + + {"RandomEvents", "Random Events", "Enjoy a bit of unpredictability with random events that can occur during certain driving conditions.", "../frogpilot/assets/toggle_icons/icon_random.png"}, + {"ScreenBrightness", "Screen Brightness", "Customize your screen brightness.", "../frogpilot/assets/toggle_icons/icon_light.png"}, + {"SilentMode", "Silent Mode", "Mute openpilot sounds for a quieter driving experience.", "../frogpilot/assets/toggle_icons/icon_mute.png"}, + {"WheelIcon", "Steering Wheel Icon", "Replace the default steering wheel icon with a custom design, adding a unique touch to your interface.", "../assets/offroad/icon_openpilot.png"}, + }; + + for (const auto &[param, title, desc, icon] : visualToggles) { + ParamControl *toggle; + + if (param == "CameraView") { + std::vector cameraOptions{tr("Auto"), tr("Standard"), tr("Wide"), tr("Driver")}; + FrogPilotButtonParamControl *preferredCamera = new FrogPilotButtonParamControl(param, title, desc, icon, cameraOptions); + toggle = preferredCamera; + + } else if (param == "CustomTheme") { + FrogPilotParamManageControl *customThemeToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(customThemeToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(customThemeKeys.find(key.c_str()) != customThemeKeys.end()); + } + }); + toggle = customThemeToggle; + } else if (param == "CustomColors" || param == "CustomIcons" || param == "CustomSignals" || param == "CustomSounds") { + std::vector themeOptions{tr("Stock"), tr("Frog"), tr("Tesla"), tr("Stalin")}; + FrogPilotButtonParamControl *themeSelection = new FrogPilotButtonParamControl(param, title, desc, icon, themeOptions); + toggle = themeSelection; + + if (param == "CustomSounds") { + QObject::connect(static_cast(toggle), &FrogPilotButtonParamControl::buttonClicked, [this](int id) { + if (id == 1) { + if (FrogPilotConfirmationDialog::yesorno("Do you want to enable the bonus 'Goat' sound effect?", this)) { + params.putBool("GoatScream", true); + } else { + params.putBool("GoatScream", false); + } + } + }); + } + + } else if (param == "CustomUI") { + FrogPilotParamManageControl *customUIToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(customUIToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end()); + } + }); + toggle = customUIToggle; + } else if (param == "LeadInfo") { + std::vector leadInfoToggles{tr("UseSI")}; + std::vector leadInfoToggleNames{tr("Use SI Values")}; + toggle = new FrogPilotParamToggleControl(param, title, desc, icon, leadInfoToggles, leadInfoToggleNames); + + } else if (param == "ModelUI") { + FrogPilotParamManageControl *modelUIToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(modelUIToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(modelUIKeys.find(key.c_str()) != modelUIKeys.end()); + } + }); + toggle = modelUIToggle; + } else if (param == "LaneLinesWidth" || param == "RoadEdgesWidth") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 24, std::map(), this, false, " inches"); + } else if (param == "PathEdgeWidth") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, std::map(), this, false, "%"); + } else if (param == "PathWidth") { + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 100, std::map(), this, false, " feet", 10); + + } else if (param == "QOLVisuals") { + FrogPilotParamManageControl *qolToggle = new FrogPilotParamManageControl(param, title, desc, icon, this); + QObject::connect(qolToggle, &FrogPilotParamManageControl::manageButtonClicked, this, [this]() { + parentToggleClicked(); + for (auto &[key, toggle] : toggles) { + toggle->setVisible(qolKeys.find(key.c_str()) != qolKeys.end()); + } + }); + toggle = qolToggle; + + } else if (param == "ScreenBrightness") { + std::map brightnessLabels; + for (int i = 0; i <= 101; ++i) { + brightnessLabels[i] = i == 0 ? "Screen Off" : i == 101 ? "Auto" : QString::number(i) + "%"; + } + toggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 101, brightnessLabels, this, false); + + } else if (param == "WheelIcon") { + std::vector wheelToggles{"RotatingWheel"}; + std::vector wheelToggleNames{tr("Rotating")}; + std::map steeringWheelLabels = {{0, "Stock"}, {1, "Lexus"}, {2, "Toyota"}, {3, "Frog"}, {4, "Rocket"}, {5, "Hyundai"}, {6, "Stalin"}}; + toggle = new FrogPilotParamValueToggleControl(param, title, desc, icon, 0, 6, steeringWheelLabels, this, true, "", 1, wheelToggles, wheelToggleNames); + + } else { + toggle = new ParamControl(param, title, desc, icon, this); + } + + addItem(toggle); + toggles[param.toStdString()] = toggle; + + QObject::connect(toggle, &ToggleControl::toggleFlipped, [this]() { + updateToggles(); + }); + + QObject::connect(static_cast(toggle), &FrogPilotParamValueControl::buttonPressed, [this]() { + updateToggles(); + }); + + QObject::connect(toggle, &AbstractControl::showDescriptionEvent, [this]() { + update(); + }); + + QObject::connect(static_cast(toggle), &FrogPilotParamManageControl::manageButtonClicked, [this]() { + update(); + }); + } + + std::set rebootKeys = {"DriveStats"}; + for (const std::string &key : rebootKeys) { + QObject::connect(toggles[key], &ToggleControl::toggleFlipped, [this]() { + if (FrogPilotConfirmationDialog::toggle("Reboot required to take effect.", "Reboot Now", this)) { + Hardware::reboot(); + } + }); + } + + customOnroadUIKeys = {"AdjacentPath", "BlindSpotPath", "ShowFPS", "LeadInfo", "RoadNameUI", "UseVienna"}; + customThemeKeys = {"CustomColors", "CustomIcons", "CustomSignals", "CustomSounds"}; + modelUIKeys = {"AccelerationPath", "LaneLinesWidth", "PathEdgeWidth", "PathWidth", "RoadEdgesWidth", "UnlimitedLength"}; + qolKeys = {"DriveStats", "HideSpeed", "ShowSLCOffset"}; + + QObject::connect(device(), &Device::interactiveTimeout, this, &FrogPilotVisualsPanel::hideSubToggles); + QObject::connect(parent, &SettingsWindow::closeParentToggle, this, &FrogPilotVisualsPanel::hideSubToggles); + QObject::connect(parent, &SettingsWindow::updateMetric, this, &FrogPilotVisualsPanel::updateMetric); + + hideSubToggles(); + updateMetric(); +} + +void FrogPilotVisualsPanel::updateToggles() { + std::thread([this]() { + paramsMemory.putBool("FrogPilotTogglesUpdated", true); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + paramsMemory.putBool("FrogPilotTogglesUpdated", false); + }).detach(); +} + +void FrogPilotVisualsPanel::updateMetric() { + bool previousIsMetric = isMetric; + isMetric = params.getBool("IsMetric"); + + if (isMetric != previousIsMetric) { + double distanceConversion = isMetric ? INCH_TO_CM : CM_TO_INCH; + double speedConversion = isMetric ? FOOT_TO_METER : METER_TO_FOOT; + params.putInt("LaneLinesWidth", std::nearbyint(params.getInt("LaneLinesWidth") * distanceConversion)); + params.putInt("RoadEdgesWidth", std::nearbyint(params.getInt("RoadEdgesWidth") * distanceConversion)); + params.putInt("PathWidth", std::nearbyint(params.getInt("PathWidth") * speedConversion)); + } + + FrogPilotParamValueControl *laneLinesWidthToggle = static_cast(toggles["LaneLinesWidth"]); + FrogPilotParamValueControl *roadEdgesWidthToggle = static_cast(toggles["RoadEdgesWidth"]); + FrogPilotParamValueControl *pathWidthToggle = static_cast(toggles["PathWidth"]); + + if (isMetric) { + laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the Vienna average of 10 centimeters."); + roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the Vienna average lane line width of 10 centimeters."); + + laneLinesWidthToggle->updateControl(0, 60, " centimeters"); + roadEdgesWidthToggle->updateControl(0, 60, " centimeters"); + pathWidthToggle->updateControl(0, 30, " meters"); + } else { + laneLinesWidthToggle->setDescription("Customize the lane line width.\n\nDefault matches the MUTCD average of 4 inches."); + roadEdgesWidthToggle->setDescription("Customize the road edges width.\n\nDefault is 1/2 of the MUTCD average lane line width of 4 inches."); + + laneLinesWidthToggle->updateControl(0, 24, " inches"); + roadEdgesWidthToggle->updateControl(0, 24, " inches"); + pathWidthToggle->updateControl(0, 100, " feet"); + } + + laneLinesWidthToggle->refresh(); + roadEdgesWidthToggle->refresh(); + + previousIsMetric = isMetric; +} + +void FrogPilotVisualsPanel::parentToggleClicked() { + this->openParentToggle(); +} + +void FrogPilotVisualsPanel::hideSubToggles() { + for (auto &[key, toggle] : toggles) { + bool subToggles = modelUIKeys.find(key.c_str()) != modelUIKeys.end() || + customOnroadUIKeys.find(key.c_str()) != customOnroadUIKeys.end() || + customThemeKeys.find(key.c_str()) != customThemeKeys.end() || + qolKeys.find(key.c_str()) != qolKeys.end(); + toggle->setVisible(!subToggles); + } + + this->closeParentToggle(); +} + +void FrogPilotVisualsPanel::hideEvent(QHideEvent *event) { + hideSubToggles(); +} diff --git a/selfdrive/clearpilot/ui/visual_settings.h b/selfdrive/clearpilot/ui/visual_settings.h new file mode 100644 index 0000000..f30cda7 --- /dev/null +++ b/selfdrive/clearpilot/ui/visual_settings.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/ui/qt/offroad/settings.h" + +class FrogPilotVisualsPanel : public FrogPilotListWidget { + Q_OBJECT + +public: + explicit FrogPilotVisualsPanel(SettingsWindow *parent); + +signals: + void closeParentToggle(); + void openParentToggle(); + +private: + void hideEvent(QHideEvent *event); + void hideSubToggles(); + void parentToggleClicked(); + void updateMetric(); + void updateToggles(); + + std::set customOnroadUIKeys; + std::set customThemeKeys; + std::set modelUIKeys; + std::set qolKeys; + + std::map toggles; + + Params params; + Params paramsMemory{"/dev/shm/params"}; + + bool isMetric = params.getBool("IsMetric"); +}; diff --git a/selfdrive/clearpilot/ui/visual_settings.h.org b/selfdrive/clearpilot/ui/visual_settings.h.org new file mode 100644 index 0000000..f30cda7 --- /dev/null +++ b/selfdrive/clearpilot/ui/visual_settings.h.org @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "selfdrive/frogpilot/ui/frogpilot_functions.h" +#include "selfdrive/ui/qt/offroad/settings.h" + +class FrogPilotVisualsPanel : public FrogPilotListWidget { + Q_OBJECT + +public: + explicit FrogPilotVisualsPanel(SettingsWindow *parent); + +signals: + void closeParentToggle(); + void openParentToggle(); + +private: + void hideEvent(QHideEvent *event); + void hideSubToggles(); + void parentToggleClicked(); + void updateMetric(); + void updateToggles(); + + std::set customOnroadUIKeys; + std::set customThemeKeys; + std::set modelUIKeys; + std::set qolKeys; + + std::map toggles; + + Params params; + Params paramsMemory{"/dev/shm/params"}; + + bool isMetric = params.getBool("IsMetric"); +}; diff --git a/selfdrive/clearpilot/weather.cc b/selfdrive/clearpilot/weather.cc new file mode 100644 index 0000000..e69de29 diff --git a/selfdrive/clearpilot/weather.h b/selfdrive/clearpilot/weather.h new file mode 100644 index 0000000..e69de29 diff --git a/system/clearpilot/configure/dependencies.sh b/system/clearpilot/configure/dependencies.sh new file mode 100644 index 0000000..91993e7 --- /dev/null +++ b/system/clearpilot/configure/dependencies.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Check if nodejs is installed +if ! which nodejs > /dev/null; then + #sudo mount -o remount,rw / + + # Node.js is not installed, setting up the NodeSource Node.js 21.x repo + echo "Node.js not found. Setting up NodeSource Node.js 21.x repository..." + curl -fsSL https://deb.nodesource.com/setup_21.x | sudo -E bash - + + # Install Node.js from the NodeSource repository + echo "Installing Node.js..." + sudo apt-get install -y nodejs +fi + +# apt-get update +# apt-get install -y nodejs npm + +apt-get update +apt-get install -y python3-pyqt5 +pip3 install termqt \ No newline at end of file diff --git a/system/clearpilot/notes_wayland.txt b/system/clearpilot/notes_wayland.txt new file mode 100644 index 0000000..4410112 --- /dev/null +++ b/system/clearpilot/notes_wayland.txt @@ -0,0 +1,47 @@ +From the information you've provided, particularly the configuration in the systemd service file for Weston and related directories, we can deduce several important environmental setup aspects for running applications using the Wayland display server (Weston) on your device. + +Key Takeaways +Weston Configuration and Runtime Directory: +Weston is run with specific configurations specified in /usr/comma/weston.ini. +The XDG_RUNTIME_DIR environment variable is set to /var/tmp/weston. This is crucial because Wayland clients locate the Wayland server (Weston in this case) through the WAYLAND_DISPLAY environment variable, which typically points to a socket file within XDG_RUNTIME_DIR. +Service Setup: +Pre-execution steps in the Weston service ensure that the runtime directory exists and has the correct permissions. This directory is used by Weston to store its runtime data, including the socket file (wayland-0), which clients use to communicate with Weston. +Execution Parameters: +Weston is started with the --config flag pointing to a custom configuration file and on a specific TTY. This setup is essential for correctly initializing the display server on your device. +Making Your PyQt Application Work +Given the above setup, you should ensure your PyQt application is configured to correctly interact with this environment. Here's what you need to do: + +Set the XDG_RUNTIME_DIR Environment Variable: This should match the configuration of the Weston service to ensure that your application can find the Wayland display server. +Direct PyQt to use the Wayland Platform: +Explicitly set the platform to Wayland in your PyQt application. +Ensure the WAYLAND_DISPLAY environment variable points to the correct socket file, usually wayland-0 inside your runtime directory. +Here’s how you can modify your Python script to accommodate these settings: + +python +Copy code +import os +import sys +from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QScrollBar +from PyQt5.QtCore import Qt + +# Set environment variables to match the Weston configuration +os.environ["XDG_RUNTIME_DIR"] = "/var/tmp/weston" +os.environ["WAYLAND_DISPLAY"] = "wayland-0" # Typically the socket is named wayland-0 +os.environ["QT_QPA_PLATFORM"] = "wayland" + +app = QApplication(sys.argv) +window = QWidget() +window.setWindowTitle("PyQt on Wayland") +layout = QHBoxLayout(window) +scroll = QScrollBar(Qt.Vertical) +layout.addWidget(scroll) +window.setLayout(layout) +window.show() + +sys.exit(app.exec_()) +Summary +By aligning your PyQt environment with the established Weston configuration: + +You replicate the environmental setup that native applications use, ensuring compatibility. +You directly address the issue of the PyQt application failing to find or connect to the Weston display server, which is indicated by errors related to the xcb platform plugin. +This setup should resolve the issues you've been facing with launching your PyQt application on the device. Ensure that Weston is actively running when you attempt to start your application, as it must be running to accept connections from Wayland clients. \ No newline at end of file diff --git a/system/clearpilot/on_boot.sh b/system/clearpilot/on_boot.sh new file mode 100644 index 0000000..e69de29 diff --git a/system/clearpilot/on_start.sh b/system/clearpilot/on_start.sh new file mode 100644 index 0000000..e69de29 diff --git a/system/clearpilot/provision_shell.sh b/system/clearpilot/provision_shell.sh new file mode 100644 index 0000000..5f21a86 --- /dev/null +++ b/system/clearpilot/provision_shell.sh @@ -0,0 +1,4 @@ +apt-get update +apt-get install -y nodejs npm + +pip install pyqt5 diff --git a/system/clearpilot/shell/authorized_keys b/system/clearpilot/shell/authorized_keys new file mode 100644 index 0000000..4d49e5f --- /dev/null +++ b/system/clearpilot/shell/authorized_keys @@ -0,0 +1,3 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQtHTzkeRlOXDWyK/IvO2RgjSdoq6V81u3YtcyIxBZVX2zCj1xzE9zWcUcVxloe63rB/DBasChODIRBtp1vGnWb/EkLWAuOqS2V5rzhlcSfM103++TI81e04A7HDspWSNUXRh5OD/mUvwtYIH7S4QAkBiCro5lAgSToXNAOR4b4cXgNQecf+RhPc0Nm3K8Is1wEeQajmlC1E22YWBDDV+uoB3Uagl90e58Psbp8PunCdbeY9EfqQsymyloiTeqzKwHnmHnMXSlZluh7A+ifoKgohDsarT1FixAgxT0LSIxxINORhE4P6em/7y3xpgubPhNpbuQSzDlb3op3fwMoFcAEEYKWg+d9OGOrdiWa13aV0g7UNdW/XmmF/BAaBdSOZeomVNnxmftmmJWfu3jtFdwTDRQpZn7nDYC+aZ1R3Q0Xd4lLuqkA/9smUXLZuiBDJXwM5nDyWQR9tESIwlTLcdKAUpj0gQqpcozVehksNksTekZBAg/mYb6DKyYCTY0ti0= +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCm/Vq50kqf94allqGq9luBGjDh2Do/rOCA719CRlDOErCvdY+ZaYNumQZ5AbFfU5KcPZwirJLBvhEoH/G0lEAg9TUaUgH/VvqBBztlpcmA1eplZHzEFLnTDn0oO4Tk46bXwjL0anOZfNaUGhbaO4Th7m+9+o16WUduEabPiyVbnqD6P44CANsvBJNKlyUDBzsdkE9z5gULp06i1+JqqXiGV81HoFWZe5YCFv4j4QUPvfmFhcBHViVrOFs87hS4Eu0gWNxQmQBhh6R1ZbjaBlGdE5GyDZQZwlofjfuO06e0HvCDuIAELSYqlGFCmUhlM/LZ6YkF79/HFrg5sS3gsuY5 +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHbrOZrByUb2Ci21DdJkhWv/4Bz4oghL9joraQYFq4Om diff --git a/system/clearpilot/shell/bg.jpg b/system/clearpilot/shell/bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..19ac03752e724b0a7b5d1c206886bb643d911c46 GIT binary patch literal 45240 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 literal 0 HcmV?d00001 diff --git a/system/clearpilot/shell/configure_ssh.sh b/system/clearpilot/shell/configure_ssh.sh new file mode 100644 index 0000000..baf3dd5 --- /dev/null +++ b/system/clearpilot/shell/configure_ssh.sh @@ -0,0 +1,5 @@ +cat /data/openpilot/shell/authorized_keys >/data/params/d/GithubSshKeys +chown comma:comma /data/params/d/GithubSshKeys +chmod 600 /data/params/d/GithubSshKeys +# systemctl restart ssh + diff --git a/system/clearpilot/shell/dependencies.sh b/system/clearpilot/shell/dependencies.sh new file mode 100644 index 0000000..caa0a7d --- /dev/null +++ b/system/clearpilot/shell/dependencies.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# Check if nodejs is installed +if ! which nodejs > /dev/null; then + #sudo mount -o remount,rw / + + # Node.js is not installed, setting up the NodeSource Node.js 21.x repo + echo "Node.js not found. Setting up NodeSource Node.js 21.x repository..." + curl -fsSL https://deb.nodesource.com/setup_21.x | sudo -E bash - + + # Install Node.js from the NodeSource repository + echo "Installing Node.js..." + sudo apt-get install -y nodejs +fi diff --git a/system/clearpilot/shell/init_shell.sh b/system/clearpilot/shell/init_shell.sh new file mode 100644 index 0000000..9a8f0a6 --- /dev/null +++ b/system/clearpilot/shell/init_shell.sh @@ -0,0 +1,16 @@ +sudo chown -R comma:comma /data/openpilot & + +cd /data/openpilot/shell/ + +sudo bash ./configure_ssh.sh +sudo bash ./set_logo.sh + +cd /data/openpilot/logs + +rm -f watcher.log.gz +ls watcher.log && gzip watcher.log + +chmod +x /data/openpilot/shell/watcher_run_loop.sh +sudo pkill -f "/bin/sh /data/openpilot/shell/watcher_run_loop.sh" +sudo rm -rf /run/screen/S-comma +screen -dmS "watcher" /data/openpilot/shell/watcher_run_loop.sh diff --git a/system/clearpilot/shell/node_modules/.package-lock.json b/system/clearpilot/shell/node_modules/.package-lock.json new file mode 100644 index 0000000..08f5b97 --- /dev/null +++ b/system/clearpilot/shell/node_modules/.package-lock.json @@ -0,0 +1,32 @@ +{ + "name": "shell", + "lockfileVersion": 3, + "requires": true, + "packages": { + "node_modules/http": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/http/-/http-0.0.1-security.tgz", + "integrity": "sha512-RnDvP10Ty9FxqOtPZuxtebw1j4L/WiqNMDtuc1YMH1XQm5TgDRaR1G9u8upL6KD1bXHSp9eSXo/ED+8Q7FAr+g==" + }, + "node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/system/clearpilot/shell/node_modules/http/README.md b/system/clearpilot/shell/node_modules/http/README.md new file mode 100644 index 0000000..5e9a74c --- /dev/null +++ b/system/clearpilot/shell/node_modules/http/README.md @@ -0,0 +1,9 @@ +# Security holding package + +This package name is not currently in use, but was formerly occupied +by another package. To avoid malicious use, npm is hanging on to the +package name, but loosely, and we'll probably give it to you if you +want it. + +You may adopt this package by contacting support@npmjs.com and +requesting the name. diff --git a/system/clearpilot/shell/node_modules/http/package.json b/system/clearpilot/shell/node_modules/http/package.json new file mode 100644 index 0000000..4196f28 --- /dev/null +++ b/system/clearpilot/shell/node_modules/http/package.json @@ -0,0 +1,6 @@ +{ + "name": "http", + "version": "0.0.1-security", + "description": "security holding package", + "repository": "npm/security-holder" +} diff --git a/system/clearpilot/shell/node_modules/ws/LICENSE b/system/clearpilot/shell/node_modules/ws/LICENSE new file mode 100644 index 0000000..1da5b96 --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2011 Einar Otto Stangvik +Copyright (c) 2013 Arnout Kazemier and contributors +Copyright (c) 2016 Luigi Pinca and contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/system/clearpilot/shell/node_modules/ws/README.md b/system/clearpilot/shell/node_modules/ws/README.md new file mode 100644 index 0000000..80d9886 --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/README.md @@ -0,0 +1,549 @@ +# ws: a Node.js WebSocket library + +[![Version npm](https://img.shields.io/npm/v/ws.svg?logo=npm)](https://www.npmjs.com/package/ws) +[![CI](https://img.shields.io/github/actions/workflow/status/websockets/ws/ci.yml?branch=master&label=CI&logo=github)](https://github.com/websockets/ws/actions?query=workflow%3ACI+branch%3Amaster) +[![Coverage Status](https://img.shields.io/coveralls/websockets/ws/master.svg?logo=coveralls)](https://coveralls.io/github/websockets/ws) + +ws is a simple to use, blazing fast, and thoroughly tested WebSocket client and +server implementation. + +Passes the quite extensive Autobahn test suite: [server][server-report], +[client][client-report]. + +**Note**: This module does not work in the browser. The client in the docs is a +reference to a back end with the role of a client in the WebSocket +communication. Browser clients must use the native +[`WebSocket`](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) +object. To make the same code work seamlessly on Node.js and the browser, you +can use one of the many wrappers available on npm, like +[isomorphic-ws](https://github.com/heineiuo/isomorphic-ws). + +## Table of Contents + +- [Protocol support](#protocol-support) +- [Installing](#installing) + - [Opt-in for performance](#opt-in-for-performance) + - [Legacy opt-in for performance](#legacy-opt-in-for-performance) +- [API docs](#api-docs) +- [WebSocket compression](#websocket-compression) +- [Usage examples](#usage-examples) + - [Sending and receiving text data](#sending-and-receiving-text-data) + - [Sending binary data](#sending-binary-data) + - [Simple server](#simple-server) + - [External HTTP/S server](#external-https-server) + - [Multiple servers sharing a single HTTP/S server](#multiple-servers-sharing-a-single-https-server) + - [Client authentication](#client-authentication) + - [Server broadcast](#server-broadcast) + - [Round-trip time](#round-trip-time) + - [Use the Node.js streams API](#use-the-nodejs-streams-api) + - [Other examples](#other-examples) +- [FAQ](#faq) + - [How to get the IP address of the client?](#how-to-get-the-ip-address-of-the-client) + - [How to detect and close broken connections?](#how-to-detect-and-close-broken-connections) + - [How to connect via a proxy?](#how-to-connect-via-a-proxy) +- [Changelog](#changelog) +- [License](#license) + +## Protocol support + +- **HyBi drafts 07-12** (Use the option `protocolVersion: 8`) +- **HyBi drafts 13-17** (Current default, alternatively option + `protocolVersion: 13`) + +## Installing + +``` +npm install ws +``` + +### Opt-in for performance + +[bufferutil][] is an optional module that can be installed alongside the ws +module: + +``` +npm install --save-optional bufferutil +``` + +This is a binary addon that improves the performance of certain operations such +as masking and unmasking the data payload of the WebSocket frames. Prebuilt +binaries are available for the most popular platforms, so you don't necessarily +need to have a C++ compiler installed on your machine. + +To force ws to not use bufferutil, use the +[`WS_NO_BUFFER_UTIL`](./doc/ws.md#ws_no_buffer_util) environment variable. This +can be useful to enhance security in systems where a user can put a package in +the package search path of an application of another user, due to how the +Node.js resolver algorithm works. + +#### Legacy opt-in for performance + +If you are running on an old version of Node.js (prior to v18.14.0), ws also +supports the [utf-8-validate][] module: + +``` +npm install --save-optional utf-8-validate +``` + +This contains a binary polyfill for [`buffer.isUtf8()`][]. + +To force ws to not use utf-8-validate, use the +[`WS_NO_UTF_8_VALIDATE`](./doc/ws.md#ws_no_utf_8_validate) environment variable. + +## API docs + +See [`/doc/ws.md`](./doc/ws.md) for Node.js-like documentation of ws classes and +utility functions. + +## WebSocket compression + +ws supports the [permessage-deflate extension][permessage-deflate] which enables +the client and server to negotiate a compression algorithm and its parameters, +and then selectively apply it to the data payloads of each WebSocket message. + +The extension is disabled by default on the server and enabled by default on the +client. It adds a significant overhead in terms of performance and memory +consumption so we suggest to enable it only if it is really needed. + +Note that Node.js has a variety of issues with high-performance compression, +where increased concurrency, especially on Linux, can lead to [catastrophic +memory fragmentation][node-zlib-bug] and slow performance. If you intend to use +permessage-deflate in production, it is worthwhile to set up a test +representative of your workload and ensure Node.js/zlib will handle it with +acceptable performance and memory usage. + +Tuning of permessage-deflate can be done via the options defined below. You can +also use `zlibDeflateOptions` and `zlibInflateOptions`, which is passed directly +into the creation of [raw deflate/inflate streams][node-zlib-deflaterawdocs]. + +See [the docs][ws-server-options] for more options. + +```js +import WebSocket, { WebSocketServer } from 'ws'; + +const wss = new WebSocketServer({ + port: 8080, + perMessageDeflate: { + zlibDeflateOptions: { + // See zlib defaults. + chunkSize: 1024, + memLevel: 7, + level: 3 + }, + zlibInflateOptions: { + chunkSize: 10 * 1024 + }, + // Other options settable: + clientNoContextTakeover: true, // Defaults to negotiated value. + serverNoContextTakeover: true, // Defaults to negotiated value. + serverMaxWindowBits: 10, // Defaults to negotiated value. + // Below options specified as default values. + concurrencyLimit: 10, // Limits zlib concurrency for perf. + threshold: 1024 // Size (in bytes) below which messages + // should not be compressed if context takeover is disabled. + } +}); +``` + +The client will only use the extension if it is supported and enabled on the +server. To always disable the extension on the client set the +`perMessageDeflate` option to `false`. + +```js +import WebSocket from 'ws'; + +const ws = new WebSocket('ws://www.host.com/path', { + perMessageDeflate: false +}); +``` + +## Usage examples + +### Sending and receiving text data + +```js +import WebSocket from 'ws'; + +const ws = new WebSocket('ws://www.host.com/path'); + +ws.on('error', console.error); + +ws.on('open', function open() { + ws.send('something'); +}); + +ws.on('message', function message(data) { + console.log('received: %s', data); +}); +``` + +### Sending binary data + +```js +import WebSocket from 'ws'; + +const ws = new WebSocket('ws://www.host.com/path'); + +ws.on('error', console.error); + +ws.on('open', function open() { + const array = new Float32Array(5); + + for (var i = 0; i < array.length; ++i) { + array[i] = i / 2; + } + + ws.send(array); +}); +``` + +### Simple server + +```js +import { WebSocketServer } from 'ws'; + +const wss = new WebSocketServer({ port: 8080 }); + +wss.on('connection', function connection(ws) { + ws.on('error', console.error); + + ws.on('message', function message(data) { + console.log('received: %s', data); + }); + + ws.send('something'); +}); +``` + +### External HTTP/S server + +```js +import { createServer } from 'https'; +import { readFileSync } from 'fs'; +import { WebSocketServer } from 'ws'; + +const server = createServer({ + cert: readFileSync('/path/to/cert.pem'), + key: readFileSync('/path/to/key.pem') +}); +const wss = new WebSocketServer({ server }); + +wss.on('connection', function connection(ws) { + ws.on('error', console.error); + + ws.on('message', function message(data) { + console.log('received: %s', data); + }); + + ws.send('something'); +}); + +server.listen(8080); +``` + +### Multiple servers sharing a single HTTP/S server + +```js +import { createServer } from 'http'; +import { parse } from 'url'; +import { WebSocketServer } from 'ws'; + +const server = createServer(); +const wss1 = new WebSocketServer({ noServer: true }); +const wss2 = new WebSocketServer({ noServer: true }); + +wss1.on('connection', function connection(ws) { + ws.on('error', console.error); + + // ... +}); + +wss2.on('connection', function connection(ws) { + ws.on('error', console.error); + + // ... +}); + +server.on('upgrade', function upgrade(request, socket, head) { + const { pathname } = parse(request.url); + + if (pathname === '/foo') { + wss1.handleUpgrade(request, socket, head, function done(ws) { + wss1.emit('connection', ws, request); + }); + } else if (pathname === '/bar') { + wss2.handleUpgrade(request, socket, head, function done(ws) { + wss2.emit('connection', ws, request); + }); + } else { + socket.destroy(); + } +}); + +server.listen(8080); +``` + +### Client authentication + +```js +import { createServer } from 'http'; +import { WebSocketServer } from 'ws'; + +function onSocketError(err) { + console.error(err); +} + +const server = createServer(); +const wss = new WebSocketServer({ noServer: true }); + +wss.on('connection', function connection(ws, request, client) { + ws.on('error', console.error); + + ws.on('message', function message(data) { + console.log(`Received message ${data} from user ${client}`); + }); +}); + +server.on('upgrade', function upgrade(request, socket, head) { + socket.on('error', onSocketError); + + // This function is not defined on purpose. Implement it with your own logic. + authenticate(request, function next(err, client) { + if (err || !client) { + socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n'); + socket.destroy(); + return; + } + + socket.removeListener('error', onSocketError); + + wss.handleUpgrade(request, socket, head, function done(ws) { + wss.emit('connection', ws, request, client); + }); + }); +}); + +server.listen(8080); +``` + +Also see the provided [example][session-parse-example] using `express-session`. + +### Server broadcast + +A client WebSocket broadcasting to all connected WebSocket clients, including +itself. + +```js +import WebSocket, { WebSocketServer } from 'ws'; + +const wss = new WebSocketServer({ port: 8080 }); + +wss.on('connection', function connection(ws) { + ws.on('error', console.error); + + ws.on('message', function message(data, isBinary) { + wss.clients.forEach(function each(client) { + if (client.readyState === WebSocket.OPEN) { + client.send(data, { binary: isBinary }); + } + }); + }); +}); +``` + +A client WebSocket broadcasting to every other connected WebSocket clients, +excluding itself. + +```js +import WebSocket, { WebSocketServer } from 'ws'; + +const wss = new WebSocketServer({ port: 8080 }); + +wss.on('connection', function connection(ws) { + ws.on('error', console.error); + + ws.on('message', function message(data, isBinary) { + wss.clients.forEach(function each(client) { + if (client !== ws && client.readyState === WebSocket.OPEN) { + client.send(data, { binary: isBinary }); + } + }); + }); +}); +``` + +### Round-trip time + +```js +import WebSocket from 'ws'; + +const ws = new WebSocket('wss://websocket-echo.com/'); + +ws.on('error', console.error); + +ws.on('open', function open() { + console.log('connected'); + ws.send(Date.now()); +}); + +ws.on('close', function close() { + console.log('disconnected'); +}); + +ws.on('message', function message(data) { + console.log(`Round-trip time: ${Date.now() - data} ms`); + + setTimeout(function timeout() { + ws.send(Date.now()); + }, 500); +}); +``` + +### Use the Node.js streams API + +```js +import WebSocket, { createWebSocketStream } from 'ws'; + +const ws = new WebSocket('wss://websocket-echo.com/'); + +const duplex = createWebSocketStream(ws, { encoding: 'utf8' }); + +duplex.on('error', console.error); + +duplex.pipe(process.stdout); +process.stdin.pipe(duplex); +``` + +### Other examples + +For a full example with a browser client communicating with a ws server, see the +examples folder. + +Otherwise, see the test cases. + +## FAQ + +### How to get the IP address of the client? + +The remote IP address can be obtained from the raw socket. + +```js +import { WebSocketServer } from 'ws'; + +const wss = new WebSocketServer({ port: 8080 }); + +wss.on('connection', function connection(ws, req) { + const ip = req.socket.remoteAddress; + + ws.on('error', console.error); +}); +``` + +When the server runs behind a proxy like NGINX, the de-facto standard is to use +the `X-Forwarded-For` header. + +```js +wss.on('connection', function connection(ws, req) { + const ip = req.headers['x-forwarded-for'].split(',')[0].trim(); + + ws.on('error', console.error); +}); +``` + +### How to detect and close broken connections? + +Sometimes the link between the server and the client can be interrupted in a way +that keeps both the server and the client unaware of the broken state of the +connection (e.g. when pulling the cord). + +In these cases ping messages can be used as a means to verify that the remote +endpoint is still responsive. + +```js +import { WebSocketServer } from 'ws'; + +function heartbeat() { + this.isAlive = true; +} + +const wss = new WebSocketServer({ port: 8080 }); + +wss.on('connection', function connection(ws) { + ws.isAlive = true; + ws.on('error', console.error); + ws.on('pong', heartbeat); +}); + +const interval = setInterval(function ping() { + wss.clients.forEach(function each(ws) { + if (ws.isAlive === false) return ws.terminate(); + + ws.isAlive = false; + ws.ping(); + }); +}, 30000); + +wss.on('close', function close() { + clearInterval(interval); +}); +``` + +Pong messages are automatically sent in response to ping messages as required by +the spec. + +Just like the server example above your clients might as well lose connection +without knowing it. You might want to add a ping listener on your clients to +prevent that. A simple implementation would be: + +```js +import WebSocket from 'ws'; + +function heartbeat() { + clearTimeout(this.pingTimeout); + + // Use `WebSocket#terminate()`, which immediately destroys the connection, + // instead of `WebSocket#close()`, which waits for the close timer. + // Delay should be equal to the interval at which your server + // sends out pings plus a conservative assumption of the latency. + this.pingTimeout = setTimeout(() => { + this.terminate(); + }, 30000 + 1000); +} + +const client = new WebSocket('wss://websocket-echo.com/'); + +client.on('error', console.error); +client.on('open', heartbeat); +client.on('ping', heartbeat); +client.on('close', function clear() { + clearTimeout(this.pingTimeout); +}); +``` + +### How to connect via a proxy? + +Use a custom `http.Agent` implementation like [https-proxy-agent][] or +[socks-proxy-agent][]. + +## Changelog + +We're using the GitHub [releases][changelog] for changelog entries. + +## License + +[MIT](LICENSE) + +[`buffer.isutf8()`]: https://nodejs.org/api/buffer.html#bufferisutf8input +[bufferutil]: https://github.com/websockets/bufferutil +[changelog]: https://github.com/websockets/ws/releases +[client-report]: http://websockets.github.io/ws/autobahn/clients/ +[https-proxy-agent]: https://github.com/TooTallNate/node-https-proxy-agent +[node-zlib-bug]: https://github.com/nodejs/node/issues/8871 +[node-zlib-deflaterawdocs]: + https://nodejs.org/api/zlib.html#zlib_zlib_createdeflateraw_options +[permessage-deflate]: https://tools.ietf.org/html/rfc7692 +[server-report]: http://websockets.github.io/ws/autobahn/servers/ +[session-parse-example]: ./examples/express-session-parse +[socks-proxy-agent]: https://github.com/TooTallNate/node-socks-proxy-agent +[utf-8-validate]: https://github.com/websockets/utf-8-validate +[ws-server-options]: ./doc/ws.md#new-websocketserveroptions-callback diff --git a/system/clearpilot/shell/node_modules/ws/browser.js b/system/clearpilot/shell/node_modules/ws/browser.js new file mode 100644 index 0000000..ca4f628 --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/browser.js @@ -0,0 +1,8 @@ +'use strict'; + +module.exports = function () { + throw new Error( + 'ws does not work in the browser. Browser clients must use the native ' + + 'WebSocket object' + ); +}; diff --git a/system/clearpilot/shell/node_modules/ws/index.js b/system/clearpilot/shell/node_modules/ws/index.js new file mode 100644 index 0000000..41edb3b --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/index.js @@ -0,0 +1,13 @@ +'use strict'; + +const WebSocket = require('./lib/websocket'); + +WebSocket.createWebSocketStream = require('./lib/stream'); +WebSocket.Server = require('./lib/websocket-server'); +WebSocket.Receiver = require('./lib/receiver'); +WebSocket.Sender = require('./lib/sender'); + +WebSocket.WebSocket = WebSocket; +WebSocket.WebSocketServer = WebSocket.Server; + +module.exports = WebSocket; diff --git a/system/clearpilot/shell/node_modules/ws/lib/buffer-util.js b/system/clearpilot/shell/node_modules/ws/lib/buffer-util.js new file mode 100644 index 0000000..f7536e2 --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/lib/buffer-util.js @@ -0,0 +1,131 @@ +'use strict'; + +const { EMPTY_BUFFER } = require('./constants'); + +const FastBuffer = Buffer[Symbol.species]; + +/** + * Merges an array of buffers into a new buffer. + * + * @param {Buffer[]} list The array of buffers to concat + * @param {Number} totalLength The total length of buffers in the list + * @return {Buffer} The resulting buffer + * @public + */ +function concat(list, totalLength) { + if (list.length === 0) return EMPTY_BUFFER; + if (list.length === 1) return list[0]; + + const target = Buffer.allocUnsafe(totalLength); + let offset = 0; + + for (let i = 0; i < list.length; i++) { + const buf = list[i]; + target.set(buf, offset); + offset += buf.length; + } + + if (offset < totalLength) { + return new FastBuffer(target.buffer, target.byteOffset, offset); + } + + return target; +} + +/** + * Masks a buffer using the given mask. + * + * @param {Buffer} source The buffer to mask + * @param {Buffer} mask The mask to use + * @param {Buffer} output The buffer where to store the result + * @param {Number} offset The offset at which to start writing + * @param {Number} length The number of bytes to mask. + * @public + */ +function _mask(source, mask, output, offset, length) { + for (let i = 0; i < length; i++) { + output[offset + i] = source[i] ^ mask[i & 3]; + } +} + +/** + * Unmasks a buffer using the given mask. + * + * @param {Buffer} buffer The buffer to unmask + * @param {Buffer} mask The mask to use + * @public + */ +function _unmask(buffer, mask) { + for (let i = 0; i < buffer.length; i++) { + buffer[i] ^= mask[i & 3]; + } +} + +/** + * Converts a buffer to an `ArrayBuffer`. + * + * @param {Buffer} buf The buffer to convert + * @return {ArrayBuffer} Converted buffer + * @public + */ +function toArrayBuffer(buf) { + if (buf.length === buf.buffer.byteLength) { + return buf.buffer; + } + + return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.length); +} + +/** + * Converts `data` to a `Buffer`. + * + * @param {*} data The data to convert + * @return {Buffer} The buffer + * @throws {TypeError} + * @public + */ +function toBuffer(data) { + toBuffer.readOnly = true; + + if (Buffer.isBuffer(data)) return data; + + let buf; + + if (data instanceof ArrayBuffer) { + buf = new FastBuffer(data); + } else if (ArrayBuffer.isView(data)) { + buf = new FastBuffer(data.buffer, data.byteOffset, data.byteLength); + } else { + buf = Buffer.from(data); + toBuffer.readOnly = false; + } + + return buf; +} + +module.exports = { + concat, + mask: _mask, + toArrayBuffer, + toBuffer, + unmask: _unmask +}; + +/* istanbul ignore else */ +if (!process.env.WS_NO_BUFFER_UTIL) { + try { + const bufferUtil = require('bufferutil'); + + module.exports.mask = function (source, mask, output, offset, length) { + if (length < 48) _mask(source, mask, output, offset, length); + else bufferUtil.mask(source, mask, output, offset, length); + }; + + module.exports.unmask = function (buffer, mask) { + if (buffer.length < 32) _unmask(buffer, mask); + else bufferUtil.unmask(buffer, mask); + }; + } catch (e) { + // Continue regardless of the error. + } +} diff --git a/system/clearpilot/shell/node_modules/ws/lib/constants.js b/system/clearpilot/shell/node_modules/ws/lib/constants.js new file mode 100644 index 0000000..d691b30 --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/lib/constants.js @@ -0,0 +1,12 @@ +'use strict'; + +module.exports = { + BINARY_TYPES: ['nodebuffer', 'arraybuffer', 'fragments'], + EMPTY_BUFFER: Buffer.alloc(0), + GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', + kForOnEventAttribute: Symbol('kIsForOnEventAttribute'), + kListener: Symbol('kListener'), + kStatusCode: Symbol('status-code'), + kWebSocket: Symbol('websocket'), + NOOP: () => {} +}; diff --git a/system/clearpilot/shell/node_modules/ws/lib/event-target.js b/system/clearpilot/shell/node_modules/ws/lib/event-target.js new file mode 100644 index 0000000..fea4cbc --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/lib/event-target.js @@ -0,0 +1,292 @@ +'use strict'; + +const { kForOnEventAttribute, kListener } = require('./constants'); + +const kCode = Symbol('kCode'); +const kData = Symbol('kData'); +const kError = Symbol('kError'); +const kMessage = Symbol('kMessage'); +const kReason = Symbol('kReason'); +const kTarget = Symbol('kTarget'); +const kType = Symbol('kType'); +const kWasClean = Symbol('kWasClean'); + +/** + * Class representing an event. + */ +class Event { + /** + * Create a new `Event`. + * + * @param {String} type The name of the event + * @throws {TypeError} If the `type` argument is not specified + */ + constructor(type) { + this[kTarget] = null; + this[kType] = type; + } + + /** + * @type {*} + */ + get target() { + return this[kTarget]; + } + + /** + * @type {String} + */ + get type() { + return this[kType]; + } +} + +Object.defineProperty(Event.prototype, 'target', { enumerable: true }); +Object.defineProperty(Event.prototype, 'type', { enumerable: true }); + +/** + * Class representing a close event. + * + * @extends Event + */ +class CloseEvent extends Event { + /** + * Create a new `CloseEvent`. + * + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {Number} [options.code=0] The status code explaining why the + * connection was closed + * @param {String} [options.reason=''] A human-readable string explaining why + * the connection was closed + * @param {Boolean} [options.wasClean=false] Indicates whether or not the + * connection was cleanly closed + */ + constructor(type, options = {}) { + super(type); + + this[kCode] = options.code === undefined ? 0 : options.code; + this[kReason] = options.reason === undefined ? '' : options.reason; + this[kWasClean] = options.wasClean === undefined ? false : options.wasClean; + } + + /** + * @type {Number} + */ + get code() { + return this[kCode]; + } + + /** + * @type {String} + */ + get reason() { + return this[kReason]; + } + + /** + * @type {Boolean} + */ + get wasClean() { + return this[kWasClean]; + } +} + +Object.defineProperty(CloseEvent.prototype, 'code', { enumerable: true }); +Object.defineProperty(CloseEvent.prototype, 'reason', { enumerable: true }); +Object.defineProperty(CloseEvent.prototype, 'wasClean', { enumerable: true }); + +/** + * Class representing an error event. + * + * @extends Event + */ +class ErrorEvent extends Event { + /** + * Create a new `ErrorEvent`. + * + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {*} [options.error=null] The error that generated this event + * @param {String} [options.message=''] The error message + */ + constructor(type, options = {}) { + super(type); + + this[kError] = options.error === undefined ? null : options.error; + this[kMessage] = options.message === undefined ? '' : options.message; + } + + /** + * @type {*} + */ + get error() { + return this[kError]; + } + + /** + * @type {String} + */ + get message() { + return this[kMessage]; + } +} + +Object.defineProperty(ErrorEvent.prototype, 'error', { enumerable: true }); +Object.defineProperty(ErrorEvent.prototype, 'message', { enumerable: true }); + +/** + * Class representing a message event. + * + * @extends Event + */ +class MessageEvent extends Event { + /** + * Create a new `MessageEvent`. + * + * @param {String} type The name of the event + * @param {Object} [options] A dictionary object that allows for setting + * attributes via object members of the same name + * @param {*} [options.data=null] The message content + */ + constructor(type, options = {}) { + super(type); + + this[kData] = options.data === undefined ? null : options.data; + } + + /** + * @type {*} + */ + get data() { + return this[kData]; + } +} + +Object.defineProperty(MessageEvent.prototype, 'data', { enumerable: true }); + +/** + * This provides methods for emulating the `EventTarget` interface. It's not + * meant to be used directly. + * + * @mixin + */ +const EventTarget = { + /** + * Register an event listener. + * + * @param {String} type A string representing the event type to listen for + * @param {(Function|Object)} handler The listener to add + * @param {Object} [options] An options object specifies characteristics about + * the event listener + * @param {Boolean} [options.once=false] A `Boolean` indicating that the + * listener should be invoked at most once after being added. If `true`, + * the listener would be automatically removed when invoked. + * @public + */ + addEventListener(type, handler, options = {}) { + for (const listener of this.listeners(type)) { + if ( + !options[kForOnEventAttribute] && + listener[kListener] === handler && + !listener[kForOnEventAttribute] + ) { + return; + } + } + + let wrapper; + + if (type === 'message') { + wrapper = function onMessage(data, isBinary) { + const event = new MessageEvent('message', { + data: isBinary ? data : data.toString() + }); + + event[kTarget] = this; + callListener(handler, this, event); + }; + } else if (type === 'close') { + wrapper = function onClose(code, message) { + const event = new CloseEvent('close', { + code, + reason: message.toString(), + wasClean: this._closeFrameReceived && this._closeFrameSent + }); + + event[kTarget] = this; + callListener(handler, this, event); + }; + } else if (type === 'error') { + wrapper = function onError(error) { + const event = new ErrorEvent('error', { + error, + message: error.message + }); + + event[kTarget] = this; + callListener(handler, this, event); + }; + } else if (type === 'open') { + wrapper = function onOpen() { + const event = new Event('open'); + + event[kTarget] = this; + callListener(handler, this, event); + }; + } else { + return; + } + + wrapper[kForOnEventAttribute] = !!options[kForOnEventAttribute]; + wrapper[kListener] = handler; + + if (options.once) { + this.once(type, wrapper); + } else { + this.on(type, wrapper); + } + }, + + /** + * Remove an event listener. + * + * @param {String} type A string representing the event type to remove + * @param {(Function|Object)} handler The listener to remove + * @public + */ + removeEventListener(type, handler) { + for (const listener of this.listeners(type)) { + if (listener[kListener] === handler && !listener[kForOnEventAttribute]) { + this.removeListener(type, listener); + break; + } + } + } +}; + +module.exports = { + CloseEvent, + ErrorEvent, + Event, + EventTarget, + MessageEvent +}; + +/** + * Call an event listener + * + * @param {(Function|Object)} listener The listener to call + * @param {*} thisArg The value to use as `this`` when calling the listener + * @param {Event} event The event to pass to the listener + * @private + */ +function callListener(listener, thisArg, event) { + if (typeof listener === 'object' && listener.handleEvent) { + listener.handleEvent.call(listener, event); + } else { + listener.call(thisArg, event); + } +} diff --git a/system/clearpilot/shell/node_modules/ws/lib/extension.js b/system/clearpilot/shell/node_modules/ws/lib/extension.js new file mode 100644 index 0000000..3d7895c --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/lib/extension.js @@ -0,0 +1,203 @@ +'use strict'; + +const { tokenChars } = require('./validation'); + +/** + * Adds an offer to the map of extension offers or a parameter to the map of + * parameters. + * + * @param {Object} dest The map of extension offers or parameters + * @param {String} name The extension or parameter name + * @param {(Object|Boolean|String)} elem The extension parameters or the + * parameter value + * @private + */ +function push(dest, name, elem) { + if (dest[name] === undefined) dest[name] = [elem]; + else dest[name].push(elem); +} + +/** + * Parses the `Sec-WebSocket-Extensions` header into an object. + * + * @param {String} header The field value of the header + * @return {Object} The parsed object + * @public + */ +function parse(header) { + const offers = Object.create(null); + let params = Object.create(null); + let mustUnescape = false; + let isEscaping = false; + let inQuotes = false; + let extensionName; + let paramName; + let start = -1; + let code = -1; + let end = -1; + let i = 0; + + for (; i < header.length; i++) { + code = header.charCodeAt(i); + + if (extensionName === undefined) { + if (end === -1 && tokenChars[code] === 1) { + if (start === -1) start = i; + } else if ( + i !== 0 && + (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */ + ) { + if (end === -1 && start !== -1) end = i; + } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + + if (end === -1) end = i; + const name = header.slice(start, end); + if (code === 0x2c) { + push(offers, name, params); + params = Object.create(null); + } else { + extensionName = name; + } + + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } else if (paramName === undefined) { + if (end === -1 && tokenChars[code] === 1) { + if (start === -1) start = i; + } else if (code === 0x20 || code === 0x09) { + if (end === -1 && start !== -1) end = i; + } else if (code === 0x3b || code === 0x2c) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + + if (end === -1) end = i; + push(params, header.slice(start, end), true); + if (code === 0x2c) { + push(offers, extensionName, params); + params = Object.create(null); + extensionName = undefined; + } + + start = end = -1; + } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) { + paramName = header.slice(start, i); + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } else { + // + // The value of a quoted-string after unescaping must conform to the + // token ABNF, so only token characters are valid. + // Ref: https://tools.ietf.org/html/rfc6455#section-9.1 + // + if (isEscaping) { + if (tokenChars[code] !== 1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + if (start === -1) start = i; + else if (!mustUnescape) mustUnescape = true; + isEscaping = false; + } else if (inQuotes) { + if (tokenChars[code] === 1) { + if (start === -1) start = i; + } else if (code === 0x22 /* '"' */ && start !== -1) { + inQuotes = false; + end = i; + } else if (code === 0x5c /* '\' */) { + isEscaping = true; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) { + inQuotes = true; + } else if (end === -1 && tokenChars[code] === 1) { + if (start === -1) start = i; + } else if (start !== -1 && (code === 0x20 || code === 0x09)) { + if (end === -1) end = i; + } else if (code === 0x3b || code === 0x2c) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + + if (end === -1) end = i; + let value = header.slice(start, end); + if (mustUnescape) { + value = value.replace(/\\/g, ''); + mustUnescape = false; + } + push(params, paramName, value); + if (code === 0x2c) { + push(offers, extensionName, params); + params = Object.create(null); + extensionName = undefined; + } + + paramName = undefined; + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } + } + + if (start === -1 || inQuotes || code === 0x20 || code === 0x09) { + throw new SyntaxError('Unexpected end of input'); + } + + if (end === -1) end = i; + const token = header.slice(start, end); + if (extensionName === undefined) { + push(offers, token, params); + } else { + if (paramName === undefined) { + push(params, token, true); + } else if (mustUnescape) { + push(params, paramName, token.replace(/\\/g, '')); + } else { + push(params, paramName, token); + } + push(offers, extensionName, params); + } + + return offers; +} + +/** + * Builds the `Sec-WebSocket-Extensions` header field value. + * + * @param {Object} extensions The map of extensions and parameters to format + * @return {String} A string representing the given object + * @public + */ +function format(extensions) { + return Object.keys(extensions) + .map((extension) => { + let configurations = extensions[extension]; + if (!Array.isArray(configurations)) configurations = [configurations]; + return configurations + .map((params) => { + return [extension] + .concat( + Object.keys(params).map((k) => { + let values = params[k]; + if (!Array.isArray(values)) values = [values]; + return values + .map((v) => (v === true ? k : `${k}=${v}`)) + .join('; '); + }) + ) + .join('; '); + }) + .join(', '); + }) + .join(', '); +} + +module.exports = { format, parse }; diff --git a/system/clearpilot/shell/node_modules/ws/lib/limiter.js b/system/clearpilot/shell/node_modules/ws/lib/limiter.js new file mode 100644 index 0000000..3fd3578 --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/lib/limiter.js @@ -0,0 +1,55 @@ +'use strict'; + +const kDone = Symbol('kDone'); +const kRun = Symbol('kRun'); + +/** + * A very simple job queue with adjustable concurrency. Adapted from + * https://github.com/STRML/async-limiter + */ +class Limiter { + /** + * Creates a new `Limiter`. + * + * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed + * to run concurrently + */ + constructor(concurrency) { + this[kDone] = () => { + this.pending--; + this[kRun](); + }; + this.concurrency = concurrency || Infinity; + this.jobs = []; + this.pending = 0; + } + + /** + * Adds a job to the queue. + * + * @param {Function} job The job to run + * @public + */ + add(job) { + this.jobs.push(job); + this[kRun](); + } + + /** + * Removes a job from the queue and runs it if possible. + * + * @private + */ + [kRun]() { + if (this.pending === this.concurrency) return; + + if (this.jobs.length) { + const job = this.jobs.shift(); + + this.pending++; + job(this[kDone]); + } + } +} + +module.exports = Limiter; diff --git a/system/clearpilot/shell/node_modules/ws/lib/permessage-deflate.js b/system/clearpilot/shell/node_modules/ws/lib/permessage-deflate.js new file mode 100644 index 0000000..77d918b --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/lib/permessage-deflate.js @@ -0,0 +1,514 @@ +'use strict'; + +const zlib = require('zlib'); + +const bufferUtil = require('./buffer-util'); +const Limiter = require('./limiter'); +const { kStatusCode } = require('./constants'); + +const FastBuffer = Buffer[Symbol.species]; +const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]); +const kPerMessageDeflate = Symbol('permessage-deflate'); +const kTotalLength = Symbol('total-length'); +const kCallback = Symbol('callback'); +const kBuffers = Symbol('buffers'); +const kError = Symbol('error'); + +// +// We limit zlib concurrency, which prevents severe memory fragmentation +// as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913 +// and https://github.com/websockets/ws/issues/1202 +// +// Intentionally global; it's the global thread pool that's an issue. +// +let zlibLimiter; + +/** + * permessage-deflate implementation. + */ +class PerMessageDeflate { + /** + * Creates a PerMessageDeflate instance. + * + * @param {Object} [options] Configuration options + * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support + * for, or request, a custom client window size + * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/ + * acknowledge disabling of client context takeover + * @param {Number} [options.concurrencyLimit=10] The number of concurrent + * calls to zlib + * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the + * use of a custom server window size + * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept + * disabling of server context takeover + * @param {Number} [options.threshold=1024] Size (in bytes) below which + * messages should not be compressed if context takeover is disabled + * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on + * deflate + * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on + * inflate + * @param {Boolean} [isServer=false] Create the instance in either server or + * client mode + * @param {Number} [maxPayload=0] The maximum allowed message length + */ + constructor(options, isServer, maxPayload) { + this._maxPayload = maxPayload | 0; + this._options = options || {}; + this._threshold = + this._options.threshold !== undefined ? this._options.threshold : 1024; + this._isServer = !!isServer; + this._deflate = null; + this._inflate = null; + + this.params = null; + + if (!zlibLimiter) { + const concurrency = + this._options.concurrencyLimit !== undefined + ? this._options.concurrencyLimit + : 10; + zlibLimiter = new Limiter(concurrency); + } + } + + /** + * @type {String} + */ + static get extensionName() { + return 'permessage-deflate'; + } + + /** + * Create an extension negotiation offer. + * + * @return {Object} Extension parameters + * @public + */ + offer() { + const params = {}; + + if (this._options.serverNoContextTakeover) { + params.server_no_context_takeover = true; + } + if (this._options.clientNoContextTakeover) { + params.client_no_context_takeover = true; + } + if (this._options.serverMaxWindowBits) { + params.server_max_window_bits = this._options.serverMaxWindowBits; + } + if (this._options.clientMaxWindowBits) { + params.client_max_window_bits = this._options.clientMaxWindowBits; + } else if (this._options.clientMaxWindowBits == null) { + params.client_max_window_bits = true; + } + + return params; + } + + /** + * Accept an extension negotiation offer/response. + * + * @param {Array} configurations The extension negotiation offers/reponse + * @return {Object} Accepted configuration + * @public + */ + accept(configurations) { + configurations = this.normalizeParams(configurations); + + this.params = this._isServer + ? this.acceptAsServer(configurations) + : this.acceptAsClient(configurations); + + return this.params; + } + + /** + * Releases all resources used by the extension. + * + * @public + */ + cleanup() { + if (this._inflate) { + this._inflate.close(); + this._inflate = null; + } + + if (this._deflate) { + const callback = this._deflate[kCallback]; + + this._deflate.close(); + this._deflate = null; + + if (callback) { + callback( + new Error( + 'The deflate stream was closed while data was being processed' + ) + ); + } + } + } + + /** + * Accept an extension negotiation offer. + * + * @param {Array} offers The extension negotiation offers + * @return {Object} Accepted configuration + * @private + */ + acceptAsServer(offers) { + const opts = this._options; + const accepted = offers.find((params) => { + if ( + (opts.serverNoContextTakeover === false && + params.server_no_context_takeover) || + (params.server_max_window_bits && + (opts.serverMaxWindowBits === false || + (typeof opts.serverMaxWindowBits === 'number' && + opts.serverMaxWindowBits > params.server_max_window_bits))) || + (typeof opts.clientMaxWindowBits === 'number' && + !params.client_max_window_bits) + ) { + return false; + } + + return true; + }); + + if (!accepted) { + throw new Error('None of the extension offers can be accepted'); + } + + if (opts.serverNoContextTakeover) { + accepted.server_no_context_takeover = true; + } + if (opts.clientNoContextTakeover) { + accepted.client_no_context_takeover = true; + } + if (typeof opts.serverMaxWindowBits === 'number') { + accepted.server_max_window_bits = opts.serverMaxWindowBits; + } + if (typeof opts.clientMaxWindowBits === 'number') { + accepted.client_max_window_bits = opts.clientMaxWindowBits; + } else if ( + accepted.client_max_window_bits === true || + opts.clientMaxWindowBits === false + ) { + delete accepted.client_max_window_bits; + } + + return accepted; + } + + /** + * Accept the extension negotiation response. + * + * @param {Array} response The extension negotiation response + * @return {Object} Accepted configuration + * @private + */ + acceptAsClient(response) { + const params = response[0]; + + if ( + this._options.clientNoContextTakeover === false && + params.client_no_context_takeover + ) { + throw new Error('Unexpected parameter "client_no_context_takeover"'); + } + + if (!params.client_max_window_bits) { + if (typeof this._options.clientMaxWindowBits === 'number') { + params.client_max_window_bits = this._options.clientMaxWindowBits; + } + } else if ( + this._options.clientMaxWindowBits === false || + (typeof this._options.clientMaxWindowBits === 'number' && + params.client_max_window_bits > this._options.clientMaxWindowBits) + ) { + throw new Error( + 'Unexpected or invalid parameter "client_max_window_bits"' + ); + } + + return params; + } + + /** + * Normalize parameters. + * + * @param {Array} configurations The extension negotiation offers/reponse + * @return {Array} The offers/response with normalized parameters + * @private + */ + normalizeParams(configurations) { + configurations.forEach((params) => { + Object.keys(params).forEach((key) => { + let value = params[key]; + + if (value.length > 1) { + throw new Error(`Parameter "${key}" must have only a single value`); + } + + value = value[0]; + + if (key === 'client_max_window_bits') { + if (value !== true) { + const num = +value; + if (!Number.isInteger(num) || num < 8 || num > 15) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + value = num; + } else if (!this._isServer) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + } else if (key === 'server_max_window_bits') { + const num = +value; + if (!Number.isInteger(num) || num < 8 || num > 15) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + value = num; + } else if ( + key === 'client_no_context_takeover' || + key === 'server_no_context_takeover' + ) { + if (value !== true) { + throw new TypeError( + `Invalid value for parameter "${key}": ${value}` + ); + } + } else { + throw new Error(`Unknown parameter "${key}"`); + } + + params[key] = value; + }); + }); + + return configurations; + } + + /** + * Decompress data. Concurrency limited. + * + * @param {Buffer} data Compressed data + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @public + */ + decompress(data, fin, callback) { + zlibLimiter.add((done) => { + this._decompress(data, fin, (err, result) => { + done(); + callback(err, result); + }); + }); + } + + /** + * Compress data. Concurrency limited. + * + * @param {(Buffer|String)} data Data to compress + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @public + */ + compress(data, fin, callback) { + zlibLimiter.add((done) => { + this._compress(data, fin, (err, result) => { + done(); + callback(err, result); + }); + }); + } + + /** + * Decompress data. + * + * @param {Buffer} data Compressed data + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @private + */ + _decompress(data, fin, callback) { + const endpoint = this._isServer ? 'client' : 'server'; + + if (!this._inflate) { + const key = `${endpoint}_max_window_bits`; + const windowBits = + typeof this.params[key] !== 'number' + ? zlib.Z_DEFAULT_WINDOWBITS + : this.params[key]; + + this._inflate = zlib.createInflateRaw({ + ...this._options.zlibInflateOptions, + windowBits + }); + this._inflate[kPerMessageDeflate] = this; + this._inflate[kTotalLength] = 0; + this._inflate[kBuffers] = []; + this._inflate.on('error', inflateOnError); + this._inflate.on('data', inflateOnData); + } + + this._inflate[kCallback] = callback; + + this._inflate.write(data); + if (fin) this._inflate.write(TRAILER); + + this._inflate.flush(() => { + const err = this._inflate[kError]; + + if (err) { + this._inflate.close(); + this._inflate = null; + callback(err); + return; + } + + const data = bufferUtil.concat( + this._inflate[kBuffers], + this._inflate[kTotalLength] + ); + + if (this._inflate._readableState.endEmitted) { + this._inflate.close(); + this._inflate = null; + } else { + this._inflate[kTotalLength] = 0; + this._inflate[kBuffers] = []; + + if (fin && this.params[`${endpoint}_no_context_takeover`]) { + this._inflate.reset(); + } + } + + callback(null, data); + }); + } + + /** + * Compress data. + * + * @param {(Buffer|String)} data Data to compress + * @param {Boolean} fin Specifies whether or not this is the last fragment + * @param {Function} callback Callback + * @private + */ + _compress(data, fin, callback) { + const endpoint = this._isServer ? 'server' : 'client'; + + if (!this._deflate) { + const key = `${endpoint}_max_window_bits`; + const windowBits = + typeof this.params[key] !== 'number' + ? zlib.Z_DEFAULT_WINDOWBITS + : this.params[key]; + + this._deflate = zlib.createDeflateRaw({ + ...this._options.zlibDeflateOptions, + windowBits + }); + + this._deflate[kTotalLength] = 0; + this._deflate[kBuffers] = []; + + this._deflate.on('data', deflateOnData); + } + + this._deflate[kCallback] = callback; + + this._deflate.write(data); + this._deflate.flush(zlib.Z_SYNC_FLUSH, () => { + if (!this._deflate) { + // + // The deflate stream was closed while data was being processed. + // + return; + } + + let data = bufferUtil.concat( + this._deflate[kBuffers], + this._deflate[kTotalLength] + ); + + if (fin) { + data = new FastBuffer(data.buffer, data.byteOffset, data.length - 4); + } + + // + // Ensure that the callback will not be called again in + // `PerMessageDeflate#cleanup()`. + // + this._deflate[kCallback] = null; + + this._deflate[kTotalLength] = 0; + this._deflate[kBuffers] = []; + + if (fin && this.params[`${endpoint}_no_context_takeover`]) { + this._deflate.reset(); + } + + callback(null, data); + }); + } +} + +module.exports = PerMessageDeflate; + +/** + * The listener of the `zlib.DeflateRaw` stream `'data'` event. + * + * @param {Buffer} chunk A chunk of data + * @private + */ +function deflateOnData(chunk) { + this[kBuffers].push(chunk); + this[kTotalLength] += chunk.length; +} + +/** + * The listener of the `zlib.InflateRaw` stream `'data'` event. + * + * @param {Buffer} chunk A chunk of data + * @private + */ +function inflateOnData(chunk) { + this[kTotalLength] += chunk.length; + + if ( + this[kPerMessageDeflate]._maxPayload < 1 || + this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload + ) { + this[kBuffers].push(chunk); + return; + } + + this[kError] = new RangeError('Max payload size exceeded'); + this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'; + this[kError][kStatusCode] = 1009; + this.removeListener('data', inflateOnData); + this.reset(); +} + +/** + * The listener of the `zlib.InflateRaw` stream `'error'` event. + * + * @param {Error} err The emitted error + * @private + */ +function inflateOnError(err) { + // + // There is no need to call `Zlib#close()` as the handle is automatically + // closed when an error is emitted. + // + this[kPerMessageDeflate]._inflate = null; + err[kStatusCode] = 1007; + this[kCallback](err); +} diff --git a/system/clearpilot/shell/node_modules/ws/lib/receiver.js b/system/clearpilot/shell/node_modules/ws/lib/receiver.js new file mode 100644 index 0000000..9e87d81 --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/lib/receiver.js @@ -0,0 +1,742 @@ +'use strict'; + +const { Writable } = require('stream'); + +const PerMessageDeflate = require('./permessage-deflate'); +const { + BINARY_TYPES, + EMPTY_BUFFER, + kStatusCode, + kWebSocket +} = require('./constants'); +const { concat, toArrayBuffer, unmask } = require('./buffer-util'); +const { isValidStatusCode, isValidUTF8 } = require('./validation'); + +const FastBuffer = Buffer[Symbol.species]; +const promise = Promise.resolve(); + +// +// `queueMicrotask()` is not available in Node.js < 11. +// +const queueTask = + typeof queueMicrotask === 'function' ? queueMicrotask : queueMicrotaskShim; + +const GET_INFO = 0; +const GET_PAYLOAD_LENGTH_16 = 1; +const GET_PAYLOAD_LENGTH_64 = 2; +const GET_MASK = 3; +const GET_DATA = 4; +const INFLATING = 5; +const DEFER_EVENT = 6; + +/** + * HyBi Receiver implementation. + * + * @extends Writable + */ +class Receiver extends Writable { + /** + * Creates a Receiver instance. + * + * @param {Object} [options] Options object + * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether + * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted + * multiple times in the same tick + * @param {String} [options.binaryType=nodebuffer] The type for binary data + * @param {Object} [options.extensions] An object containing the negotiated + * extensions + * @param {Boolean} [options.isServer=false] Specifies whether to operate in + * client or server mode + * @param {Number} [options.maxPayload=0] The maximum allowed message length + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + */ + constructor(options = {}) { + super(); + + this._allowSynchronousEvents = !!options.allowSynchronousEvents; + this._binaryType = options.binaryType || BINARY_TYPES[0]; + this._extensions = options.extensions || {}; + this._isServer = !!options.isServer; + this._maxPayload = options.maxPayload | 0; + this._skipUTF8Validation = !!options.skipUTF8Validation; + this[kWebSocket] = undefined; + + this._bufferedBytes = 0; + this._buffers = []; + + this._compressed = false; + this._payloadLength = 0; + this._mask = undefined; + this._fragmented = 0; + this._masked = false; + this._fin = false; + this._opcode = 0; + + this._totalPayloadLength = 0; + this._messageLength = 0; + this._fragments = []; + + this._errored = false; + this._loop = false; + this._state = GET_INFO; + } + + /** + * Implements `Writable.prototype._write()`. + * + * @param {Buffer} chunk The chunk of data to write + * @param {String} encoding The character encoding of `chunk` + * @param {Function} cb Callback + * @private + */ + _write(chunk, encoding, cb) { + if (this._opcode === 0x08 && this._state == GET_INFO) return cb(); + + this._bufferedBytes += chunk.length; + this._buffers.push(chunk); + this.startLoop(cb); + } + + /** + * Consumes `n` bytes from the buffered data. + * + * @param {Number} n The number of bytes to consume + * @return {Buffer} The consumed bytes + * @private + */ + consume(n) { + this._bufferedBytes -= n; + + if (n === this._buffers[0].length) return this._buffers.shift(); + + if (n < this._buffers[0].length) { + const buf = this._buffers[0]; + this._buffers[0] = new FastBuffer( + buf.buffer, + buf.byteOffset + n, + buf.length - n + ); + + return new FastBuffer(buf.buffer, buf.byteOffset, n); + } + + const dst = Buffer.allocUnsafe(n); + + do { + const buf = this._buffers[0]; + const offset = dst.length - n; + + if (n >= buf.length) { + dst.set(this._buffers.shift(), offset); + } else { + dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset); + this._buffers[0] = new FastBuffer( + buf.buffer, + buf.byteOffset + n, + buf.length - n + ); + } + + n -= buf.length; + } while (n > 0); + + return dst; + } + + /** + * Starts the parsing loop. + * + * @param {Function} cb Callback + * @private + */ + startLoop(cb) { + this._loop = true; + + do { + switch (this._state) { + case GET_INFO: + this.getInfo(cb); + break; + case GET_PAYLOAD_LENGTH_16: + this.getPayloadLength16(cb); + break; + case GET_PAYLOAD_LENGTH_64: + this.getPayloadLength64(cb); + break; + case GET_MASK: + this.getMask(); + break; + case GET_DATA: + this.getData(cb); + break; + case INFLATING: + case DEFER_EVENT: + this._loop = false; + return; + } + } while (this._loop); + + if (!this._errored) cb(); + } + + /** + * Reads the first two bytes of a frame. + * + * @param {Function} cb Callback + * @private + */ + getInfo(cb) { + if (this._bufferedBytes < 2) { + this._loop = false; + return; + } + + const buf = this.consume(2); + + if ((buf[0] & 0x30) !== 0x00) { + const error = this.createError( + RangeError, + 'RSV2 and RSV3 must be clear', + true, + 1002, + 'WS_ERR_UNEXPECTED_RSV_2_3' + ); + + cb(error); + return; + } + + const compressed = (buf[0] & 0x40) === 0x40; + + if (compressed && !this._extensions[PerMessageDeflate.extensionName]) { + const error = this.createError( + RangeError, + 'RSV1 must be clear', + true, + 1002, + 'WS_ERR_UNEXPECTED_RSV_1' + ); + + cb(error); + return; + } + + this._fin = (buf[0] & 0x80) === 0x80; + this._opcode = buf[0] & 0x0f; + this._payloadLength = buf[1] & 0x7f; + + if (this._opcode === 0x00) { + if (compressed) { + const error = this.createError( + RangeError, + 'RSV1 must be clear', + true, + 1002, + 'WS_ERR_UNEXPECTED_RSV_1' + ); + + cb(error); + return; + } + + if (!this._fragmented) { + const error = this.createError( + RangeError, + 'invalid opcode 0', + true, + 1002, + 'WS_ERR_INVALID_OPCODE' + ); + + cb(error); + return; + } + + this._opcode = this._fragmented; + } else if (this._opcode === 0x01 || this._opcode === 0x02) { + if (this._fragmented) { + const error = this.createError( + RangeError, + `invalid opcode ${this._opcode}`, + true, + 1002, + 'WS_ERR_INVALID_OPCODE' + ); + + cb(error); + return; + } + + this._compressed = compressed; + } else if (this._opcode > 0x07 && this._opcode < 0x0b) { + if (!this._fin) { + const error = this.createError( + RangeError, + 'FIN must be set', + true, + 1002, + 'WS_ERR_EXPECTED_FIN' + ); + + cb(error); + return; + } + + if (compressed) { + const error = this.createError( + RangeError, + 'RSV1 must be clear', + true, + 1002, + 'WS_ERR_UNEXPECTED_RSV_1' + ); + + cb(error); + return; + } + + if ( + this._payloadLength > 0x7d || + (this._opcode === 0x08 && this._payloadLength === 1) + ) { + const error = this.createError( + RangeError, + `invalid payload length ${this._payloadLength}`, + true, + 1002, + 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH' + ); + + cb(error); + return; + } + } else { + const error = this.createError( + RangeError, + `invalid opcode ${this._opcode}`, + true, + 1002, + 'WS_ERR_INVALID_OPCODE' + ); + + cb(error); + return; + } + + if (!this._fin && !this._fragmented) this._fragmented = this._opcode; + this._masked = (buf[1] & 0x80) === 0x80; + + if (this._isServer) { + if (!this._masked) { + const error = this.createError( + RangeError, + 'MASK must be set', + true, + 1002, + 'WS_ERR_EXPECTED_MASK' + ); + + cb(error); + return; + } + } else if (this._masked) { + const error = this.createError( + RangeError, + 'MASK must be clear', + true, + 1002, + 'WS_ERR_UNEXPECTED_MASK' + ); + + cb(error); + return; + } + + if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16; + else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64; + else this.haveLength(cb); + } + + /** + * Gets extended payload length (7+16). + * + * @param {Function} cb Callback + * @private + */ + getPayloadLength16(cb) { + if (this._bufferedBytes < 2) { + this._loop = false; + return; + } + + this._payloadLength = this.consume(2).readUInt16BE(0); + this.haveLength(cb); + } + + /** + * Gets extended payload length (7+64). + * + * @param {Function} cb Callback + * @private + */ + getPayloadLength64(cb) { + if (this._bufferedBytes < 8) { + this._loop = false; + return; + } + + const buf = this.consume(8); + const num = buf.readUInt32BE(0); + + // + // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned + // if payload length is greater than this number. + // + if (num > Math.pow(2, 53 - 32) - 1) { + const error = this.createError( + RangeError, + 'Unsupported WebSocket frame: payload length > 2^53 - 1', + false, + 1009, + 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH' + ); + + cb(error); + return; + } + + this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4); + this.haveLength(cb); + } + + /** + * Payload length has been read. + * + * @param {Function} cb Callback + * @private + */ + haveLength(cb) { + if (this._payloadLength && this._opcode < 0x08) { + this._totalPayloadLength += this._payloadLength; + if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) { + const error = this.createError( + RangeError, + 'Max payload size exceeded', + false, + 1009, + 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH' + ); + + cb(error); + return; + } + } + + if (this._masked) this._state = GET_MASK; + else this._state = GET_DATA; + } + + /** + * Reads mask bytes. + * + * @private + */ + getMask() { + if (this._bufferedBytes < 4) { + this._loop = false; + return; + } + + this._mask = this.consume(4); + this._state = GET_DATA; + } + + /** + * Reads data bytes. + * + * @param {Function} cb Callback + * @private + */ + getData(cb) { + let data = EMPTY_BUFFER; + + if (this._payloadLength) { + if (this._bufferedBytes < this._payloadLength) { + this._loop = false; + return; + } + + data = this.consume(this._payloadLength); + + if ( + this._masked && + (this._mask[0] | this._mask[1] | this._mask[2] | this._mask[3]) !== 0 + ) { + unmask(data, this._mask); + } + } + + if (this._opcode > 0x07) { + this.controlMessage(data, cb); + return; + } + + if (this._compressed) { + this._state = INFLATING; + this.decompress(data, cb); + return; + } + + if (data.length) { + // + // This message is not compressed so its length is the sum of the payload + // length of all fragments. + // + this._messageLength = this._totalPayloadLength; + this._fragments.push(data); + } + + this.dataMessage(cb); + } + + /** + * Decompresses data. + * + * @param {Buffer} data Compressed data + * @param {Function} cb Callback + * @private + */ + decompress(data, cb) { + const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; + + perMessageDeflate.decompress(data, this._fin, (err, buf) => { + if (err) return cb(err); + + if (buf.length) { + this._messageLength += buf.length; + if (this._messageLength > this._maxPayload && this._maxPayload > 0) { + const error = this.createError( + RangeError, + 'Max payload size exceeded', + false, + 1009, + 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH' + ); + + cb(error); + return; + } + + this._fragments.push(buf); + } + + this.dataMessage(cb); + if (this._state === GET_INFO) this.startLoop(cb); + }); + } + + /** + * Handles a data message. + * + * @param {Function} cb Callback + * @private + */ + dataMessage(cb) { + if (!this._fin) { + this._state = GET_INFO; + return; + } + + const messageLength = this._messageLength; + const fragments = this._fragments; + + this._totalPayloadLength = 0; + this._messageLength = 0; + this._fragmented = 0; + this._fragments = []; + + if (this._opcode === 2) { + let data; + + if (this._binaryType === 'nodebuffer') { + data = concat(fragments, messageLength); + } else if (this._binaryType === 'arraybuffer') { + data = toArrayBuffer(concat(fragments, messageLength)); + } else { + data = fragments; + } + + // + // If the state is `INFLATING`, it means that the frame data was + // decompressed asynchronously, so there is no need to defer the event + // as it will be emitted asynchronously anyway. + // + if (this._state === INFLATING || this._allowSynchronousEvents) { + this.emit('message', data, true); + this._state = GET_INFO; + } else { + this._state = DEFER_EVENT; + queueTask(() => { + this.emit('message', data, true); + this._state = GET_INFO; + this.startLoop(cb); + }); + } + } else { + const buf = concat(fragments, messageLength); + + if (!this._skipUTF8Validation && !isValidUTF8(buf)) { + const error = this.createError( + Error, + 'invalid UTF-8 sequence', + true, + 1007, + 'WS_ERR_INVALID_UTF8' + ); + + cb(error); + return; + } + + if (this._state === INFLATING || this._allowSynchronousEvents) { + this.emit('message', buf, false); + this._state = GET_INFO; + } else { + this._state = DEFER_EVENT; + queueTask(() => { + this.emit('message', buf, false); + this._state = GET_INFO; + this.startLoop(cb); + }); + } + } + } + + /** + * Handles a control message. + * + * @param {Buffer} data Data to handle + * @return {(Error|RangeError|undefined)} A possible error + * @private + */ + controlMessage(data, cb) { + if (this._opcode === 0x08) { + if (data.length === 0) { + this._loop = false; + this.emit('conclude', 1005, EMPTY_BUFFER); + this.end(); + } else { + const code = data.readUInt16BE(0); + + if (!isValidStatusCode(code)) { + const error = this.createError( + RangeError, + `invalid status code ${code}`, + true, + 1002, + 'WS_ERR_INVALID_CLOSE_CODE' + ); + + cb(error); + return; + } + + const buf = new FastBuffer( + data.buffer, + data.byteOffset + 2, + data.length - 2 + ); + + if (!this._skipUTF8Validation && !isValidUTF8(buf)) { + const error = this.createError( + Error, + 'invalid UTF-8 sequence', + true, + 1007, + 'WS_ERR_INVALID_UTF8' + ); + + cb(error); + return; + } + + this._loop = false; + this.emit('conclude', code, buf); + this.end(); + } + + this._state = GET_INFO; + return; + } + + if (this._allowSynchronousEvents) { + this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data); + this._state = GET_INFO; + } else { + this._state = DEFER_EVENT; + queueTask(() => { + this.emit(this._opcode === 0x09 ? 'ping' : 'pong', data); + this._state = GET_INFO; + this.startLoop(cb); + }); + } + } + + /** + * Builds an error object. + * + * @param {function(new:Error|RangeError)} ErrorCtor The error constructor + * @param {String} message The error message + * @param {Boolean} prefix Specifies whether or not to add a default prefix to + * `message` + * @param {Number} statusCode The status code + * @param {String} errorCode The exposed error code + * @return {(Error|RangeError)} The error + * @private + */ + createError(ErrorCtor, message, prefix, statusCode, errorCode) { + this._loop = false; + this._errored = true; + + const err = new ErrorCtor( + prefix ? `Invalid WebSocket frame: ${message}` : message + ); + + Error.captureStackTrace(err, this.createError); + err.code = errorCode; + err[kStatusCode] = statusCode; + return err; + } +} + +module.exports = Receiver; + +/** + * A shim for `queueMicrotask()`. + * + * @param {Function} cb Callback + */ +function queueMicrotaskShim(cb) { + promise.then(cb).catch(throwErrorNextTick); +} + +/** + * Throws an error. + * + * @param {Error} err The error to throw + * @private + */ +function throwError(err) { + throw err; +} + +/** + * Throws an error in the next tick. + * + * @param {Error} err The error to throw + * @private + */ +function throwErrorNextTick(err) { + process.nextTick(throwError, err); +} diff --git a/system/clearpilot/shell/node_modules/ws/lib/sender.js b/system/clearpilot/shell/node_modules/ws/lib/sender.js new file mode 100644 index 0000000..1ed04b0 --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/lib/sender.js @@ -0,0 +1,477 @@ +/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex" }] */ + +'use strict'; + +const { Duplex } = require('stream'); +const { randomFillSync } = require('crypto'); + +const PerMessageDeflate = require('./permessage-deflate'); +const { EMPTY_BUFFER } = require('./constants'); +const { isValidStatusCode } = require('./validation'); +const { mask: applyMask, toBuffer } = require('./buffer-util'); + +const kByteLength = Symbol('kByteLength'); +const maskBuffer = Buffer.alloc(4); + +/** + * HyBi Sender implementation. + */ +class Sender { + /** + * Creates a Sender instance. + * + * @param {Duplex} socket The connection socket + * @param {Object} [extensions] An object containing the negotiated extensions + * @param {Function} [generateMask] The function used to generate the masking + * key + */ + constructor(socket, extensions, generateMask) { + this._extensions = extensions || {}; + + if (generateMask) { + this._generateMask = generateMask; + this._maskBuffer = Buffer.alloc(4); + } + + this._socket = socket; + + this._firstFragment = true; + this._compress = false; + + this._bufferedBytes = 0; + this._deflating = false; + this._queue = []; + } + + /** + * Frames a piece of data according to the HyBi WebSocket protocol. + * + * @param {(Buffer|String)} data The data to frame + * @param {Object} options Options object + * @param {Boolean} [options.fin=false] Specifies whether or not to set the + * FIN bit + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Buffer} [options.maskBuffer] The buffer used to store the masking + * key + * @param {Number} options.opcode The opcode + * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be + * modified + * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the + * RSV1 bit + * @return {(Buffer|String)[]} The framed data + * @public + */ + static frame(data, options) { + let mask; + let merge = false; + let offset = 2; + let skipMasking = false; + + if (options.mask) { + mask = options.maskBuffer || maskBuffer; + + if (options.generateMask) { + options.generateMask(mask); + } else { + randomFillSync(mask, 0, 4); + } + + skipMasking = (mask[0] | mask[1] | mask[2] | mask[3]) === 0; + offset = 6; + } + + let dataLength; + + if (typeof data === 'string') { + if ( + (!options.mask || skipMasking) && + options[kByteLength] !== undefined + ) { + dataLength = options[kByteLength]; + } else { + data = Buffer.from(data); + dataLength = data.length; + } + } else { + dataLength = data.length; + merge = options.mask && options.readOnly && !skipMasking; + } + + let payloadLength = dataLength; + + if (dataLength >= 65536) { + offset += 8; + payloadLength = 127; + } else if (dataLength > 125) { + offset += 2; + payloadLength = 126; + } + + const target = Buffer.allocUnsafe(merge ? dataLength + offset : offset); + + target[0] = options.fin ? options.opcode | 0x80 : options.opcode; + if (options.rsv1) target[0] |= 0x40; + + target[1] = payloadLength; + + if (payloadLength === 126) { + target.writeUInt16BE(dataLength, 2); + } else if (payloadLength === 127) { + target[2] = target[3] = 0; + target.writeUIntBE(dataLength, 4, 6); + } + + if (!options.mask) return [target, data]; + + target[1] |= 0x80; + target[offset - 4] = mask[0]; + target[offset - 3] = mask[1]; + target[offset - 2] = mask[2]; + target[offset - 1] = mask[3]; + + if (skipMasking) return [target, data]; + + if (merge) { + applyMask(data, mask, target, offset, dataLength); + return [target]; + } + + applyMask(data, mask, data, 0, dataLength); + return [target, data]; + } + + /** + * Sends a close message to the other peer. + * + * @param {Number} [code] The status code component of the body + * @param {(String|Buffer)} [data] The message component of the body + * @param {Boolean} [mask=false] Specifies whether or not to mask the message + * @param {Function} [cb] Callback + * @public + */ + close(code, data, mask, cb) { + let buf; + + if (code === undefined) { + buf = EMPTY_BUFFER; + } else if (typeof code !== 'number' || !isValidStatusCode(code)) { + throw new TypeError('First argument must be a valid error code number'); + } else if (data === undefined || !data.length) { + buf = Buffer.allocUnsafe(2); + buf.writeUInt16BE(code, 0); + } else { + const length = Buffer.byteLength(data); + + if (length > 123) { + throw new RangeError('The message must not be greater than 123 bytes'); + } + + buf = Buffer.allocUnsafe(2 + length); + buf.writeUInt16BE(code, 0); + + if (typeof data === 'string') { + buf.write(data, 2); + } else { + buf.set(data, 2); + } + } + + const options = { + [kByteLength]: buf.length, + fin: true, + generateMask: this._generateMask, + mask, + maskBuffer: this._maskBuffer, + opcode: 0x08, + readOnly: false, + rsv1: false + }; + + if (this._deflating) { + this.enqueue([this.dispatch, buf, false, options, cb]); + } else { + this.sendFrame(Sender.frame(buf, options), cb); + } + } + + /** + * Sends a ping message to the other peer. + * + * @param {*} data The message to send + * @param {Boolean} [mask=false] Specifies whether or not to mask `data` + * @param {Function} [cb] Callback + * @public + */ + ping(data, mask, cb) { + let byteLength; + let readOnly; + + if (typeof data === 'string') { + byteLength = Buffer.byteLength(data); + readOnly = false; + } else { + data = toBuffer(data); + byteLength = data.length; + readOnly = toBuffer.readOnly; + } + + if (byteLength > 125) { + throw new RangeError('The data size must not be greater than 125 bytes'); + } + + const options = { + [kByteLength]: byteLength, + fin: true, + generateMask: this._generateMask, + mask, + maskBuffer: this._maskBuffer, + opcode: 0x09, + readOnly, + rsv1: false + }; + + if (this._deflating) { + this.enqueue([this.dispatch, data, false, options, cb]); + } else { + this.sendFrame(Sender.frame(data, options), cb); + } + } + + /** + * Sends a pong message to the other peer. + * + * @param {*} data The message to send + * @param {Boolean} [mask=false] Specifies whether or not to mask `data` + * @param {Function} [cb] Callback + * @public + */ + pong(data, mask, cb) { + let byteLength; + let readOnly; + + if (typeof data === 'string') { + byteLength = Buffer.byteLength(data); + readOnly = false; + } else { + data = toBuffer(data); + byteLength = data.length; + readOnly = toBuffer.readOnly; + } + + if (byteLength > 125) { + throw new RangeError('The data size must not be greater than 125 bytes'); + } + + const options = { + [kByteLength]: byteLength, + fin: true, + generateMask: this._generateMask, + mask, + maskBuffer: this._maskBuffer, + opcode: 0x0a, + readOnly, + rsv1: false + }; + + if (this._deflating) { + this.enqueue([this.dispatch, data, false, options, cb]); + } else { + this.sendFrame(Sender.frame(data, options), cb); + } + } + + /** + * Sends a data message to the other peer. + * + * @param {*} data The message to send + * @param {Object} options Options object + * @param {Boolean} [options.binary=false] Specifies whether `data` is binary + * or text + * @param {Boolean} [options.compress=false] Specifies whether or not to + * compress `data` + * @param {Boolean} [options.fin=false] Specifies whether the fragment is the + * last one + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Function} [cb] Callback + * @public + */ + send(data, options, cb) { + const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; + let opcode = options.binary ? 2 : 1; + let rsv1 = options.compress; + + let byteLength; + let readOnly; + + if (typeof data === 'string') { + byteLength = Buffer.byteLength(data); + readOnly = false; + } else { + data = toBuffer(data); + byteLength = data.length; + readOnly = toBuffer.readOnly; + } + + if (this._firstFragment) { + this._firstFragment = false; + if ( + rsv1 && + perMessageDeflate && + perMessageDeflate.params[ + perMessageDeflate._isServer + ? 'server_no_context_takeover' + : 'client_no_context_takeover' + ] + ) { + rsv1 = byteLength >= perMessageDeflate._threshold; + } + this._compress = rsv1; + } else { + rsv1 = false; + opcode = 0; + } + + if (options.fin) this._firstFragment = true; + + if (perMessageDeflate) { + const opts = { + [kByteLength]: byteLength, + fin: options.fin, + generateMask: this._generateMask, + mask: options.mask, + maskBuffer: this._maskBuffer, + opcode, + readOnly, + rsv1 + }; + + if (this._deflating) { + this.enqueue([this.dispatch, data, this._compress, opts, cb]); + } else { + this.dispatch(data, this._compress, opts, cb); + } + } else { + this.sendFrame( + Sender.frame(data, { + [kByteLength]: byteLength, + fin: options.fin, + generateMask: this._generateMask, + mask: options.mask, + maskBuffer: this._maskBuffer, + opcode, + readOnly, + rsv1: false + }), + cb + ); + } + } + + /** + * Dispatches a message. + * + * @param {(Buffer|String)} data The message to send + * @param {Boolean} [compress=false] Specifies whether or not to compress + * `data` + * @param {Object} options Options object + * @param {Boolean} [options.fin=false] Specifies whether or not to set the + * FIN bit + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Boolean} [options.mask=false] Specifies whether or not to mask + * `data` + * @param {Buffer} [options.maskBuffer] The buffer used to store the masking + * key + * @param {Number} options.opcode The opcode + * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be + * modified + * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the + * RSV1 bit + * @param {Function} [cb] Callback + * @private + */ + dispatch(data, compress, options, cb) { + if (!compress) { + this.sendFrame(Sender.frame(data, options), cb); + return; + } + + const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName]; + + this._bufferedBytes += options[kByteLength]; + this._deflating = true; + perMessageDeflate.compress(data, options.fin, (_, buf) => { + if (this._socket.destroyed) { + const err = new Error( + 'The socket was closed while data was being compressed' + ); + + if (typeof cb === 'function') cb(err); + + for (let i = 0; i < this._queue.length; i++) { + const params = this._queue[i]; + const callback = params[params.length - 1]; + + if (typeof callback === 'function') callback(err); + } + + return; + } + + this._bufferedBytes -= options[kByteLength]; + this._deflating = false; + options.readOnly = false; + this.sendFrame(Sender.frame(buf, options), cb); + this.dequeue(); + }); + } + + /** + * Executes queued send operations. + * + * @private + */ + dequeue() { + while (!this._deflating && this._queue.length) { + const params = this._queue.shift(); + + this._bufferedBytes -= params[3][kByteLength]; + Reflect.apply(params[0], this, params.slice(1)); + } + } + + /** + * Enqueues a send operation. + * + * @param {Array} params Send operation parameters. + * @private + */ + enqueue(params) { + this._bufferedBytes += params[3][kByteLength]; + this._queue.push(params); + } + + /** + * Sends a frame. + * + * @param {Buffer[]} list The frame to send + * @param {Function} [cb] Callback + * @private + */ + sendFrame(list, cb) { + if (list.length === 2) { + this._socket.cork(); + this._socket.write(list[0]); + this._socket.write(list[1], cb); + this._socket.uncork(); + } else { + this._socket.write(list[0], cb); + } + } +} + +module.exports = Sender; diff --git a/system/clearpilot/shell/node_modules/ws/lib/stream.js b/system/clearpilot/shell/node_modules/ws/lib/stream.js new file mode 100644 index 0000000..230734b --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/lib/stream.js @@ -0,0 +1,159 @@ +'use strict'; + +const { Duplex } = require('stream'); + +/** + * Emits the `'close'` event on a stream. + * + * @param {Duplex} stream The stream. + * @private + */ +function emitClose(stream) { + stream.emit('close'); +} + +/** + * The listener of the `'end'` event. + * + * @private + */ +function duplexOnEnd() { + if (!this.destroyed && this._writableState.finished) { + this.destroy(); + } +} + +/** + * The listener of the `'error'` event. + * + * @param {Error} err The error + * @private + */ +function duplexOnError(err) { + this.removeListener('error', duplexOnError); + this.destroy(); + if (this.listenerCount('error') === 0) { + // Do not suppress the throwing behavior. + this.emit('error', err); + } +} + +/** + * Wraps a `WebSocket` in a duplex stream. + * + * @param {WebSocket} ws The `WebSocket` to wrap + * @param {Object} [options] The options for the `Duplex` constructor + * @return {Duplex} The duplex stream + * @public + */ +function createWebSocketStream(ws, options) { + let terminateOnDestroy = true; + + const duplex = new Duplex({ + ...options, + autoDestroy: false, + emitClose: false, + objectMode: false, + writableObjectMode: false + }); + + ws.on('message', function message(msg, isBinary) { + const data = + !isBinary && duplex._readableState.objectMode ? msg.toString() : msg; + + if (!duplex.push(data)) ws.pause(); + }); + + ws.once('error', function error(err) { + if (duplex.destroyed) return; + + // Prevent `ws.terminate()` from being called by `duplex._destroy()`. + // + // - If the `'error'` event is emitted before the `'open'` event, then + // `ws.terminate()` is a noop as no socket is assigned. + // - Otherwise, the error is re-emitted by the listener of the `'error'` + // event of the `Receiver` object. The listener already closes the + // connection by calling `ws.close()`. This allows a close frame to be + // sent to the other peer. If `ws.terminate()` is called right after this, + // then the close frame might not be sent. + terminateOnDestroy = false; + duplex.destroy(err); + }); + + ws.once('close', function close() { + if (duplex.destroyed) return; + + duplex.push(null); + }); + + duplex._destroy = function (err, callback) { + if (ws.readyState === ws.CLOSED) { + callback(err); + process.nextTick(emitClose, duplex); + return; + } + + let called = false; + + ws.once('error', function error(err) { + called = true; + callback(err); + }); + + ws.once('close', function close() { + if (!called) callback(err); + process.nextTick(emitClose, duplex); + }); + + if (terminateOnDestroy) ws.terminate(); + }; + + duplex._final = function (callback) { + if (ws.readyState === ws.CONNECTING) { + ws.once('open', function open() { + duplex._final(callback); + }); + return; + } + + // If the value of the `_socket` property is `null` it means that `ws` is a + // client websocket and the handshake failed. In fact, when this happens, a + // socket is never assigned to the websocket. Wait for the `'error'` event + // that will be emitted by the websocket. + if (ws._socket === null) return; + + if (ws._socket._writableState.finished) { + callback(); + if (duplex._readableState.endEmitted) duplex.destroy(); + } else { + ws._socket.once('finish', function finish() { + // `duplex` is not destroyed here because the `'end'` event will be + // emitted on `duplex` after this `'finish'` event. The EOF signaling + // `null` chunk is, in fact, pushed when the websocket emits `'close'`. + callback(); + }); + ws.close(); + } + }; + + duplex._read = function () { + if (ws.isPaused) ws.resume(); + }; + + duplex._write = function (chunk, encoding, callback) { + if (ws.readyState === ws.CONNECTING) { + ws.once('open', function open() { + duplex._write(chunk, encoding, callback); + }); + return; + } + + ws.send(chunk, callback); + }; + + duplex.on('end', duplexOnEnd); + duplex.on('error', duplexOnError); + return duplex; +} + +module.exports = createWebSocketStream; diff --git a/system/clearpilot/shell/node_modules/ws/lib/subprotocol.js b/system/clearpilot/shell/node_modules/ws/lib/subprotocol.js new file mode 100644 index 0000000..d4381e8 --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/lib/subprotocol.js @@ -0,0 +1,62 @@ +'use strict'; + +const { tokenChars } = require('./validation'); + +/** + * Parses the `Sec-WebSocket-Protocol` header into a set of subprotocol names. + * + * @param {String} header The field value of the header + * @return {Set} The subprotocol names + * @public + */ +function parse(header) { + const protocols = new Set(); + let start = -1; + let end = -1; + let i = 0; + + for (i; i < header.length; i++) { + const code = header.charCodeAt(i); + + if (end === -1 && tokenChars[code] === 1) { + if (start === -1) start = i; + } else if ( + i !== 0 && + (code === 0x20 /* ' ' */ || code === 0x09) /* '\t' */ + ) { + if (end === -1 && start !== -1) end = i; + } else if (code === 0x2c /* ',' */) { + if (start === -1) { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + + if (end === -1) end = i; + + const protocol = header.slice(start, end); + + if (protocols.has(protocol)) { + throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`); + } + + protocols.add(protocol); + start = end = -1; + } else { + throw new SyntaxError(`Unexpected character at index ${i}`); + } + } + + if (start === -1 || end !== -1) { + throw new SyntaxError('Unexpected end of input'); + } + + const protocol = header.slice(start, i); + + if (protocols.has(protocol)) { + throw new SyntaxError(`The "${protocol}" subprotocol is duplicated`); + } + + protocols.add(protocol); + return protocols; +} + +module.exports = { parse }; diff --git a/system/clearpilot/shell/node_modules/ws/lib/validation.js b/system/clearpilot/shell/node_modules/ws/lib/validation.js new file mode 100644 index 0000000..c352e6e --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/lib/validation.js @@ -0,0 +1,130 @@ +'use strict'; + +const { isUtf8 } = require('buffer'); + +// +// Allowed token characters: +// +// '!', '#', '$', '%', '&', ''', '*', '+', '-', +// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~' +// +// tokenChars[32] === 0 // ' ' +// tokenChars[33] === 1 // '!' +// tokenChars[34] === 0 // '"' +// ... +// +// prettier-ignore +const tokenChars = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31 + 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63 + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127 +]; + +/** + * Checks if a status code is allowed in a close frame. + * + * @param {Number} code The status code + * @return {Boolean} `true` if the status code is valid, else `false` + * @public + */ +function isValidStatusCode(code) { + return ( + (code >= 1000 && + code <= 1014 && + code !== 1004 && + code !== 1005 && + code !== 1006) || + (code >= 3000 && code <= 4999) + ); +} + +/** + * Checks if a given buffer contains only correct UTF-8. + * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by + * Markus Kuhn. + * + * @param {Buffer} buf The buffer to check + * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false` + * @public + */ +function _isValidUTF8(buf) { + const len = buf.length; + let i = 0; + + while (i < len) { + if ((buf[i] & 0x80) === 0) { + // 0xxxxxxx + i++; + } else if ((buf[i] & 0xe0) === 0xc0) { + // 110xxxxx 10xxxxxx + if ( + i + 1 === len || + (buf[i + 1] & 0xc0) !== 0x80 || + (buf[i] & 0xfe) === 0xc0 // Overlong + ) { + return false; + } + + i += 2; + } else if ((buf[i] & 0xf0) === 0xe0) { + // 1110xxxx 10xxxxxx 10xxxxxx + if ( + i + 2 >= len || + (buf[i + 1] & 0xc0) !== 0x80 || + (buf[i + 2] & 0xc0) !== 0x80 || + (buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || // Overlong + (buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) // Surrogate (U+D800 - U+DFFF) + ) { + return false; + } + + i += 3; + } else if ((buf[i] & 0xf8) === 0xf0) { + // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + if ( + i + 3 >= len || + (buf[i + 1] & 0xc0) !== 0x80 || + (buf[i + 2] & 0xc0) !== 0x80 || + (buf[i + 3] & 0xc0) !== 0x80 || + (buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || // Overlong + (buf[i] === 0xf4 && buf[i + 1] > 0x8f) || + buf[i] > 0xf4 // > U+10FFFF + ) { + return false; + } + + i += 4; + } else { + return false; + } + } + + return true; +} + +module.exports = { + isValidStatusCode, + isValidUTF8: _isValidUTF8, + tokenChars +}; + +if (isUtf8) { + module.exports.isValidUTF8 = function (buf) { + return buf.length < 24 ? _isValidUTF8(buf) : isUtf8(buf); + }; +} /* istanbul ignore else */ else if (!process.env.WS_NO_UTF_8_VALIDATE) { + try { + const isValidUTF8 = require('utf-8-validate'); + + module.exports.isValidUTF8 = function (buf) { + return buf.length < 32 ? _isValidUTF8(buf) : isValidUTF8(buf); + }; + } catch (e) { + // Continue regardless of the error. + } +} diff --git a/system/clearpilot/shell/node_modules/ws/lib/websocket-server.js b/system/clearpilot/shell/node_modules/ws/lib/websocket-server.js new file mode 100644 index 0000000..377c45a --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/lib/websocket-server.js @@ -0,0 +1,539 @@ +/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex$" }] */ + +'use strict'; + +const EventEmitter = require('events'); +const http = require('http'); +const { Duplex } = require('stream'); +const { createHash } = require('crypto'); + +const extension = require('./extension'); +const PerMessageDeflate = require('./permessage-deflate'); +const subprotocol = require('./subprotocol'); +const WebSocket = require('./websocket'); +const { GUID, kWebSocket } = require('./constants'); + +const keyRegex = /^[+/0-9A-Za-z]{22}==$/; + +const RUNNING = 0; +const CLOSING = 1; +const CLOSED = 2; + +/** + * Class representing a WebSocket server. + * + * @extends EventEmitter + */ +class WebSocketServer extends EventEmitter { + /** + * Create a `WebSocketServer` instance. + * + * @param {Object} options Configuration options + * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether + * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted + * multiple times in the same tick + * @param {Boolean} [options.autoPong=true] Specifies whether or not to + * automatically send a pong in response to a ping + * @param {Number} [options.backlog=511] The maximum length of the queue of + * pending connections + * @param {Boolean} [options.clientTracking=true] Specifies whether or not to + * track clients + * @param {Function} [options.handleProtocols] A hook to handle protocols + * @param {String} [options.host] The hostname where to bind the server + * @param {Number} [options.maxPayload=104857600] The maximum allowed message + * size + * @param {Boolean} [options.noServer=false] Enable no server mode + * @param {String} [options.path] Accept only connections matching this path + * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable + * permessage-deflate + * @param {Number} [options.port] The port where to bind the server + * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S + * server to use + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + * @param {Function} [options.verifyClient] A hook to reject connections + * @param {Function} [options.WebSocket=WebSocket] Specifies the `WebSocket` + * class to use. It must be the `WebSocket` class or class that extends it + * @param {Function} [callback] A listener for the `listening` event + */ + constructor(options, callback) { + super(); + + options = { + allowSynchronousEvents: false, + autoPong: true, + maxPayload: 100 * 1024 * 1024, + skipUTF8Validation: false, + perMessageDeflate: false, + handleProtocols: null, + clientTracking: true, + verifyClient: null, + noServer: false, + backlog: null, // use default (511 as implemented in net.js) + server: null, + host: null, + path: null, + port: null, + WebSocket, + ...options + }; + + if ( + (options.port == null && !options.server && !options.noServer) || + (options.port != null && (options.server || options.noServer)) || + (options.server && options.noServer) + ) { + throw new TypeError( + 'One and only one of the "port", "server", or "noServer" options ' + + 'must be specified' + ); + } + + if (options.port != null) { + this._server = http.createServer((req, res) => { + const body = http.STATUS_CODES[426]; + + res.writeHead(426, { + 'Content-Length': body.length, + 'Content-Type': 'text/plain' + }); + res.end(body); + }); + this._server.listen( + options.port, + options.host, + options.backlog, + callback + ); + } else if (options.server) { + this._server = options.server; + } + + if (this._server) { + const emitConnection = this.emit.bind(this, 'connection'); + + this._removeListeners = addListeners(this._server, { + listening: this.emit.bind(this, 'listening'), + error: this.emit.bind(this, 'error'), + upgrade: (req, socket, head) => { + this.handleUpgrade(req, socket, head, emitConnection); + } + }); + } + + if (options.perMessageDeflate === true) options.perMessageDeflate = {}; + if (options.clientTracking) { + this.clients = new Set(); + this._shouldEmitClose = false; + } + + this.options = options; + this._state = RUNNING; + } + + /** + * Returns the bound address, the address family name, and port of the server + * as reported by the operating system if listening on an IP socket. + * If the server is listening on a pipe or UNIX domain socket, the name is + * returned as a string. + * + * @return {(Object|String|null)} The address of the server + * @public + */ + address() { + if (this.options.noServer) { + throw new Error('The server is operating in "noServer" mode'); + } + + if (!this._server) return null; + return this._server.address(); + } + + /** + * Stop the server from accepting new connections and emit the `'close'` event + * when all existing connections are closed. + * + * @param {Function} [cb] A one-time listener for the `'close'` event + * @public + */ + close(cb) { + if (this._state === CLOSED) { + if (cb) { + this.once('close', () => { + cb(new Error('The server is not running')); + }); + } + + process.nextTick(emitClose, this); + return; + } + + if (cb) this.once('close', cb); + + if (this._state === CLOSING) return; + this._state = CLOSING; + + if (this.options.noServer || this.options.server) { + if (this._server) { + this._removeListeners(); + this._removeListeners = this._server = null; + } + + if (this.clients) { + if (!this.clients.size) { + process.nextTick(emitClose, this); + } else { + this._shouldEmitClose = true; + } + } else { + process.nextTick(emitClose, this); + } + } else { + const server = this._server; + + this._removeListeners(); + this._removeListeners = this._server = null; + + // + // The HTTP/S server was created internally. Close it, and rely on its + // `'close'` event. + // + server.close(() => { + emitClose(this); + }); + } + } + + /** + * See if a given request should be handled by this server instance. + * + * @param {http.IncomingMessage} req Request object to inspect + * @return {Boolean} `true` if the request is valid, else `false` + * @public + */ + shouldHandle(req) { + if (this.options.path) { + const index = req.url.indexOf('?'); + const pathname = index !== -1 ? req.url.slice(0, index) : req.url; + + if (pathname !== this.options.path) return false; + } + + return true; + } + + /** + * Handle a HTTP Upgrade request. + * + * @param {http.IncomingMessage} req The request object + * @param {Duplex} socket The network socket between the server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Function} cb Callback + * @public + */ + handleUpgrade(req, socket, head, cb) { + socket.on('error', socketOnError); + + const key = req.headers['sec-websocket-key']; + const version = +req.headers['sec-websocket-version']; + + if (req.method !== 'GET') { + const message = 'Invalid HTTP method'; + abortHandshakeOrEmitwsClientError(this, req, socket, 405, message); + return; + } + + if (req.headers.upgrade.toLowerCase() !== 'websocket') { + const message = 'Invalid Upgrade header'; + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); + return; + } + + if (!key || !keyRegex.test(key)) { + const message = 'Missing or invalid Sec-WebSocket-Key header'; + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); + return; + } + + if (version !== 8 && version !== 13) { + const message = 'Missing or invalid Sec-WebSocket-Version header'; + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); + return; + } + + if (!this.shouldHandle(req)) { + abortHandshake(socket, 400); + return; + } + + const secWebSocketProtocol = req.headers['sec-websocket-protocol']; + let protocols = new Set(); + + if (secWebSocketProtocol !== undefined) { + try { + protocols = subprotocol.parse(secWebSocketProtocol); + } catch (err) { + const message = 'Invalid Sec-WebSocket-Protocol header'; + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); + return; + } + } + + const secWebSocketExtensions = req.headers['sec-websocket-extensions']; + const extensions = {}; + + if ( + this.options.perMessageDeflate && + secWebSocketExtensions !== undefined + ) { + const perMessageDeflate = new PerMessageDeflate( + this.options.perMessageDeflate, + true, + this.options.maxPayload + ); + + try { + const offers = extension.parse(secWebSocketExtensions); + + if (offers[PerMessageDeflate.extensionName]) { + perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]); + extensions[PerMessageDeflate.extensionName] = perMessageDeflate; + } + } catch (err) { + const message = + 'Invalid or unacceptable Sec-WebSocket-Extensions header'; + abortHandshakeOrEmitwsClientError(this, req, socket, 400, message); + return; + } + } + + // + // Optionally call external client verification handler. + // + if (this.options.verifyClient) { + const info = { + origin: + req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`], + secure: !!(req.socket.authorized || req.socket.encrypted), + req + }; + + if (this.options.verifyClient.length === 2) { + this.options.verifyClient(info, (verified, code, message, headers) => { + if (!verified) { + return abortHandshake(socket, code || 401, message, headers); + } + + this.completeUpgrade( + extensions, + key, + protocols, + req, + socket, + head, + cb + ); + }); + return; + } + + if (!this.options.verifyClient(info)) return abortHandshake(socket, 401); + } + + this.completeUpgrade(extensions, key, protocols, req, socket, head, cb); + } + + /** + * Upgrade the connection to WebSocket. + * + * @param {Object} extensions The accepted extensions + * @param {String} key The value of the `Sec-WebSocket-Key` header + * @param {Set} protocols The subprotocols + * @param {http.IncomingMessage} req The request object + * @param {Duplex} socket The network socket between the server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Function} cb Callback + * @throws {Error} If called more than once with the same socket + * @private + */ + completeUpgrade(extensions, key, protocols, req, socket, head, cb) { + // + // Destroy the socket if the client has already sent a FIN packet. + // + if (!socket.readable || !socket.writable) return socket.destroy(); + + if (socket[kWebSocket]) { + throw new Error( + 'server.handleUpgrade() was called more than once with the same ' + + 'socket, possibly due to a misconfiguration' + ); + } + + if (this._state > RUNNING) return abortHandshake(socket, 503); + + const digest = createHash('sha1') + .update(key + GUID) + .digest('base64'); + + const headers = [ + 'HTTP/1.1 101 Switching Protocols', + 'Upgrade: websocket', + 'Connection: Upgrade', + `Sec-WebSocket-Accept: ${digest}` + ]; + + const ws = new this.options.WebSocket(null, undefined, this.options); + + if (protocols.size) { + // + // Optionally call external protocol selection handler. + // + const protocol = this.options.handleProtocols + ? this.options.handleProtocols(protocols, req) + : protocols.values().next().value; + + if (protocol) { + headers.push(`Sec-WebSocket-Protocol: ${protocol}`); + ws._protocol = protocol; + } + } + + if (extensions[PerMessageDeflate.extensionName]) { + const params = extensions[PerMessageDeflate.extensionName].params; + const value = extension.format({ + [PerMessageDeflate.extensionName]: [params] + }); + headers.push(`Sec-WebSocket-Extensions: ${value}`); + ws._extensions = extensions; + } + + // + // Allow external modification/inspection of handshake headers. + // + this.emit('headers', headers, req); + + socket.write(headers.concat('\r\n').join('\r\n')); + socket.removeListener('error', socketOnError); + + ws.setSocket(socket, head, { + allowSynchronousEvents: this.options.allowSynchronousEvents, + maxPayload: this.options.maxPayload, + skipUTF8Validation: this.options.skipUTF8Validation + }); + + if (this.clients) { + this.clients.add(ws); + ws.on('close', () => { + this.clients.delete(ws); + + if (this._shouldEmitClose && !this.clients.size) { + process.nextTick(emitClose, this); + } + }); + } + + cb(ws, req); + } +} + +module.exports = WebSocketServer; + +/** + * Add event listeners on an `EventEmitter` using a map of + * pairs. + * + * @param {EventEmitter} server The event emitter + * @param {Object.} map The listeners to add + * @return {Function} A function that will remove the added listeners when + * called + * @private + */ +function addListeners(server, map) { + for (const event of Object.keys(map)) server.on(event, map[event]); + + return function removeListeners() { + for (const event of Object.keys(map)) { + server.removeListener(event, map[event]); + } + }; +} + +/** + * Emit a `'close'` event on an `EventEmitter`. + * + * @param {EventEmitter} server The event emitter + * @private + */ +function emitClose(server) { + server._state = CLOSED; + server.emit('close'); +} + +/** + * Handle socket errors. + * + * @private + */ +function socketOnError() { + this.destroy(); +} + +/** + * Close the connection when preconditions are not fulfilled. + * + * @param {Duplex} socket The socket of the upgrade request + * @param {Number} code The HTTP response status code + * @param {String} [message] The HTTP response body + * @param {Object} [headers] Additional HTTP response headers + * @private + */ +function abortHandshake(socket, code, message, headers) { + // + // The socket is writable unless the user destroyed or ended it before calling + // `server.handleUpgrade()` or in the `verifyClient` function, which is a user + // error. Handling this does not make much sense as the worst that can happen + // is that some of the data written by the user might be discarded due to the + // call to `socket.end()` below, which triggers an `'error'` event that in + // turn causes the socket to be destroyed. + // + message = message || http.STATUS_CODES[code]; + headers = { + Connection: 'close', + 'Content-Type': 'text/html', + 'Content-Length': Buffer.byteLength(message), + ...headers + }; + + socket.once('finish', socket.destroy); + + socket.end( + `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` + + Object.keys(headers) + .map((h) => `${h}: ${headers[h]}`) + .join('\r\n') + + '\r\n\r\n' + + message + ); +} + +/** + * Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least + * one listener for it, otherwise call `abortHandshake()`. + * + * @param {WebSocketServer} server The WebSocket server + * @param {http.IncomingMessage} req The request object + * @param {Duplex} socket The socket of the upgrade request + * @param {Number} code The HTTP response status code + * @param {String} message The HTTP response body + * @private + */ +function abortHandshakeOrEmitwsClientError(server, req, socket, code, message) { + if (server.listenerCount('wsClientError')) { + const err = new Error(message); + Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError); + + server.emit('wsClientError', err, socket, req); + } else { + abortHandshake(socket, code, message); + } +} diff --git a/system/clearpilot/shell/node_modules/ws/lib/websocket.js b/system/clearpilot/shell/node_modules/ws/lib/websocket.js new file mode 100644 index 0000000..df5034c --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/lib/websocket.js @@ -0,0 +1,1336 @@ +/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Duplex|Readable$" }] */ + +'use strict'; + +const EventEmitter = require('events'); +const https = require('https'); +const http = require('http'); +const net = require('net'); +const tls = require('tls'); +const { randomBytes, createHash } = require('crypto'); +const { Duplex, Readable } = require('stream'); +const { URL } = require('url'); + +const PerMessageDeflate = require('./permessage-deflate'); +const Receiver = require('./receiver'); +const Sender = require('./sender'); +const { + BINARY_TYPES, + EMPTY_BUFFER, + GUID, + kForOnEventAttribute, + kListener, + kStatusCode, + kWebSocket, + NOOP +} = require('./constants'); +const { + EventTarget: { addEventListener, removeEventListener } +} = require('./event-target'); +const { format, parse } = require('./extension'); +const { toBuffer } = require('./buffer-util'); + +const closeTimeout = 30 * 1000; +const kAborted = Symbol('kAborted'); +const protocolVersions = [8, 13]; +const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED']; +const subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/; + +/** + * Class representing a WebSocket. + * + * @extends EventEmitter + */ +class WebSocket extends EventEmitter { + /** + * Create a new `WebSocket`. + * + * @param {(String|URL)} address The URL to which to connect + * @param {(String|String[])} [protocols] The subprotocols + * @param {Object} [options] Connection options + */ + constructor(address, protocols, options) { + super(); + + this._binaryType = BINARY_TYPES[0]; + this._closeCode = 1006; + this._closeFrameReceived = false; + this._closeFrameSent = false; + this._closeMessage = EMPTY_BUFFER; + this._closeTimer = null; + this._extensions = {}; + this._paused = false; + this._protocol = ''; + this._readyState = WebSocket.CONNECTING; + this._receiver = null; + this._sender = null; + this._socket = null; + + if (address !== null) { + this._bufferedAmount = 0; + this._isServer = false; + this._redirects = 0; + + if (protocols === undefined) { + protocols = []; + } else if (!Array.isArray(protocols)) { + if (typeof protocols === 'object' && protocols !== null) { + options = protocols; + protocols = []; + } else { + protocols = [protocols]; + } + } + + initAsClient(this, address, protocols, options); + } else { + this._autoPong = options.autoPong; + this._isServer = true; + } + } + + /** + * This deviates from the WHATWG interface since ws doesn't support the + * required default "blob" type (instead we define a custom "nodebuffer" + * type). + * + * @type {String} + */ + get binaryType() { + return this._binaryType; + } + + set binaryType(type) { + if (!BINARY_TYPES.includes(type)) return; + + this._binaryType = type; + + // + // Allow to change `binaryType` on the fly. + // + if (this._receiver) this._receiver._binaryType = type; + } + + /** + * @type {Number} + */ + get bufferedAmount() { + if (!this._socket) return this._bufferedAmount; + + return this._socket._writableState.length + this._sender._bufferedBytes; + } + + /** + * @type {String} + */ + get extensions() { + return Object.keys(this._extensions).join(); + } + + /** + * @type {Boolean} + */ + get isPaused() { + return this._paused; + } + + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onclose() { + return null; + } + + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onerror() { + return null; + } + + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onopen() { + return null; + } + + /** + * @type {Function} + */ + /* istanbul ignore next */ + get onmessage() { + return null; + } + + /** + * @type {String} + */ + get protocol() { + return this._protocol; + } + + /** + * @type {Number} + */ + get readyState() { + return this._readyState; + } + + /** + * @type {String} + */ + get url() { + return this._url; + } + + /** + * Set up the socket and the internal resources. + * + * @param {Duplex} socket The network socket between the server and client + * @param {Buffer} head The first packet of the upgraded stream + * @param {Object} options Options object + * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether + * any of the `'message'`, `'ping'`, and `'pong'` events can be emitted + * multiple times in the same tick + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Number} [options.maxPayload=0] The maximum allowed message size + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + * @private + */ + setSocket(socket, head, options) { + const receiver = new Receiver({ + allowSynchronousEvents: options.allowSynchronousEvents, + binaryType: this.binaryType, + extensions: this._extensions, + isServer: this._isServer, + maxPayload: options.maxPayload, + skipUTF8Validation: options.skipUTF8Validation + }); + + this._sender = new Sender(socket, this._extensions, options.generateMask); + this._receiver = receiver; + this._socket = socket; + + receiver[kWebSocket] = this; + socket[kWebSocket] = this; + + receiver.on('conclude', receiverOnConclude); + receiver.on('drain', receiverOnDrain); + receiver.on('error', receiverOnError); + receiver.on('message', receiverOnMessage); + receiver.on('ping', receiverOnPing); + receiver.on('pong', receiverOnPong); + + // + // These methods may not be available if `socket` is just a `Duplex`. + // + if (socket.setTimeout) socket.setTimeout(0); + if (socket.setNoDelay) socket.setNoDelay(); + + if (head.length > 0) socket.unshift(head); + + socket.on('close', socketOnClose); + socket.on('data', socketOnData); + socket.on('end', socketOnEnd); + socket.on('error', socketOnError); + + this._readyState = WebSocket.OPEN; + this.emit('open'); + } + + /** + * Emit the `'close'` event. + * + * @private + */ + emitClose() { + if (!this._socket) { + this._readyState = WebSocket.CLOSED; + this.emit('close', this._closeCode, this._closeMessage); + return; + } + + if (this._extensions[PerMessageDeflate.extensionName]) { + this._extensions[PerMessageDeflate.extensionName].cleanup(); + } + + this._receiver.removeAllListeners(); + this._readyState = WebSocket.CLOSED; + this.emit('close', this._closeCode, this._closeMessage); + } + + /** + * Start a closing handshake. + * + * +----------+ +-----------+ +----------+ + * - - -|ws.close()|-->|close frame|-->|ws.close()|- - - + * | +----------+ +-----------+ +----------+ | + * +----------+ +-----------+ | + * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING + * +----------+ +-----------+ | + * | | | +---+ | + * +------------------------+-->|fin| - - - - + * | +---+ | +---+ + * - - - - -|fin|<---------------------+ + * +---+ + * + * @param {Number} [code] Status code explaining why the connection is closing + * @param {(String|Buffer)} [data] The reason why the connection is + * closing + * @public + */ + close(code, data) { + if (this.readyState === WebSocket.CLOSED) return; + if (this.readyState === WebSocket.CONNECTING) { + const msg = 'WebSocket was closed before the connection was established'; + abortHandshake(this, this._req, msg); + return; + } + + if (this.readyState === WebSocket.CLOSING) { + if ( + this._closeFrameSent && + (this._closeFrameReceived || this._receiver._writableState.errorEmitted) + ) { + this._socket.end(); + } + + return; + } + + this._readyState = WebSocket.CLOSING; + this._sender.close(code, data, !this._isServer, (err) => { + // + // This error is handled by the `'error'` listener on the socket. We only + // want to know if the close frame has been sent here. + // + if (err) return; + + this._closeFrameSent = true; + + if ( + this._closeFrameReceived || + this._receiver._writableState.errorEmitted + ) { + this._socket.end(); + } + }); + + // + // Specify a timeout for the closing handshake to complete. + // + this._closeTimer = setTimeout( + this._socket.destroy.bind(this._socket), + closeTimeout + ); + } + + /** + * Pause the socket. + * + * @public + */ + pause() { + if ( + this.readyState === WebSocket.CONNECTING || + this.readyState === WebSocket.CLOSED + ) { + return; + } + + this._paused = true; + this._socket.pause(); + } + + /** + * Send a ping. + * + * @param {*} [data] The data to send + * @param {Boolean} [mask] Indicates whether or not to mask `data` + * @param {Function} [cb] Callback which is executed when the ping is sent + * @public + */ + ping(data, mask, cb) { + if (this.readyState === WebSocket.CONNECTING) { + throw new Error('WebSocket is not open: readyState 0 (CONNECTING)'); + } + + if (typeof data === 'function') { + cb = data; + data = mask = undefined; + } else if (typeof mask === 'function') { + cb = mask; + mask = undefined; + } + + if (typeof data === 'number') data = data.toString(); + + if (this.readyState !== WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + + if (mask === undefined) mask = !this._isServer; + this._sender.ping(data || EMPTY_BUFFER, mask, cb); + } + + /** + * Send a pong. + * + * @param {*} [data] The data to send + * @param {Boolean} [mask] Indicates whether or not to mask `data` + * @param {Function} [cb] Callback which is executed when the pong is sent + * @public + */ + pong(data, mask, cb) { + if (this.readyState === WebSocket.CONNECTING) { + throw new Error('WebSocket is not open: readyState 0 (CONNECTING)'); + } + + if (typeof data === 'function') { + cb = data; + data = mask = undefined; + } else if (typeof mask === 'function') { + cb = mask; + mask = undefined; + } + + if (typeof data === 'number') data = data.toString(); + + if (this.readyState !== WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + + if (mask === undefined) mask = !this._isServer; + this._sender.pong(data || EMPTY_BUFFER, mask, cb); + } + + /** + * Resume the socket. + * + * @public + */ + resume() { + if ( + this.readyState === WebSocket.CONNECTING || + this.readyState === WebSocket.CLOSED + ) { + return; + } + + this._paused = false; + if (!this._receiver._writableState.needDrain) this._socket.resume(); + } + + /** + * Send a data message. + * + * @param {*} data The message to send + * @param {Object} [options] Options object + * @param {Boolean} [options.binary] Specifies whether `data` is binary or + * text + * @param {Boolean} [options.compress] Specifies whether or not to compress + * `data` + * @param {Boolean} [options.fin=true] Specifies whether the fragment is the + * last one + * @param {Boolean} [options.mask] Specifies whether or not to mask `data` + * @param {Function} [cb] Callback which is executed when data is written out + * @public + */ + send(data, options, cb) { + if (this.readyState === WebSocket.CONNECTING) { + throw new Error('WebSocket is not open: readyState 0 (CONNECTING)'); + } + + if (typeof options === 'function') { + cb = options; + options = {}; + } + + if (typeof data === 'number') data = data.toString(); + + if (this.readyState !== WebSocket.OPEN) { + sendAfterClose(this, data, cb); + return; + } + + const opts = { + binary: typeof data !== 'string', + mask: !this._isServer, + compress: true, + fin: true, + ...options + }; + + if (!this._extensions[PerMessageDeflate.extensionName]) { + opts.compress = false; + } + + this._sender.send(data || EMPTY_BUFFER, opts, cb); + } + + /** + * Forcibly close the connection. + * + * @public + */ + terminate() { + if (this.readyState === WebSocket.CLOSED) return; + if (this.readyState === WebSocket.CONNECTING) { + const msg = 'WebSocket was closed before the connection was established'; + abortHandshake(this, this._req, msg); + return; + } + + if (this._socket) { + this._readyState = WebSocket.CLOSING; + this._socket.destroy(); + } + } +} + +/** + * @constant {Number} CONNECTING + * @memberof WebSocket + */ +Object.defineProperty(WebSocket, 'CONNECTING', { + enumerable: true, + value: readyStates.indexOf('CONNECTING') +}); + +/** + * @constant {Number} CONNECTING + * @memberof WebSocket.prototype + */ +Object.defineProperty(WebSocket.prototype, 'CONNECTING', { + enumerable: true, + value: readyStates.indexOf('CONNECTING') +}); + +/** + * @constant {Number} OPEN + * @memberof WebSocket + */ +Object.defineProperty(WebSocket, 'OPEN', { + enumerable: true, + value: readyStates.indexOf('OPEN') +}); + +/** + * @constant {Number} OPEN + * @memberof WebSocket.prototype + */ +Object.defineProperty(WebSocket.prototype, 'OPEN', { + enumerable: true, + value: readyStates.indexOf('OPEN') +}); + +/** + * @constant {Number} CLOSING + * @memberof WebSocket + */ +Object.defineProperty(WebSocket, 'CLOSING', { + enumerable: true, + value: readyStates.indexOf('CLOSING') +}); + +/** + * @constant {Number} CLOSING + * @memberof WebSocket.prototype + */ +Object.defineProperty(WebSocket.prototype, 'CLOSING', { + enumerable: true, + value: readyStates.indexOf('CLOSING') +}); + +/** + * @constant {Number} CLOSED + * @memberof WebSocket + */ +Object.defineProperty(WebSocket, 'CLOSED', { + enumerable: true, + value: readyStates.indexOf('CLOSED') +}); + +/** + * @constant {Number} CLOSED + * @memberof WebSocket.prototype + */ +Object.defineProperty(WebSocket.prototype, 'CLOSED', { + enumerable: true, + value: readyStates.indexOf('CLOSED') +}); + +[ + 'binaryType', + 'bufferedAmount', + 'extensions', + 'isPaused', + 'protocol', + 'readyState', + 'url' +].forEach((property) => { + Object.defineProperty(WebSocket.prototype, property, { enumerable: true }); +}); + +// +// Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes. +// See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface +// +['open', 'error', 'close', 'message'].forEach((method) => { + Object.defineProperty(WebSocket.prototype, `on${method}`, { + enumerable: true, + get() { + for (const listener of this.listeners(method)) { + if (listener[kForOnEventAttribute]) return listener[kListener]; + } + + return null; + }, + set(handler) { + for (const listener of this.listeners(method)) { + if (listener[kForOnEventAttribute]) { + this.removeListener(method, listener); + break; + } + } + + if (typeof handler !== 'function') return; + + this.addEventListener(method, handler, { + [kForOnEventAttribute]: true + }); + } + }); +}); + +WebSocket.prototype.addEventListener = addEventListener; +WebSocket.prototype.removeEventListener = removeEventListener; + +module.exports = WebSocket; + +/** + * Initialize a WebSocket client. + * + * @param {WebSocket} websocket The client to initialize + * @param {(String|URL)} address The URL to which to connect + * @param {Array} protocols The subprotocols + * @param {Object} [options] Connection options + * @param {Boolean} [options.allowSynchronousEvents=false] Specifies whether any + * of the `'message'`, `'ping'`, and `'pong'` events can be emitted multiple + * times in the same tick + * @param {Boolean} [options.autoPong=true] Specifies whether or not to + * automatically send a pong in response to a ping + * @param {Function} [options.finishRequest] A function which can be used to + * customize the headers of each http request before it is sent + * @param {Boolean} [options.followRedirects=false] Whether or not to follow + * redirects + * @param {Function} [options.generateMask] The function used to generate the + * masking key + * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the + * handshake request + * @param {Number} [options.maxPayload=104857600] The maximum allowed message + * size + * @param {Number} [options.maxRedirects=10] The maximum number of redirects + * allowed + * @param {String} [options.origin] Value of the `Origin` or + * `Sec-WebSocket-Origin` header + * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable + * permessage-deflate + * @param {Number} [options.protocolVersion=13] Value of the + * `Sec-WebSocket-Version` header + * @param {Boolean} [options.skipUTF8Validation=false] Specifies whether or + * not to skip UTF-8 validation for text and close messages + * @private + */ +function initAsClient(websocket, address, protocols, options) { + const opts = { + allowSynchronousEvents: false, + autoPong: true, + protocolVersion: protocolVersions[1], + maxPayload: 100 * 1024 * 1024, + skipUTF8Validation: false, + perMessageDeflate: true, + followRedirects: false, + maxRedirects: 10, + ...options, + createConnection: undefined, + socketPath: undefined, + hostname: undefined, + protocol: undefined, + timeout: undefined, + method: 'GET', + host: undefined, + path: undefined, + port: undefined + }; + + websocket._autoPong = opts.autoPong; + + if (!protocolVersions.includes(opts.protocolVersion)) { + throw new RangeError( + `Unsupported protocol version: ${opts.protocolVersion} ` + + `(supported versions: ${protocolVersions.join(', ')})` + ); + } + + let parsedUrl; + + if (address instanceof URL) { + parsedUrl = address; + } else { + try { + parsedUrl = new URL(address); + } catch (e) { + throw new SyntaxError(`Invalid URL: ${address}`); + } + } + + if (parsedUrl.protocol === 'http:') { + parsedUrl.protocol = 'ws:'; + } else if (parsedUrl.protocol === 'https:') { + parsedUrl.protocol = 'wss:'; + } + + websocket._url = parsedUrl.href; + + const isSecure = parsedUrl.protocol === 'wss:'; + const isIpcUrl = parsedUrl.protocol === 'ws+unix:'; + let invalidUrlMessage; + + if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) { + invalidUrlMessage = + 'The URL\'s protocol must be one of "ws:", "wss:", ' + + '"http:", "https", or "ws+unix:"'; + } else if (isIpcUrl && !parsedUrl.pathname) { + invalidUrlMessage = "The URL's pathname is empty"; + } else if (parsedUrl.hash) { + invalidUrlMessage = 'The URL contains a fragment identifier'; + } + + if (invalidUrlMessage) { + const err = new SyntaxError(invalidUrlMessage); + + if (websocket._redirects === 0) { + throw err; + } else { + emitErrorAndClose(websocket, err); + return; + } + } + + const defaultPort = isSecure ? 443 : 80; + const key = randomBytes(16).toString('base64'); + const request = isSecure ? https.request : http.request; + const protocolSet = new Set(); + let perMessageDeflate; + + opts.createConnection = isSecure ? tlsConnect : netConnect; + opts.defaultPort = opts.defaultPort || defaultPort; + opts.port = parsedUrl.port || defaultPort; + opts.host = parsedUrl.hostname.startsWith('[') + ? parsedUrl.hostname.slice(1, -1) + : parsedUrl.hostname; + opts.headers = { + ...opts.headers, + 'Sec-WebSocket-Version': opts.protocolVersion, + 'Sec-WebSocket-Key': key, + Connection: 'Upgrade', + Upgrade: 'websocket' + }; + opts.path = parsedUrl.pathname + parsedUrl.search; + opts.timeout = opts.handshakeTimeout; + + if (opts.perMessageDeflate) { + perMessageDeflate = new PerMessageDeflate( + opts.perMessageDeflate !== true ? opts.perMessageDeflate : {}, + false, + opts.maxPayload + ); + opts.headers['Sec-WebSocket-Extensions'] = format({ + [PerMessageDeflate.extensionName]: perMessageDeflate.offer() + }); + } + if (protocols.length) { + for (const protocol of protocols) { + if ( + typeof protocol !== 'string' || + !subprotocolRegex.test(protocol) || + protocolSet.has(protocol) + ) { + throw new SyntaxError( + 'An invalid or duplicated subprotocol was specified' + ); + } + + protocolSet.add(protocol); + } + + opts.headers['Sec-WebSocket-Protocol'] = protocols.join(','); + } + if (opts.origin) { + if (opts.protocolVersion < 13) { + opts.headers['Sec-WebSocket-Origin'] = opts.origin; + } else { + opts.headers.Origin = opts.origin; + } + } + if (parsedUrl.username || parsedUrl.password) { + opts.auth = `${parsedUrl.username}:${parsedUrl.password}`; + } + + if (isIpcUrl) { + const parts = opts.path.split(':'); + + opts.socketPath = parts[0]; + opts.path = parts[1]; + } + + let req; + + if (opts.followRedirects) { + if (websocket._redirects === 0) { + websocket._originalIpc = isIpcUrl; + websocket._originalSecure = isSecure; + websocket._originalHostOrSocketPath = isIpcUrl + ? opts.socketPath + : parsedUrl.host; + + const headers = options && options.headers; + + // + // Shallow copy the user provided options so that headers can be changed + // without mutating the original object. + // + options = { ...options, headers: {} }; + + if (headers) { + for (const [key, value] of Object.entries(headers)) { + options.headers[key.toLowerCase()] = value; + } + } + } else if (websocket.listenerCount('redirect') === 0) { + const isSameHost = isIpcUrl + ? websocket._originalIpc + ? opts.socketPath === websocket._originalHostOrSocketPath + : false + : websocket._originalIpc + ? false + : parsedUrl.host === websocket._originalHostOrSocketPath; + + if (!isSameHost || (websocket._originalSecure && !isSecure)) { + // + // Match curl 7.77.0 behavior and drop the following headers. These + // headers are also dropped when following a redirect to a subdomain. + // + delete opts.headers.authorization; + delete opts.headers.cookie; + + if (!isSameHost) delete opts.headers.host; + + opts.auth = undefined; + } + } + + // + // Match curl 7.77.0 behavior and make the first `Authorization` header win. + // If the `Authorization` header is set, then there is nothing to do as it + // will take precedence. + // + if (opts.auth && !options.headers.authorization) { + options.headers.authorization = + 'Basic ' + Buffer.from(opts.auth).toString('base64'); + } + + req = websocket._req = request(opts); + + if (websocket._redirects) { + // + // Unlike what is done for the `'upgrade'` event, no early exit is + // triggered here if the user calls `websocket.close()` or + // `websocket.terminate()` from a listener of the `'redirect'` event. This + // is because the user can also call `request.destroy()` with an error + // before calling `websocket.close()` or `websocket.terminate()` and this + // would result in an error being emitted on the `request` object with no + // `'error'` event listeners attached. + // + websocket.emit('redirect', websocket.url, req); + } + } else { + req = websocket._req = request(opts); + } + + if (opts.timeout) { + req.on('timeout', () => { + abortHandshake(websocket, req, 'Opening handshake has timed out'); + }); + } + + req.on('error', (err) => { + if (req === null || req[kAborted]) return; + + req = websocket._req = null; + emitErrorAndClose(websocket, err); + }); + + req.on('response', (res) => { + const location = res.headers.location; + const statusCode = res.statusCode; + + if ( + location && + opts.followRedirects && + statusCode >= 300 && + statusCode < 400 + ) { + if (++websocket._redirects > opts.maxRedirects) { + abortHandshake(websocket, req, 'Maximum redirects exceeded'); + return; + } + + req.abort(); + + let addr; + + try { + addr = new URL(location, address); + } catch (e) { + const err = new SyntaxError(`Invalid URL: ${location}`); + emitErrorAndClose(websocket, err); + return; + } + + initAsClient(websocket, addr, protocols, options); + } else if (!websocket.emit('unexpected-response', req, res)) { + abortHandshake( + websocket, + req, + `Unexpected server response: ${res.statusCode}` + ); + } + }); + + req.on('upgrade', (res, socket, head) => { + websocket.emit('upgrade', res); + + // + // The user may have closed the connection from a listener of the + // `'upgrade'` event. + // + if (websocket.readyState !== WebSocket.CONNECTING) return; + + req = websocket._req = null; + + if (res.headers.upgrade.toLowerCase() !== 'websocket') { + abortHandshake(websocket, socket, 'Invalid Upgrade header'); + return; + } + + const digest = createHash('sha1') + .update(key + GUID) + .digest('base64'); + + if (res.headers['sec-websocket-accept'] !== digest) { + abortHandshake(websocket, socket, 'Invalid Sec-WebSocket-Accept header'); + return; + } + + const serverProt = res.headers['sec-websocket-protocol']; + let protError; + + if (serverProt !== undefined) { + if (!protocolSet.size) { + protError = 'Server sent a subprotocol but none was requested'; + } else if (!protocolSet.has(serverProt)) { + protError = 'Server sent an invalid subprotocol'; + } + } else if (protocolSet.size) { + protError = 'Server sent no subprotocol'; + } + + if (protError) { + abortHandshake(websocket, socket, protError); + return; + } + + if (serverProt) websocket._protocol = serverProt; + + const secWebSocketExtensions = res.headers['sec-websocket-extensions']; + + if (secWebSocketExtensions !== undefined) { + if (!perMessageDeflate) { + const message = + 'Server sent a Sec-WebSocket-Extensions header but no extension ' + + 'was requested'; + abortHandshake(websocket, socket, message); + return; + } + + let extensions; + + try { + extensions = parse(secWebSocketExtensions); + } catch (err) { + const message = 'Invalid Sec-WebSocket-Extensions header'; + abortHandshake(websocket, socket, message); + return; + } + + const extensionNames = Object.keys(extensions); + + if ( + extensionNames.length !== 1 || + extensionNames[0] !== PerMessageDeflate.extensionName + ) { + const message = 'Server indicated an extension that was not requested'; + abortHandshake(websocket, socket, message); + return; + } + + try { + perMessageDeflate.accept(extensions[PerMessageDeflate.extensionName]); + } catch (err) { + const message = 'Invalid Sec-WebSocket-Extensions header'; + abortHandshake(websocket, socket, message); + return; + } + + websocket._extensions[PerMessageDeflate.extensionName] = + perMessageDeflate; + } + + websocket.setSocket(socket, head, { + allowSynchronousEvents: opts.allowSynchronousEvents, + generateMask: opts.generateMask, + maxPayload: opts.maxPayload, + skipUTF8Validation: opts.skipUTF8Validation + }); + }); + + if (opts.finishRequest) { + opts.finishRequest(req, websocket); + } else { + req.end(); + } +} + +/** + * Emit the `'error'` and `'close'` events. + * + * @param {WebSocket} websocket The WebSocket instance + * @param {Error} The error to emit + * @private + */ +function emitErrorAndClose(websocket, err) { + websocket._readyState = WebSocket.CLOSING; + websocket.emit('error', err); + websocket.emitClose(); +} + +/** + * Create a `net.Socket` and initiate a connection. + * + * @param {Object} options Connection options + * @return {net.Socket} The newly created socket used to start the connection + * @private + */ +function netConnect(options) { + options.path = options.socketPath; + return net.connect(options); +} + +/** + * Create a `tls.TLSSocket` and initiate a connection. + * + * @param {Object} options Connection options + * @return {tls.TLSSocket} The newly created socket used to start the connection + * @private + */ +function tlsConnect(options) { + options.path = undefined; + + if (!options.servername && options.servername !== '') { + options.servername = net.isIP(options.host) ? '' : options.host; + } + + return tls.connect(options); +} + +/** + * Abort the handshake and emit an error. + * + * @param {WebSocket} websocket The WebSocket instance + * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to + * abort or the socket to destroy + * @param {String} message The error message + * @private + */ +function abortHandshake(websocket, stream, message) { + websocket._readyState = WebSocket.CLOSING; + + const err = new Error(message); + Error.captureStackTrace(err, abortHandshake); + + if (stream.setHeader) { + stream[kAborted] = true; + stream.abort(); + + if (stream.socket && !stream.socket.destroyed) { + // + // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if + // called after the request completed. See + // https://github.com/websockets/ws/issues/1869. + // + stream.socket.destroy(); + } + + process.nextTick(emitErrorAndClose, websocket, err); + } else { + stream.destroy(err); + stream.once('error', websocket.emit.bind(websocket, 'error')); + stream.once('close', websocket.emitClose.bind(websocket)); + } +} + +/** + * Handle cases where the `ping()`, `pong()`, or `send()` methods are called + * when the `readyState` attribute is `CLOSING` or `CLOSED`. + * + * @param {WebSocket} websocket The WebSocket instance + * @param {*} [data] The data to send + * @param {Function} [cb] Callback + * @private + */ +function sendAfterClose(websocket, data, cb) { + if (data) { + const length = toBuffer(data).length; + + // + // The `_bufferedAmount` property is used only when the peer is a client and + // the opening handshake fails. Under these circumstances, in fact, the + // `setSocket()` method is not called, so the `_socket` and `_sender` + // properties are set to `null`. + // + if (websocket._socket) websocket._sender._bufferedBytes += length; + else websocket._bufferedAmount += length; + } + + if (cb) { + const err = new Error( + `WebSocket is not open: readyState ${websocket.readyState} ` + + `(${readyStates[websocket.readyState]})` + ); + process.nextTick(cb, err); + } +} + +/** + * The listener of the `Receiver` `'conclude'` event. + * + * @param {Number} code The status code + * @param {Buffer} reason The reason for closing + * @private + */ +function receiverOnConclude(code, reason) { + const websocket = this[kWebSocket]; + + websocket._closeFrameReceived = true; + websocket._closeMessage = reason; + websocket._closeCode = code; + + if (websocket._socket[kWebSocket] === undefined) return; + + websocket._socket.removeListener('data', socketOnData); + process.nextTick(resume, websocket._socket); + + if (code === 1005) websocket.close(); + else websocket.close(code, reason); +} + +/** + * The listener of the `Receiver` `'drain'` event. + * + * @private + */ +function receiverOnDrain() { + const websocket = this[kWebSocket]; + + if (!websocket.isPaused) websocket._socket.resume(); +} + +/** + * The listener of the `Receiver` `'error'` event. + * + * @param {(RangeError|Error)} err The emitted error + * @private + */ +function receiverOnError(err) { + const websocket = this[kWebSocket]; + + if (websocket._socket[kWebSocket] !== undefined) { + websocket._socket.removeListener('data', socketOnData); + + // + // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See + // https://github.com/websockets/ws/issues/1940. + // + process.nextTick(resume, websocket._socket); + + websocket.close(err[kStatusCode]); + } + + websocket.emit('error', err); +} + +/** + * The listener of the `Receiver` `'finish'` event. + * + * @private + */ +function receiverOnFinish() { + this[kWebSocket].emitClose(); +} + +/** + * The listener of the `Receiver` `'message'` event. + * + * @param {Buffer|ArrayBuffer|Buffer[])} data The message + * @param {Boolean} isBinary Specifies whether the message is binary or not + * @private + */ +function receiverOnMessage(data, isBinary) { + this[kWebSocket].emit('message', data, isBinary); +} + +/** + * The listener of the `Receiver` `'ping'` event. + * + * @param {Buffer} data The data included in the ping frame + * @private + */ +function receiverOnPing(data) { + const websocket = this[kWebSocket]; + + if (websocket._autoPong) websocket.pong(data, !this._isServer, NOOP); + websocket.emit('ping', data); +} + +/** + * The listener of the `Receiver` `'pong'` event. + * + * @param {Buffer} data The data included in the pong frame + * @private + */ +function receiverOnPong(data) { + this[kWebSocket].emit('pong', data); +} + +/** + * Resume a readable stream + * + * @param {Readable} stream The readable stream + * @private + */ +function resume(stream) { + stream.resume(); +} + +/** + * The listener of the socket `'close'` event. + * + * @private + */ +function socketOnClose() { + const websocket = this[kWebSocket]; + + this.removeListener('close', socketOnClose); + this.removeListener('data', socketOnData); + this.removeListener('end', socketOnEnd); + + websocket._readyState = WebSocket.CLOSING; + + let chunk; + + // + // The close frame might not have been received or the `'end'` event emitted, + // for example, if the socket was destroyed due to an error. Ensure that the + // `receiver` stream is closed after writing any remaining buffered data to + // it. If the readable side of the socket is in flowing mode then there is no + // buffered data as everything has been already written and `readable.read()` + // will return `null`. If instead, the socket is paused, any possible buffered + // data will be read as a single chunk. + // + if ( + !this._readableState.endEmitted && + !websocket._closeFrameReceived && + !websocket._receiver._writableState.errorEmitted && + (chunk = websocket._socket.read()) !== null + ) { + websocket._receiver.write(chunk); + } + + websocket._receiver.end(); + + this[kWebSocket] = undefined; + + clearTimeout(websocket._closeTimer); + + if ( + websocket._receiver._writableState.finished || + websocket._receiver._writableState.errorEmitted + ) { + websocket.emitClose(); + } else { + websocket._receiver.on('error', receiverOnFinish); + websocket._receiver.on('finish', receiverOnFinish); + } +} + +/** + * The listener of the socket `'data'` event. + * + * @param {Buffer} chunk A chunk of data + * @private + */ +function socketOnData(chunk) { + if (!this[kWebSocket]._receiver.write(chunk)) { + this.pause(); + } +} + +/** + * The listener of the socket `'end'` event. + * + * @private + */ +function socketOnEnd() { + const websocket = this[kWebSocket]; + + websocket._readyState = WebSocket.CLOSING; + websocket._receiver.end(); + this.end(); +} + +/** + * The listener of the socket `'error'` event. + * + * @private + */ +function socketOnError() { + const websocket = this[kWebSocket]; + + this.removeListener('error', socketOnError); + this.on('error', NOOP); + + if (websocket) { + websocket._readyState = WebSocket.CLOSING; + this.destroy(); + } +} diff --git a/system/clearpilot/shell/node_modules/ws/package.json b/system/clearpilot/shell/node_modules/ws/package.json new file mode 100644 index 0000000..a244320 --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/package.json @@ -0,0 +1,68 @@ +{ + "name": "ws", + "version": "8.16.0", + "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js", + "keywords": [ + "HyBi", + "Push", + "RFC-6455", + "WebSocket", + "WebSockets", + "real-time" + ], + "homepage": "https://github.com/websockets/ws", + "bugs": "https://github.com/websockets/ws/issues", + "repository": { + "type": "git", + "url": "git+https://github.com/websockets/ws.git" + }, + "author": "Einar Otto Stangvik (http://2x.io)", + "license": "MIT", + "main": "index.js", + "exports": { + ".": { + "browser": "./browser.js", + "import": "./wrapper.mjs", + "require": "./index.js" + }, + "./package.json": "./package.json" + }, + "browser": "browser.js", + "engines": { + "node": ">=10.0.0" + }, + "files": [ + "browser.js", + "index.js", + "lib/*.js", + "wrapper.mjs" + ], + "scripts": { + "test": "nyc --reporter=lcov --reporter=text mocha --throw-deprecation test/*.test.js", + "integration": "mocha --throw-deprecation test/*.integration.js", + "lint": "eslint --ignore-path .gitignore . && prettier --check --ignore-path .gitignore \"**/*.{json,md,yaml,yml}\"" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + }, + "devDependencies": { + "benchmark": "^2.1.4", + "bufferutil": "^4.0.1", + "eslint": "^8.0.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", + "mocha": "^8.4.0", + "nyc": "^15.0.0", + "prettier": "^3.0.0", + "utf-8-validate": "^6.0.0" + } +} diff --git a/system/clearpilot/shell/node_modules/ws/wrapper.mjs b/system/clearpilot/shell/node_modules/ws/wrapper.mjs new file mode 100644 index 0000000..7245ad1 --- /dev/null +++ b/system/clearpilot/shell/node_modules/ws/wrapper.mjs @@ -0,0 +1,8 @@ +import createWebSocketStream from './lib/stream.js'; +import Receiver from './lib/receiver.js'; +import Sender from './lib/sender.js'; +import WebSocket from './lib/websocket.js'; +import WebSocketServer from './lib/websocket-server.js'; + +export { createWebSocketStream, Receiver, Sender, WebSocket, WebSocketServer }; +export default WebSocket; diff --git a/system/clearpilot/shell/package-lock.json b/system/clearpilot/shell/package-lock.json new file mode 100644 index 0000000..6f750c4 --- /dev/null +++ b/system/clearpilot/shell/package-lock.json @@ -0,0 +1,38 @@ +{ + "name": "shell", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "http": "^0.0.1-security", + "ws": "^8.16.0" + } + }, + "node_modules/http": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/http/-/http-0.0.1-security.tgz", + "integrity": "sha512-RnDvP10Ty9FxqOtPZuxtebw1j4L/WiqNMDtuc1YMH1XQm5TgDRaR1G9u8upL6KD1bXHSp9eSXo/ED+8Q7FAr+g==" + }, + "node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/system/clearpilot/shell/package.json b/system/clearpilot/shell/package.json new file mode 100644 index 0000000..6c6421c --- /dev/null +++ b/system/clearpilot/shell/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "http": "^0.0.1-security", + "ws": "^8.16.0" + } +} diff --git a/system/clearpilot/shell/revert_logo.sh b/system/clearpilot/shell/revert_logo.sh new file mode 100644 index 0000000..a50b2ed --- /dev/null +++ b/system/clearpilot/shell/revert_logo.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Check if /data/openpilot/shell/bg.jpg does not exist +if [ ! -f /data/openpilot/shell/bg.jpg ]; then + # Check if /usr/comma/bg.org does exist + if [ -f /usr/comma/bg.org ]; then + sudo mount -o remount,rw / + # Copy /usr/comma/bg.org to /usr/comma/bg.jpg + sudo mv -f /usr/comma/bg.org /usr/comma/bg.jpg + # Remove /usr/comma/bg.org + # sudo rm /usr/comma/bg.org + if [ -f /usr/comma/comma.org ]; then + sudo mv -f /usr/comma/comma.org /usr/comma/comma.sh + fi + echo Reverted custom logo for comma boot sequence + sudo sync + sleep 2 + sudo reboot + while true; do + sleep 1 + done + fi +fi \ No newline at end of file diff --git a/system/clearpilot/shell/set_logo.sh b/system/clearpilot/shell/set_logo.sh new file mode 100644 index 0000000..e0cc12e --- /dev/null +++ b/system/clearpilot/shell/set_logo.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +set -x + +# Test: sudo mount -o remount,rw /; cp /usr/comma/bg.org /usr/comma/bg.jpg; bash shell/set_logo.sh + +# Check if md5sum of /usr/comma/bg.jpg is not equal to md5sum of /data/openpilot/shell/bg.jpg +if [ "$(md5sum /usr/comma/bg.jpg | awk '{print $1}')" != "$(md5sum /data/openpilot/shell/bg.jpg | awk '{print $1}')" ]; then + + # If /usr/comma/bg.org does not exist + if [ ! -f /usr/comma/bg.org ]; then + if [[ "$(md5sum /usr/comma/bg.jpg | awk '{print $1}')" == "642380ba4c0f00b16e9cf6e613f43eec" ]]; then + sudo mount -o remount,rw / + sudo cp /usr/comma/bg.jpg /usr/comma/bg.org + fi + fi + + if [[ "$(md5sum /usr/comma/bg.org | awk '{print $1}')" != "642380ba4c0f00b16e9cf6e613f43eec" ]]; then + sudo mount -o remount,ro / + echo failed to backup the correct picture + exit + fi + + sudo mount -o remount,rw / + + # If /usr/comma/bg.org does exist + if [ -f /usr/comma/bg.org ]; then + sudo cp -f /data/openpilot/shell/bg.jpg /usr/comma/bg.jpg + fi + + # If file /usr/comma/revert_logo.sh does not exist + if [ "$(md5sum /data/openpilot/shell/revert_logo.sh | awk '{print $1}')" != "$(md5sum /usr/comma/revert_logo.sh | awk '{print $1}')" ]; then + sudo cp /data/openpilot/shell/revert_logo.sh /usr/comma/revert_logo.sh + fi + + if [ "$(md5sum md5sum /usr/comma/comma.sh | awk '{print $1}')" != "$(md5sum /data/openpilot/shell/usr_comma_comma.sh | awk '{print $1}')" ]; then + if [[ "$(md5sum /usr/comma/comma.sh | awk '{print $1}')" == "ddbac0b46dd02efd672a0ef31ca426cf" ]]; then + if [ ! -f /usr/comma/comma.org ]; then + sudo cp /usr/comma/comma.sh /usr/comma/comma.org + fi + fi + if [-f /usr/comma/comma.org ]; then + sudo cp /data/openpilot/shell/usr_comma_comma.sh /usr/comma/comma.sh + echo updated comma.sh + fi + fi + + echo Applied custom logo for comma boot sequence + sudo sync + sleep 2 + sudo mount -o remount,ro / + sudo sync + sleep 2 +fi diff --git a/system/clearpilot/shell/usr_comma_comma.sh b/system/clearpilot/shell/usr_comma_comma.sh new file mode 100644 index 0000000..beeb74a --- /dev/null +++ b/system/clearpilot/shell/usr_comma_comma.sh @@ -0,0 +1,95 @@ +#/usr/bin/env bash + +source /etc/profile + +SETUP="/usr/comma/setup" +RESET="/usr/comma/reset" +CONTINUE="/data/continue.sh" +INSTALLER="/tmp/installer" +RESET_TRIGGER="/data/__system_reset__" + +echo "waiting for weston" +for i in {1..200}; do + if systemctl is-active --quiet weston-ready; then + break + fi + sleep 0.1 +done + +if systemctl is-active --quiet weston-ready; then + echo "weston ready after ${SECONDS}s" +else + echo "timed out waiting for weston, ${SECONDS}s" +fi + +sudo chown comma: /data +sudo chown comma: /data/media + +handle_setup_keys () { + # install default SSH key while still in setup + if [[ ! -e /data/params/d/GithubSshKeys && ! -e /data/continue.sh ]]; then + if [ ! -e /data/params/d ]; then + mkdir -p /data/params/d_tmp + ln -s /data/params/d_tmp /data/params/d + fi + + echo -n 1 > /data/params/d/SshEnabled + cp /usr/comma/setup_keys /data/params/d/GithubSshKeys + elif [[ -e /data/params/d/GithubSshKeys && -e /data/continue.sh ]]; then + if cmp -s /data/params/d/GithubSshKeys /usr/comma/setup_keys; then + rm /data/params/d/SshEnabled + rm /data/params/d/GithubSshKeys + fi + fi +} + +# factory reset handling +if [ -f "$RESET_TRIGGER" ]; then + echo "launching system reset, reset trigger present" + rm -f $RESET_TRIGGER + $RESET +elif ! mountpoint -q /data; then + echo "userdata not mounted. loading system reset" + if [ "$(head -c 15 /dev/disk/by-partlabel/userdata)" == "COMMA_ABL_RESET" ]; then + $RESET --format + else + $RESET --recover + fi +fi + +# symlink vscode to userdata +mkdir -p /data/tmp/vscode-server +ln -s /data/tmp/vscode-server ~/.vscode-server + +# Check to see if the comma logo should be reverted +bash /usr/comma/revert_logo.sh + +while true; do + pkill -f "$SETUP" + handle_setup_keys + + if [ -f $CONTINUE ]; then + exec "$CONTINUE" + fi + + sudo abctl --set_success + + # cleanup installers from previous runs + rm -f $INSTALLER + pkill -f $INSTALLER + + # run setup and wait for installer + $SETUP & + echo "waiting for installer" + while [ ! -f $INSTALLER ]; do + sleep 1 + done + + # run installer and wait for continue.sh + chmod +x $INSTALLER + $INSTALLER & + echo "running installer" + while [ ! -f $CONTINUE ] && ps -p $! > /dev/null; do + sleep 1 + done +done \ No newline at end of file diff --git a/system/clearpilot/shell/watcher.example.py b/system/clearpilot/shell/watcher.example.py new file mode 100644 index 0000000..91fdfbb --- /dev/null +++ b/system/clearpilot/shell/watcher.example.py @@ -0,0 +1,32 @@ +import socket +import json + +# Initialize the socket without connecting +sock = None + +def ensure_socket_connected(): + global sock + if sock is None or sock.fileno() == -1: # Checks if socket is not initialized or closed + try: + # Attempt to initialize and connect the socket + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect("/tmp/oscar_watcher.sock") + except socket.error: + # If connection fails, set sock to None and do nothing + sock = None + +def log_watch(var_name, message): + ensure_socket_connected() # Ensure the socket is connected before attempting to log + if sock: # Proceed only if sock is not None (i.e., is connected) + message_json = json.dumps(message) + try: + sock.sendall(message_json.encode('utf-8') + b'\n') + except socket.error: + # Handle potential error in sending (e.g., if connection was lost) + global sock + sock.close() # Close the current socket to clean up resources + sock = None # Reset sock to ensure reconnection attempt on next call + +#message = {"variable": "car_stats", "value": {"car_lights_on": [3, 5, 7], "car_state": "on"}} +#log_watch(sock, message) + diff --git a/system/clearpilot/shell/watcher.html b/system/clearpilot/shell/watcher.html new file mode 100644 index 0000000..add68ad --- /dev/null +++ b/system/clearpilot/shell/watcher.html @@ -0,0 +1,42 @@ + + + + + WebSocket Test + + + + +