From 028b6e5664f8c0461be2ea7bc372d86be94705a1 Mon Sep 17 00:00:00 2001 From: Rick Lan Date: Thu, 21 Aug 2025 12:30:31 +0800 Subject: [PATCH] feat: Squash all core features into min --- .vscode/extensions.json | 3 + .vscode/settings.json | 17 +- LICENSE.md | 30 ++ common/params_keys.h | 4 +- dragonpilot/.gitignore | 0 dragonpilot/selfdrive/assets/.gitignore | 0 dragonpilot/selfdrive/assets/dragonpilot.png | Bin 0 -> 21118 bytes .../selfdrive/assets/icons/icon_empty.svg | 35 +++ .../selfdrive/assets/icons/icon_minus.png | Bin 0 -> 2577 bytes .../selfdrive/assets/icons/icon_plus.png | Bin 0 -> 2833 bytes .../selfdrive/assets/images/spinner_comma.png | Bin 0 -> 88317 bytes .../selfdrive/assets/offroad/icon_plus.png | Bin 0 -> 2833 bytes dragonpilot/selfdrive/controls/.gitignore | 0 dragonpilot/selfdrive/controls/lib/.gitignore | 0 dragonpilot/selfdrive/ui/.gitignore | 0 opendbc_repo/opendbc/car/body/interface.py | 2 +- opendbc_repo/opendbc/car/car_helpers.py | 4 +- .../opendbc/car/chrysler/interface.py | 2 +- opendbc_repo/opendbc/car/docs.py | 2 +- opendbc_repo/opendbc/car/ford/interface.py | 2 +- opendbc_repo/opendbc/car/gm/interface.py | 2 +- opendbc_repo/opendbc/car/honda/interface.py | 2 +- opendbc_repo/opendbc/car/hyundai/interface.py | 2 +- .../opendbc/car/hyundai/tests/test_hyundai.py | 6 +- opendbc_repo/opendbc/car/interfaces.py | 8 +- opendbc_repo/opendbc/car/mazda/interface.py | 2 +- opendbc_repo/opendbc/car/mock/interface.py | 2 +- opendbc_repo/opendbc/car/nissan/interface.py | 2 +- opendbc_repo/opendbc/car/psa/interface.py | 2 +- opendbc_repo/opendbc/car/rivian/interface.py | 2 +- opendbc_repo/opendbc/car/structs.py | 3 + opendbc_repo/opendbc/car/subaru/interface.py | 2 +- opendbc_repo/opendbc/car/tesla/interface.py | 2 +- .../opendbc/car/tests/test_car_interfaces.py | 2 +- opendbc_repo/opendbc/car/toyota/interface.py | 2 +- .../opendbc/car/volkswagen/interface.py | 2 +- selfdrive/car/card.py | 4 +- selfdrive/car/cruise.py | 2 +- selfdrive/car/tests/test_car_interfaces.py | 2 +- selfdrive/car/tests/test_models.py | 2 +- .../controls/lib/longitudinal_planner.py | 4 +- selfdrive/controls/plannerd.py | 6 +- selfdrive/selfdrived/selfdrived.py | 2 +- selfdrive/ui/SConscript | 2 +- selfdrive/ui/qt/offroad/developer_panel.cc | 15 + selfdrive/ui/qt/offroad/dp_panel.cc | 295 ++++++++++++++++++ selfdrive/ui/qt/offroad/dp_panel.h | 31 ++ selfdrive/ui/qt/offroad/settings.cc | 30 +- selfdrive/ui/qt/offroad/software_settings.cc | 4 +- selfdrive/ui/qt/onroad/buttons.cc | 2 +- selfdrive/ui/qt/sidebar.cc | 2 +- selfdrive/ui/qt/util.cc | 4 +- selfdrive/ui/qt/widgets/controls.h | 137 ++++++++ system/manager/manager.py | 4 +- system/manager/process_config.py | 2 +- system/sentry.py | 9 +- system/ui/spinner.py | 2 +- 57 files changed, 651 insertions(+), 54 deletions(-) create mode 100644 LICENSE.md create mode 100644 dragonpilot/.gitignore create mode 100644 dragonpilot/selfdrive/assets/.gitignore create mode 100644 dragonpilot/selfdrive/assets/dragonpilot.png create mode 100644 dragonpilot/selfdrive/assets/icons/icon_empty.svg create mode 100644 dragonpilot/selfdrive/assets/icons/icon_minus.png create mode 100644 dragonpilot/selfdrive/assets/icons/icon_plus.png create mode 100644 dragonpilot/selfdrive/assets/images/spinner_comma.png create mode 100644 dragonpilot/selfdrive/assets/offroad/icon_plus.png create mode 100644 dragonpilot/selfdrive/controls/.gitignore create mode 100644 dragonpilot/selfdrive/controls/lib/.gitignore create mode 100644 dragonpilot/selfdrive/ui/.gitignore create mode 100644 selfdrive/ui/qt/offroad/dp_panel.cc create mode 100644 selfdrive/ui/qt/offroad/dp_panel.h diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 458312fc8..03ba8b0b6 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -4,5 +4,8 @@ "ms-vscode.cpptools", "elagil.pre-commit-helper", "charliermarsh.ruff", + "JamiTech.simply-blame", + "k--kato.intellij-idea-keybindings", + "trinm1709.dracula-theme-from-intellij" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index f0731c362..c62cc3df5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,10 +3,25 @@ "editor.insertSpaces": true, "editor.renderWhitespace": "trailing", "files.trimTrailingWhitespace": true, + "terminal.integrated.defaultProfile.linux": "dragonpilot", + "terminal.integrated.profiles.linux": { + "dragonpilot": { + "path": "bash", + "args": ["-c", "distrobox enter dp"] + } + }, "search.exclude": { "**/.git": true, "**/.venv": true, - "**/__pycache__": true + "**/__pycache__": true, + "msgq_repo/": true, + "opendbc/": true, + "rednose/": true, + "rednose_repo/": true, + "openpilot/": true, + "teleoprtc_repo/": true, + "tinygrad/": true, + "tinygrad_repo/": true }, "files.exclude": { "**/.git": true, diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 000000000..abeb9f075 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,30 @@ +Copyright (c) 2019, Rick Lan + +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, and/or sublicense, +for non-commercial purposes only, 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. +- Commercial use (e.g. use in a product, service, or activity intended to + generate revenue) is prohibited without explicit written permission from + the copyright holder. + +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. + +--- +Copyright (c) 2018, Comma.ai, Inc. + +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/common/params_keys.h b/common/params_keys.h index c54600462..3167df8b1 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -28,7 +28,7 @@ inline static std::unordered_map keys = { {"ControlsReady", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}}, {"CurrentBootlog", {PERSISTENT, STRING}}, {"CurrentRoute", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, STRING}}, - {"DisableLogging", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}}, + {"DisableLogging", {PERSISTENT, BOOL, "0"}}, {"DisablePowerDown", {PERSISTENT, BOOL}}, {"DisableUpdates", {PERSISTENT, BOOL}}, {"DisengageOnAccelerator", {PERSISTENT, BOOL, "0"}}, @@ -129,4 +129,6 @@ inline static std::unordered_map keys = { {"UptimeOffroad", {PERSISTENT, FLOAT, "0.0"}}, {"UptimeOnroad", {PERSISTENT, FLOAT, "0.0"}}, {"Version", {PERSISTENT, STRING}}, + {"dp_device_last_log", {CLEAR_ON_ONROAD_TRANSITION, STRING}}, + {"dp_device_reset_conf", {CLEAR_ON_MANAGER_START, BOOL}}, }; diff --git a/dragonpilot/.gitignore b/dragonpilot/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/dragonpilot/selfdrive/assets/.gitignore b/dragonpilot/selfdrive/assets/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/dragonpilot/selfdrive/assets/dragonpilot.png b/dragonpilot/selfdrive/assets/dragonpilot.png new file mode 100644 index 0000000000000000000000000000000000000000..1001f19426b496dacb62c591ac430500dbb8087e GIT binary patch literal 21118 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 + + + + diff --git a/dragonpilot/selfdrive/assets/icons/icon_minus.png b/dragonpilot/selfdrive/assets/icons/icon_minus.png new file mode 100644 index 0000000000000000000000000000000000000000..e5327c0d3b2d48433078ceef273122318d8c8860 GIT binary patch literal 2577 zcmV+s3hwoZP)yP$Ou!_AX?FxFZ7cI1)RWAis3cd9o zuol<$)`AuEsG!H5>|GQTv=@a|(1KnRe^F>xt1DHPwN)$I=Lvbo$z+mmCdqtB`sIb$ z%#U~8_n9Y?$z(G5c4){VGcz-15iVJZhGyxRP@2)x5}yT;_^?E>lv&O)$Xv#wnoKd# zOXx{?=%vhZ*j>v%Y@oBego+C^>$kPI9$hL4uQs64xK{<$Xhy_k&hbd146UA<)AGX! zWj%pPYqg5I^)hQ5%Bv8bAbe^nDBQGY7D`&$=gdyT3=EElg}fv5rf223H!FK}H1-)? zY<=cMfANL!y>2=$?nRydNzq;FZICmkms{hgG{TAwve#+=nF_Wj(3r#v9M=H-MX9HZ zmozH&qNC8`e0CDG9TIXOta8xxRv{C-aGs#%9J97G&CIu@VdG`wKQ+sEp?zj%GEL8} z0`-((+6c;d(B7iPpP1t{Y)%Pzq@OE=+%yQjr;+!HnQu$$25sfJd2sYK!YzbJgdY&t zJ8~rt^+VLu@7h*FS%?+aQVVFdBXC^lX_R%S3wb2<<(NPWg+EcSND6(AI(mf|MlX~x zN)UuDV3c8Gj7nyiBW#~${fG+PQyHUDmy`rC3CB37&dEU~_i@v9PI@W&+nucPOwa&ZYI>CA&@+Dpz+X4( zq^?4Ml?h_u`JCybMEV-LnOQ%yyeXj0^ENDuf)j;Y|K52Z#j09+A06162<}=katG%10LB8C|0ng{G#74 zM7Y8Wx1@|00g}29ix>fL-k`Q2Y(aP*;Y|cy%zUW$1K|Y1F)(-;$NB_7`PSNb-eQ~) z&fohdaK6_7P$tQlUAP+?jE|K;*P|}GQMCexk9s(*s(8B#^4tp%NS45e>x#FFKNp>g zxL|YND`tWQV6G~0b*T=y3*d{h99uyH@N!hRmQ|@w`I*2|paGaWr2g&`uwHJgUBz}A zZwg>GXcQ!-F3tqgP~h9ijlG)R?{f6-1WuIzVBU5)mu{lm25wFbBGExlBgbi1L0q@r zheZH>k4~dL4VL*rR6wt6IN%5#dPFok!Ax##Bh%-6nEnUc@ug(t0=r*$oR_zJn9hBR>fzL? zic!qEq0^%L)Q9O$EC#B~O6@?+Fh1qOG;MJA==}_1WwL$N4li4GL*;lU8$J$lOcgHr z)u($D_EK@hW9%MHpOTtwoYf7mkF8`V#fR3$LGPXS^~=g-ZLM4d^v~1 zz`|wb>II6g`~IM%ax&wp@hU=}YfWw~o_6TdEmH z12~uGJHrhK8xcN0sA`@3F>IYh;Fgb{5H8>XZ__j!kP8S%je09((wD5N>_y))g5aHZyE#j#J3zzPyg) z7X*=u+c7sUax-GNJsL(h4)YRe$FwJ-k$uSK=aHj%<9B9{2FYWn%vnT7a_=)mjyOvp zXI8NijS2^#ebic`%gkfoD7fQml$4~1hT>jmeVNkiGF%zh6?2%-PmIw}7)Pmk+m+Dl z621)V!I-^IDk-8ta;vrxN&^~xTnDnF_sS8`AeqaR{8@?D8xFi}@a_ZfVvzk@#%R6+ z??|rxG?LS3e*rhr@GHCr2vse(R}Z({7Wo2VA$v4Gb?itEcQVQCHWIxxoR7|O%)k~B z{a!~$a0W)bel!K+xvT694n2?qG;qwdksf-Jycs?LX4n1TuFV_4l%`ETX`Lh6#_bjKhJtmfAWmtp!;5c8c;GH{9<%c4@Zau=>sL@RjFq7oQC4?l;( z`5IWuhhlD%yZ$j=UjZd62bPv<8-5iezbhuy!ap-WG&!6v;G`AetFa;4i2wLEwg&PW%`kXG>xZ6E#yrvlNQ_ z?u@^+!`HfCW$nRz#lMNgFt74CTuf5 zkmVKvXOc;hSC2MXMGxofVs7Uw3&2MZ_@mCw|7HWa{Ssm#wvk$UW+>-q z7=QYk|2?ee&wrz;x6l`Ta!I)FQtD<{HCm9sm$_W=;tHaKWr%Z;i@WM2AR65dIF2%K n5r-e|T-CxAjIGa*ZiM^?DE2tKw$>7|00000NkvXXu0mjfk@?0^ literal 0 HcmV?d00001 diff --git a/dragonpilot/selfdrive/assets/icons/icon_plus.png b/dragonpilot/selfdrive/assets/icons/icon_plus.png new file mode 100644 index 0000000000000000000000000000000000000000..92b448b0bdcfcb2b1f1abede5f5b751b314353d1 GIT binary patch literal 2833 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 literal 0 HcmV?d00001 diff --git a/dragonpilot/selfdrive/assets/images/spinner_comma.png b/dragonpilot/selfdrive/assets/images/spinner_comma.png new file mode 100644 index 0000000000000000000000000000000000000000..aa90a78c471f413653616f97d72a019f459dc173 GIT binary patch literal 88317 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 C?W-mL literal 0 HcmV?d00001 diff --git a/dragonpilot/selfdrive/assets/offroad/icon_plus.png b/dragonpilot/selfdrive/assets/offroad/icon_plus.png new file mode 100644 index 0000000000000000000000000000000000000000..92b448b0bdcfcb2b1f1abede5f5b751b314353d1 GIT binary patch literal 2833 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 literal 0 HcmV?d00001 diff --git a/dragonpilot/selfdrive/controls/.gitignore b/dragonpilot/selfdrive/controls/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/dragonpilot/selfdrive/controls/lib/.gitignore b/dragonpilot/selfdrive/controls/lib/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/dragonpilot/selfdrive/ui/.gitignore b/dragonpilot/selfdrive/ui/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/opendbc_repo/opendbc/car/body/interface.py b/opendbc_repo/opendbc/car/body/interface.py index 24e571ee9..daa9dc055 100644 --- a/opendbc_repo/opendbc/car/body/interface.py +++ b/opendbc_repo/opendbc/car/body/interface.py @@ -11,7 +11,7 @@ class CarInterface(CarInterfaceBase): CarController = CarController @staticmethod - def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: ret.notCar = True ret.brand = "body" ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.body)] diff --git a/opendbc_repo/opendbc/car/car_helpers.py b/opendbc_repo/opendbc/car/car_helpers.py index dfda01552..eaa6a2fc5 100644 --- a/opendbc_repo/opendbc/car/car_helpers.py +++ b/opendbc_repo/opendbc/car/car_helpers.py @@ -149,7 +149,7 @@ def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_mu def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, alpha_long_allowed: bool, - is_release: bool, num_pandas: int = 1, cached_params: CarParamsT | None = None): + is_release: bool, num_pandas: int = 1, dp_params: int = 0, cached_params: CarParamsT | None = None): candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(can_recv, can_send, set_obd_multiplexing, num_pandas, cached_params) if candidate is None: @@ -157,7 +157,7 @@ def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multip candidate = "MOCK" CarInterface = interfaces[candidate] - CP: CarParams = CarInterface.get_params(candidate, fingerprints, car_fw, alpha_long_allowed, is_release, docs=False) + CP: CarParams = CarInterface.get_params(candidate, fingerprints, car_fw, alpha_long_allowed, is_release, dp_params, docs=False) CP.carVin = vin CP.carFw = car_fw CP.fingerprintSource = source diff --git a/opendbc_repo/opendbc/car/chrysler/interface.py b/opendbc_repo/opendbc/car/chrysler/interface.py index 0be2ccacb..d69f192d2 100755 --- a/opendbc_repo/opendbc/car/chrysler/interface.py +++ b/opendbc_repo/opendbc/car/chrysler/interface.py @@ -13,7 +13,7 @@ class CarInterface(CarInterfaceBase): RadarInterface = RadarInterface @staticmethod - def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: ret.brand = "chrysler" ret.dashcamOnly = candidate in RAM_HD diff --git a/opendbc_repo/opendbc/car/docs.py b/opendbc_repo/opendbc/car/docs.py index 901b889d5..a66a08166 100755 --- a/opendbc_repo/opendbc/car/docs.py +++ b/opendbc_repo/opendbc/car/docs.py @@ -32,7 +32,7 @@ def get_params_for_docs(platform) -> CarParams: cp_platform = platform if platform in interfaces else MOCK.MOCK CP: CarParams = interfaces[cp_platform].get_params(cp_platform, fingerprint=gen_empty_fingerprint(), car_fw=[CarParams.CarFw(ecu=CarParams.Ecu.unknown)], - alpha_long=True, is_release=False, docs=True) + alpha_long=True, is_release=False, dp_params=0, docs=True) return CP diff --git a/opendbc_repo/opendbc/car/ford/interface.py b/opendbc_repo/opendbc/car/ford/interface.py index 97685df58..9d3872e0b 100644 --- a/opendbc_repo/opendbc/car/ford/interface.py +++ b/opendbc_repo/opendbc/car/ford/interface.py @@ -26,7 +26,7 @@ class CarInterface(CarInterfaceBase): return CarControllerParams.ACCEL_MIN, np.interp(current_speed, ACCEL_MAX_BP, ACCEL_MAX_VALS) @staticmethod - def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: ret.brand = "ford" ret.radarUnavailable = Bus.radar not in DBC[candidate] diff --git a/opendbc_repo/opendbc/car/gm/interface.py b/opendbc_repo/opendbc/car/gm/interface.py index 3e731b6b0..5885b8285 100755 --- a/opendbc_repo/opendbc/car/gm/interface.py +++ b/opendbc_repo/opendbc/car/gm/interface.py @@ -82,7 +82,7 @@ class CarInterface(CarInterfaceBase): return self.torque_from_lateral_accel_linear @staticmethod - def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: ret.brand = "gm" ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.gm)] ret.autoResumeSng = False diff --git a/opendbc_repo/opendbc/car/honda/interface.py b/opendbc_repo/opendbc/car/honda/interface.py index 10d52f246..90844cef7 100755 --- a/opendbc_repo/opendbc/car/honda/interface.py +++ b/opendbc_repo/opendbc/car/honda/interface.py @@ -31,7 +31,7 @@ class CarInterface(CarInterfaceBase): return CarControllerParams.NIDEC_ACCEL_MIN, np.interp(current_speed, ACCEL_MAX_BP, ACCEL_MAX_VALS) @staticmethod - def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: ret.brand = "honda" CAN = CanBus(ret, fingerprint) diff --git a/opendbc_repo/opendbc/car/hyundai/interface.py b/opendbc_repo/opendbc/car/hyundai/interface.py index 1e058c4fc..3744450ab 100644 --- a/opendbc_repo/opendbc/car/hyundai/interface.py +++ b/opendbc_repo/opendbc/car/hyundai/interface.py @@ -23,7 +23,7 @@ class CarInterface(CarInterfaceBase): RadarInterface = RadarInterface @staticmethod - def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: ret.brand = "hyundai" # "LKA steering" if LKAS or LKAS_ALT messages are seen coming from the camera. diff --git a/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py b/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py index b798acaa1..4f3a20c60 100644 --- a/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py +++ b/opendbc_repo/opendbc/car/hyundai/tests/test_hyundai.py @@ -51,7 +51,7 @@ class TestHyundaiFingerprint: if lka_steering: cam_can = CanBus(None, fingerprint).CAM fingerprint[cam_can] = [0x50, 0x110] # LKA steering messages - CP = CarInterface.get_params(CAR.KIA_EV6, fingerprint, [], False, False, False) + CP = CarInterface.get_params(CAR.KIA_EV6, fingerprint, [], False, False, 0, False) assert bool(CP.flags & HyundaiFlags.CANFD_LKA_STEERING) == lka_steering # radar available @@ -59,14 +59,14 @@ class TestHyundaiFingerprint: fingerprint = gen_empty_fingerprint() if radar: fingerprint[1][RADAR_START_ADDR] = 8 - CP = CarInterface.get_params(CAR.HYUNDAI_SONATA, fingerprint, [], False, False, False) + CP = CarInterface.get_params(CAR.HYUNDAI_SONATA, fingerprint, [], False, False, 0, False) assert CP.radarUnavailable != radar def test_alternate_limits(self): # Alternate lateral control limits, for high torque cars, verify Panda safety mode flag is set fingerprint = gen_empty_fingerprint() for car_model in CAR: - CP = CarInterface.get_params(car_model, fingerprint, [], False, False, False) + CP = CarInterface.get_params(car_model, fingerprint, [], False, False, 0, False) assert bool(CP.flags & HyundaiFlags.ALT_LIMITS) == bool(CP.safetyConfigs[-1].safetyParam & HyundaiSafetyFlags.ALT_LIMITS) def test_can_features(self): diff --git a/opendbc_repo/opendbc/car/interfaces.py b/opendbc_repo/opendbc/car/interfaces.py index d3bc08134..756aad316 100644 --- a/opendbc_repo/opendbc/car/interfaces.py +++ b/opendbc_repo/opendbc/car/interfaces.py @@ -130,11 +130,11 @@ class CarInterfaceBase(ABC): """ Parameters essential to controlling the car may be incomplete or wrong without FW versions or fingerprints. """ - return cls.get_params(candidate, gen_empty_fingerprint(), list(), False, False, False) + return cls.get_params(candidate, gen_empty_fingerprint(), list(), False, False, 0, False) @classmethod def get_params(cls, candidate: str, fingerprint: dict[int, dict[int, int]], car_fw: list[structs.CarParams.CarFw], - alpha_long: bool, is_release: bool, docs: bool) -> structs.CarParams: + alpha_long: bool, is_release: bool, dp_params: int, docs: bool) -> structs.CarParams: ret = CarInterfaceBase.get_std_params(candidate) platform = PLATFORMS[candidate] @@ -147,7 +147,7 @@ class CarInterfaceBase(ABC): ret.tireStiffnessFactor = platform.config.specs.tireStiffnessFactor ret.flags |= int(platform.config.flags) - ret = cls._get_params(ret, candidate, fingerprint, car_fw, alpha_long, is_release, docs) + ret = cls._get_params(ret, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) # Vehicle mass is published curb weight plus assumed payload such as a human driver; notCars have no assumed payload if not ret.notCar: @@ -162,7 +162,7 @@ class CarInterfaceBase(ABC): @staticmethod @abstractmethod def _get_params(ret: structs.CarParams, candidate, fingerprint: dict[int, dict[int, int]], - car_fw: list[structs.CarParams.CarFw], alpha_long: bool, is_release: bool, docs: bool) -> structs.CarParams: + car_fw: list[structs.CarParams.CarFw], alpha_long: bool, is_release: bool, dp_params: int, docs: bool) -> structs.CarParams: raise NotImplementedError @staticmethod diff --git a/opendbc_repo/opendbc/car/mazda/interface.py b/opendbc_repo/opendbc/car/mazda/interface.py index 814846e85..1381e47b1 100755 --- a/opendbc_repo/opendbc/car/mazda/interface.py +++ b/opendbc_repo/opendbc/car/mazda/interface.py @@ -12,7 +12,7 @@ class CarInterface(CarInterfaceBase): CarController = CarController @staticmethod - def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: ret.brand = "mazda" ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.mazda)] ret.radarUnavailable = True diff --git a/opendbc_repo/opendbc/car/mock/interface.py b/opendbc_repo/opendbc/car/mock/interface.py index 3bcc2f8f1..3b6d50159 100755 --- a/opendbc_repo/opendbc/car/mock/interface.py +++ b/opendbc_repo/opendbc/car/mock/interface.py @@ -11,7 +11,7 @@ class CarInterface(CarInterfaceBase): CarController = CarController @staticmethod - def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: ret.brand = "mock" ret.mass = 1700. ret.wheelbase = 2.70 diff --git a/opendbc_repo/opendbc/car/nissan/interface.py b/opendbc_repo/opendbc/car/nissan/interface.py index bac7b3f1a..f4ca54fa2 100644 --- a/opendbc_repo/opendbc/car/nissan/interface.py +++ b/opendbc_repo/opendbc/car/nissan/interface.py @@ -10,7 +10,7 @@ class CarInterface(CarInterfaceBase): CarController = CarController @staticmethod - def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: ret.brand = "nissan" ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.nissan)] ret.autoResumeSng = False diff --git a/opendbc_repo/opendbc/car/psa/interface.py b/opendbc_repo/opendbc/car/psa/interface.py index f719a3d6a..d644b3406 100644 --- a/opendbc_repo/opendbc/car/psa/interface.py +++ b/opendbc_repo/opendbc/car/psa/interface.py @@ -11,7 +11,7 @@ class CarInterface(CarInterfaceBase): CarController = CarController @staticmethod - def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: ret.brand = 'psa' ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.psa)] diff --git a/opendbc_repo/opendbc/car/rivian/interface.py b/opendbc_repo/opendbc/car/rivian/interface.py index f1108e081..2731627f9 100644 --- a/opendbc_repo/opendbc/car/rivian/interface.py +++ b/opendbc_repo/opendbc/car/rivian/interface.py @@ -12,7 +12,7 @@ class CarInterface(CarInterfaceBase): RadarInterface = RadarInterface @staticmethod - def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: ret.brand = "rivian" ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.rivian)] diff --git a/opendbc_repo/opendbc/car/structs.py b/opendbc_repo/opendbc/car/structs.py index a5628c7e0..0959d5c75 100644 --- a/opendbc_repo/opendbc/car/structs.py +++ b/opendbc_repo/opendbc/car/structs.py @@ -18,3 +18,6 @@ CarStateT = capnp.lib.capnp._StructModule RadarDataT = capnp.lib.capnp._StructModule CarControlT = capnp.lib.capnp._StructModule CarParamsT = capnp.lib.capnp._StructModule + +class DPFlags: + pass diff --git a/opendbc_repo/opendbc/car/subaru/interface.py b/opendbc_repo/opendbc/car/subaru/interface.py index b11a987d5..09b9b3a91 100644 --- a/opendbc_repo/opendbc/car/subaru/interface.py +++ b/opendbc_repo/opendbc/car/subaru/interface.py @@ -11,7 +11,7 @@ class CarInterface(CarInterfaceBase): CarController = CarController @staticmethod - def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: ret.brand = "subaru" ret.radarUnavailable = True # for HYBRID CARS to be upstreamed, we need: diff --git a/opendbc_repo/opendbc/car/tesla/interface.py b/opendbc_repo/opendbc/car/tesla/interface.py index baf159323..2019f7cf4 100644 --- a/opendbc_repo/opendbc/car/tesla/interface.py +++ b/opendbc_repo/opendbc/car/tesla/interface.py @@ -10,7 +10,7 @@ class CarInterface(CarInterfaceBase): CarController = CarController @staticmethod - def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: ret.brand = "tesla" ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.tesla)] diff --git a/opendbc_repo/opendbc/car/tests/test_car_interfaces.py b/opendbc_repo/opendbc/car/tests/test_car_interfaces.py index ae67788de..9b83e7010 100644 --- a/opendbc_repo/opendbc/car/tests/test_car_interfaces.py +++ b/opendbc_repo/opendbc/car/tests/test_car_interfaces.py @@ -64,7 +64,7 @@ class TestCarInterfaces: args = get_fuzzy_car_interface_args(data.draw) car_params = CarInterface.get_params(car_name, args['fingerprints'], args['car_fw'], - alpha_long=args['alpha_long'], is_release=False, docs=False) + alpha_long=args['alpha_long'], is_release=False, dp_params=0, docs=False) car_interface = CarInterface(car_params) assert car_params assert car_interface diff --git a/opendbc_repo/opendbc/car/toyota/interface.py b/opendbc_repo/opendbc/car/toyota/interface.py index b8ee8c946..dae5c509b 100644 --- a/opendbc_repo/opendbc/car/toyota/interface.py +++ b/opendbc_repo/opendbc/car/toyota/interface.py @@ -21,7 +21,7 @@ class CarInterface(CarInterfaceBase): return CarControllerParams(CP).ACCEL_MIN, CarControllerParams(CP).ACCEL_MAX @staticmethod - def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: ret.brand = "toyota" ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.toyota)] ret.safetyConfigs[0].safetyParam = EPS_SCALE[candidate] diff --git a/opendbc_repo/opendbc/car/volkswagen/interface.py b/opendbc_repo/opendbc/car/volkswagen/interface.py index 4c40f8740..61dd79719 100644 --- a/opendbc_repo/opendbc/car/volkswagen/interface.py +++ b/opendbc_repo/opendbc/car/volkswagen/interface.py @@ -10,7 +10,7 @@ class CarInterface(CarInterfaceBase): CarController = CarController @staticmethod - def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, alpha_long, is_release, dp_params, docs) -> structs.CarParams: ret.brand = "volkswagen" ret.radarUnavailable = True diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index 27b04ae65..00be61362 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -82,6 +82,8 @@ class Car: is_release = self.params.get_bool("IsReleaseBranch") + dp_params = 0 + if CI is None: # wait for one pandaState and one CAN packet print("Waiting for CAN messages...") @@ -99,7 +101,7 @@ class Car: with car.CarParams.from_bytes(cached_params_raw) as _cached_params: cached_params = _cached_params - self.CI = get_car(*self.can_callbacks, obd_callback(self.params), alpha_long_allowed, is_release, num_pandas, cached_params) + self.CI = get_car(*self.can_callbacks, obd_callback(self.params), alpha_long_allowed, is_release, num_pandas, dp_params, cached_params) self.RI = interfaces[self.CI.CP.carFingerprint].RadarInterface(self.CI.CP) self.CP = self.CI.CP diff --git a/selfdrive/car/cruise.py b/selfdrive/car/cruise.py index 0d761844b..0474a7a77 100644 --- a/selfdrive/car/cruise.py +++ b/selfdrive/car/cruise.py @@ -12,7 +12,7 @@ V_CRUISE_MIN = 8 V_CRUISE_MAX = 145 V_CRUISE_UNSET = 255 V_CRUISE_INITIAL = 40 -V_CRUISE_INITIAL_EXPERIMENTAL_MODE = 105 +V_CRUISE_INITIAL_EXPERIMENTAL_MODE = 50 IMPERIAL_INCREMENT = round(CV.MPH_TO_KPH, 1) # round here to avoid rounding errors incrementing set speed ButtonEvent = car.CarState.ButtonEvent diff --git a/selfdrive/car/tests/test_car_interfaces.py b/selfdrive/car/tests/test_car_interfaces.py index 5c4729ee9..50717ef04 100644 --- a/selfdrive/car/tests/test_car_interfaces.py +++ b/selfdrive/car/tests/test_car_interfaces.py @@ -39,7 +39,7 @@ class TestCarInterfaces: args = get_fuzzy_car_interface_args(data.draw) car_params = CarInterface.get_params(car_name, args['fingerprints'], args['car_fw'], - alpha_long=args['alpha_long'], is_release=False, docs=False) + alpha_long=args['alpha_long'], is_release=False, dp_params=0, docs=False) car_params = car_params.as_reader() car_interface = CarInterface(car_params) assert car_params diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index 8996ad646..49532f51b 100644 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -149,7 +149,7 @@ class TestCarModelBase(unittest.TestCase): cls.openpilot_enabled = cls.car_safety_mode_frame is not None cls.CarInterface = interfaces[cls.platform] - cls.CP = cls.CarInterface.get_params(cls.platform, cls.fingerprint, car_fw, alpha_long, False, docs=False) + cls.CP = cls.CarInterface.get_params(cls.platform, cls.fingerprint, car_fw, alpha_long, False, dp_params=0, docs=False) assert cls.CP assert cls.CP.carFingerprint == cls.platform diff --git a/selfdrive/controls/lib/longitudinal_planner.py b/selfdrive/controls/lib/longitudinal_planner.py index 34fc85f8a..94b63290c 100755 --- a/selfdrive/controls/lib/longitudinal_planner.py +++ b/selfdrive/controls/lib/longitudinal_planner.py @@ -26,6 +26,8 @@ MIN_ALLOW_THROTTLE_SPEED = 2.5 _A_TOTAL_MAX_V = [1.7, 3.2] _A_TOTAL_MAX_BP = [20., 40.] +class DPFlags: + pass def get_max_accel(v_ego): return np.interp(v_ego, A_CRUISE_MAX_BP, A_CRUISE_MAX_VALS) @@ -89,7 +91,7 @@ class LongitudinalPlanner: throttle_prob = 1.0 return x, v, a, j, throttle_prob - def update(self, sm): + def update(self, sm, dp_flags = 0): mode = 'blended' if sm['selfdriveState'].experimentalMode else 'acc' if len(sm['carControl'].orientationNED) == 3: diff --git a/selfdrive/controls/plannerd.py b/selfdrive/controls/plannerd.py index bec7eede0..dc3d5d231 100755 --- a/selfdrive/controls/plannerd.py +++ b/selfdrive/controls/plannerd.py @@ -4,7 +4,7 @@ from openpilot.common.params import Params from openpilot.common.realtime import Priority, config_realtime_process from openpilot.common.swaglog import cloudlog from openpilot.selfdrive.controls.lib.ldw import LaneDepartureWarning -from openpilot.selfdrive.controls.lib.longitudinal_planner import LongitudinalPlanner +from openpilot.selfdrive.controls.lib.longitudinal_planner import LongitudinalPlanner, DPFlags import cereal.messaging as messaging @@ -22,10 +22,12 @@ def main(): sm = messaging.SubMaster(['carControl', 'carState', 'controlsState', 'liveParameters', 'radarState', 'modelV2', 'selfdriveState'], poll='modelV2') + dp_flags = 0 + while True: sm.update() if sm.updated['modelV2']: - longitudinal_planner.update(sm) + longitudinal_planner.update(sm, dp_flags) longitudinal_planner.publish(sm, pm) ldw.update(sm.frame, sm['modelV2'], sm['carState'], sm['carControl']) diff --git a/selfdrive/selfdrived/selfdrived.py b/selfdrive/selfdrived/selfdrived.py index cf22040e8..d783b2b67 100755 --- a/selfdrive/selfdrived/selfdrived.py +++ b/selfdrive/selfdrived/selfdrived.py @@ -130,7 +130,7 @@ class SelfdriveD: self.ignored_processes = {'loggerd', } # Determine startup event - self.startup_event = EventName.startup if build_metadata.openpilot.comma_remote and build_metadata.tested_channel else EventName.startupMaster + self.startup_event = EventName.startup #if build_metadata.openpilot.comma_remote and build_metadata.tested_channel else EventName.startupMaster if not car_recognized: self.startup_event = EventName.startupNoCar elif car_recognized and self.CP.passive: diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index ba9fa8b7a..751e7a032 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -27,7 +27,7 @@ qt_libs = [widgets, qt_util] + base_libs qt_src = ["main.cc", "ui.cc", "qt/sidebar.cc", "qt/body.cc", "qt/window.cc", "qt/home.cc", "qt/offroad/settings.cc", - "qt/offroad/software_settings.cc", "qt/offroad/developer_panel.cc", "qt/offroad/onboarding.cc", + "qt/offroad/software_settings.cc", "qt/offroad/developer_panel.cc", "qt/offroad/onboarding.cc", "qt/offroad/dp_panel.cc", "qt/offroad/driverview.cc", "qt/offroad/experimental_mode.cc", "qt/offroad/firehose.cc", "qt/onroad/onroad_home.cc", "qt/onroad/annotated_camera.cc", "qt/onroad/model.cc", "qt/onroad/buttons.cc", "qt/onroad/alerts.cc", "qt/onroad/driver_monitoring.cc", "qt/onroad/hud.cc"] diff --git a/selfdrive/ui/qt/offroad/developer_panel.cc b/selfdrive/ui/qt/offroad/developer_panel.cc index a095228da..2f533f16b 100644 --- a/selfdrive/ui/qt/offroad/developer_panel.cc +++ b/selfdrive/ui/qt/offroad/developer_panel.cc @@ -45,6 +45,21 @@ DeveloperPanel::DeveloperPanel(SettingsWindow *parent) : ListWidget(parent) { // Toggles should be not available to change in onroad state QObject::connect(uiState(), &UIState::offroadTransition, this, &DeveloperPanel::updateToggles); + + // error logs + QPushButton* error_log_btn = new QPushButton(QObject::tr("Show Last Errors")); + error_log_btn->setObjectName("error_log_btn"); + + error_log_btn->setStyleSheet(R"( + #error_log_btn { height: 120px; border-radius: 15px; background-color: #393939; } + #error_log_btn:pressed { background-color: #4a4a4a; } + )"); + + addItem(error_log_btn); + + QObject::connect(error_log_btn, &QPushButton::clicked, [=]() { + ConfirmationDialog::rich(QString::fromStdString(params.get("dp_device_last_log")), parent); + }); } void DeveloperPanel::updateToggles(bool _offroad) { diff --git a/selfdrive/ui/qt/offroad/dp_panel.cc b/selfdrive/ui/qt/offroad/dp_panel.cc new file mode 100644 index 000000000..548b02be5 --- /dev/null +++ b/selfdrive/ui/qt/offroad/dp_panel.cc @@ -0,0 +1,295 @@ +#include "selfdrive/ui/qt/offroad/dp_panel.h" + +void DPPanel::add_toyota_toggles() { + std::vector> toggle_defs{ + { + "", + QString::fromUtf8("🐉 ") + tr("Toyota / Lexus"), + "", + }, + }; + + QWidget *label = nullptr; + bool has_toggle = false; + + for (auto &[param, title, desc] : toggle_defs) { + if (param.isEmpty()) { + label = new LabelControl(title, ""); + addItem(label); + continue; + } + + has_toggle = true; + auto toggle = new ParamControl(param, title, desc, "", this); + bool locked = params.getBool((param + "Lock").toStdString()); + toggle->setEnabled(!locked); + addItem(toggle); + toggles[param.toStdString()] = toggle; + } + + // If no toggles were added, hide the label + if (!has_toggle && label) { + label->hide(); + } +} + +void DPPanel::add_vag_toggles() { + std::vector> toggle_defs{ + { + "", + QString::fromUtf8("🐉 ") + tr("VW / Audi / Skoda"), + "", + }, + }; + + QWidget *label = nullptr; + bool has_toggle = false; + + for (auto &[param, title, desc] : toggle_defs) { + if (param.isEmpty()) { + label = new LabelControl(title, ""); + addItem(label); + continue; + } + + has_toggle = true; + auto toggle = new ParamControl(param, title, desc, "", this); + bool locked = params.getBool((param + "Lock").toStdString()); + toggle->setEnabled(!locked); + addItem(toggle); + toggles[param.toStdString()] = toggle; + } + + // If no toggles were added, hide the label + if (!has_toggle && label) { + label->hide(); + } +} + +void DPPanel::add_mazda_toggles() { + std::vector> toggle_defs{ + { + "", + QString::fromUtf8("🐉 ") + tr("Mazda"), + "", + }, + }; + + QWidget *label = nullptr; + bool has_toggle = false; + + for (auto &[param, title, desc] : toggle_defs) { + if (param.isEmpty()) { + label = new LabelControl(title, ""); + addItem(label); + continue; + } + + has_toggle = true; + auto toggle = new ParamControl(param, title, desc, "", this); + bool locked = params.getBool((param + "Lock").toStdString()); + toggle->setEnabled(!locked); + addItem(toggle); + toggles[param.toStdString()] = toggle; + } + + // If no toggles were added, hide the label + if (!has_toggle && label) { + label->hide(); + } +} + +void DPPanel::add_lateral_toggles() { + std::vector> toggle_defs{ + { + "", + QString::fromUtf8("🐉 ") + tr("Lateral Ctrl"), + "", + }, + }; + + QWidget *label = nullptr; + bool has_toggle = false; + + for (auto &[param, title, desc] : toggle_defs) { + if (param.isEmpty()) { + label = new LabelControl(title, ""); + addItem(label); + continue; + } + + has_toggle = true; + auto toggle = new ParamControl(param, title, desc, "", this); + bool locked = params.getBool((param + "Lock").toStdString()); + toggle->setEnabled(!locked); + addItem(toggle); + toggles[param.toStdString()] = toggle; + } + + // If no toggles were added, hide the label + if (!has_toggle && label) { + label->hide(); + } +} + +void DPPanel::add_longitudinal_toggles() { + std::vector> toggle_defs{ + { + "", + QString::fromUtf8("🐉 ") + tr("Longitudinal Ctrl"), + "", + }, + }; + + QWidget *label = nullptr; + bool has_toggle = false; + + for (auto &[param, title, desc] : toggle_defs) { + if (param.isEmpty()) { + label = new LabelControl(title, ""); + addItem(label); + continue; + } + + has_toggle = true; + auto toggle = new ParamControl(param, title, desc, "", this); + bool locked = params.getBool((param + "Lock").toStdString()); + toggle->setEnabled(!locked); + addItem(toggle); + toggles[param.toStdString()] = toggle; + } + + // If no toggles were added, hide the label + if (!has_toggle && label) { + label->hide(); + } +} + +void DPPanel::add_ui_toggles() { + std::vector> toggle_defs{ + { + "", + QString::fromUtf8("🐉 ") + tr("UI"), + "", + }, + }; + + QWidget *label = nullptr; + bool has_toggle = false; + + for (auto &[param, title, desc] : toggle_defs) { + if (param.isEmpty()) { + label = new LabelControl(title, ""); + addItem(label); + continue; + } + + has_toggle = true; + auto toggle = new ParamControl(param, title, desc, "", this); + bool locked = params.getBool((param + "Lock").toStdString()); + toggle->setEnabled(!locked); + addItem(toggle); + toggles[param.toStdString()] = toggle; + } + + // If no toggles were added, hide the label + if (!has_toggle && label) { + label->hide(); + } +} + +void DPPanel::add_device_toggles() { + std::vector> toggle_defs{ + { + "", + QString::fromUtf8("🐉 ") + tr("Device"), + "", + }, + }; + + QWidget *label = nullptr; + bool has_toggle = false; + + for (auto &[param, title, desc] : toggle_defs) { + if (param.isEmpty()) { + label = new LabelControl(title, ""); + addItem(label); + continue; + } + + has_toggle = true; + auto toggle = new ParamControl(param, title, desc, "", this); + bool locked = params.getBool((param + "Lock").toStdString()); + toggle->setEnabled(!locked); + addItem(toggle); + toggles[param.toStdString()] = toggle; + } + + // If no toggles were added, hide the label + if (!has_toggle && label) { + label->hide(); + } +} + +DPPanel::DPPanel(SettingsWindow *parent) : ListWidget(parent) { + auto cp_bytes = params.get("CarParamsPersistent"); + if (!cp_bytes.empty()) { + AlignedBuffer aligned_buf; + capnp::FlatArrayMessageReader cmsg(aligned_buf.align(cp_bytes.data(), cp_bytes.size())); + cereal::CarParams::Reader CP = cmsg.getRoot(); + brand = QString::fromStdString(CP.getBrand()); + vehicle_has_long_ctrl = hasLongitudinalControl(CP); + vehicle_has_radar_unavailable = CP.getRadarUnavailable(); + } + + if (brand == "toyota") { + add_toyota_toggles(); + } else if (brand == "volkswagen") { + add_vag_toggles(); + } else if (brand == "mazda") { + add_mazda_toggles(); + } + add_lateral_toggles(); + add_longitudinal_toggles(); + add_ui_toggles(); + add_device_toggles(); + + auto resetBtn = new ButtonControl(tr("Reset dragonpilot settings"), tr("RESET")); + connect(resetBtn, &ButtonControl::clicked, [&]() { + if (ConfirmationDialog::confirm(tr("Are you sure you want to reset all settings?"), tr("Reset"), this)) { + params.putBool("dp_device_reset_conf", true); + } + }); + addItem(resetBtn); + + fs_watch = new ParamWatcher(this); + QObject::connect(fs_watch, &ParamWatcher::paramChanged, [=](const QString ¶m_name, const QString ¶m_value) { + updateStates(); + }); + + connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { + is_onroad = !offroad; + updateStates(); + }); + + updateStates(); +} + +void DPPanel::showEvent(QShowEvent *event) { + updateStates(); +} + +void DPPanel::updateStates() { + // do fs_watch here + + if (!isVisible()) { + return; + } + + // do state change logic here + +} + +void DPPanel::expandToggleDescription(const QString ¶m) { + toggles[param.toStdString()]->showDescription(); +} diff --git a/selfdrive/ui/qt/offroad/dp_panel.h b/selfdrive/ui/qt/offroad/dp_panel.h new file mode 100644 index 000000000..87095c73b --- /dev/null +++ b/selfdrive/ui/qt/offroad/dp_panel.h @@ -0,0 +1,31 @@ +#pragma once + +#include "selfdrive/ui/qt/offroad/settings.h" + +class DPPanel : public ListWidget { + Q_OBJECT +public: + explicit DPPanel(SettingsWindow *parent); + +public slots: + void expandToggleDescription(const QString ¶m); + +private: + Params params; + ParamWatcher *fs_watch; + std::map toggles; + QString brand; + bool is_onroad = false; + bool vehicle_has_long_ctrl; + bool vehicle_has_radar_unavailable; + + void add_toyota_toggles(); + void add_vag_toggles(); + void add_mazda_toggles(); + void add_lateral_toggles(); + void add_longitudinal_toggles(); + void add_ui_toggles(); + void add_device_toggles(); + void updateStates(); + void showEvent(QShowEvent *event) override; +}; diff --git a/selfdrive/ui/qt/offroad/settings.cc b/selfdrive/ui/qt/offroad/settings.cc index 96734d69d..7f37241de 100644 --- a/selfdrive/ui/qt/offroad/settings.cc +++ b/selfdrive/ui/qt/offroad/settings.cc @@ -15,6 +15,7 @@ #include "selfdrive/ui/qt/widgets/scrollview.h" #include "selfdrive/ui/qt/offroad/developer_panel.h" #include "selfdrive/ui/qt/offroad/firehose.h" +#include "selfdrive/ui/qt/offroad/dp_panel.h" TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { // param, title, desc, icon, restart needed @@ -75,6 +76,20 @@ TogglesPanel::TogglesPanel(SettingsWindow *parent) : ListWidget(parent) { "../assets/icons/metric.png", false, }, + { + "DisableLogging", + tr("Disable Logging"), + "", + "../assets/offroad/icon_empty.svg", + true, + }, + { + "DisableUpdates", + tr("Disable Updates"), + "", + "../assets/offroad/icon_empty.svg", + true, + }, }; @@ -278,13 +293,13 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) { QObject::connect(uiState()->prime_state, &PrimeState::changed, [this] (PrimeState::Type type) { pair_device->setVisible(type == PrimeState::PRIME_TYPE_UNPAIRED); }); - QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { - for (auto btn : findChildren()) { - if (btn != pair_device && btn != resetCalibBtn) { - btn->setEnabled(offroad); - } - } - }); + // QObject::connect(uiState(), &UIState::offroadTransition, [=](bool offroad) { + // for (auto btn : findChildren()) { + // if (btn != pair_device && btn != resetCalibBtn) { + // btn->setEnabled(offroad); + // } + // } + // }); // power buttons QHBoxLayout *power_layout = new QHBoxLayout(); @@ -475,6 +490,7 @@ SettingsWindow::SettingsWindow(QWidget *parent) : QFrame(parent) { {tr("Software"), new SoftwarePanel(this)}, {tr("Firehose"), new FirehosePanel(this)}, {tr("Developer"), new DeveloperPanel(this)}, + {"DP", new DPPanel(this)}, }; nav_btns = new QButtonGroup(this); diff --git a/selfdrive/ui/qt/offroad/software_settings.cc b/selfdrive/ui/qt/offroad/software_settings.cc index 9bc3fad3c..43358ad72 100644 --- a/selfdrive/ui/qt/offroad/software_settings.cc +++ b/selfdrive/ui/qt/offroad/software_settings.cc @@ -50,6 +50,7 @@ SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) { addItem(installBtn); // branch selecting + /* targetBranchBtn = new ButtonControl(tr("Target Branch"), tr("SELECT")); connect(targetBranchBtn, &ButtonControl::clicked, [=]() { auto current = params.get("GitBranch"); @@ -73,6 +74,7 @@ SoftwarePanel::SoftwarePanel(QWidget* parent) : ListWidget(parent) { if (!params.getBool("IsTestedBranch")) { addItem(targetBranchBtn); } + */ // uninstall button auto uninstallBtn = new ButtonControl(tr("Uninstall %1").arg(getBrand()), tr("UNINSTALL")); @@ -142,7 +144,7 @@ void SoftwarePanel::updateLabels() { } downloadBtn->setEnabled(true); } - targetBranchBtn->setValue(QString::fromStdString(params.get("UpdaterTargetBranch"))); +// targetBranchBtn->setValue(QString::fromStdString(params.get("UpdaterTargetBranch"))); // current + new versions versionLbl->setText(QString::fromStdString(params.get("UpdaterCurrentDescription"))); diff --git a/selfdrive/ui/qt/onroad/buttons.cc b/selfdrive/ui/qt/onroad/buttons.cc index 32e58c9db..b4f9c68b1 100644 --- a/selfdrive/ui/qt/onroad/buttons.cc +++ b/selfdrive/ui/qt/onroad/buttons.cc @@ -19,7 +19,7 @@ void drawIcon(QPainter &p, const QPoint ¢er, const QPixmap &img, const QBrus ExperimentalButton::ExperimentalButton(QWidget *parent) : experimental_mode(false), engageable(false), QPushButton(parent) { setFixedSize(btn_size, btn_size); - engage_img = loadPixmap("../assets/icons/chffr_wheel.png", {img_size, img_size}); + engage_img = loadPixmap("../../dragonpilot/selfdrive/assets/dragonpilot.png", {img_size, img_size}); experimental_img = loadPixmap("../assets/icons/experimental.svg", {img_size, img_size}); QObject::connect(this, &QPushButton::clicked, this, &ExperimentalButton::changeMode); } diff --git a/selfdrive/ui/qt/sidebar.cc b/selfdrive/ui/qt/sidebar.cc index e9c6a2f7c..d29ac0998 100644 --- a/selfdrive/ui/qt/sidebar.cc +++ b/selfdrive/ui/qt/sidebar.cc @@ -25,7 +25,7 @@ void Sidebar::drawMetric(QPainter &p, const QPair &label, QCol } Sidebar::Sidebar(QWidget *parent) : QFrame(parent), onroad(false), flag_pressed(false), settings_pressed(false), mic_indicator_pressed(false) { - home_img = loadPixmap("../assets/images/button_home.png", home_btn.size()); + home_img = loadPixmap("../../dragonpilot/selfdrive/assets/dragonpilot.png", home_btn.size()); flag_img = loadPixmap("../assets/images/button_flag.png", home_btn.size()); settings_img = loadPixmap("../assets/images/button_settings.png", settings_btn.size(), Qt::IgnoreAspectRatio); mic_img = loadPixmap("../assets/icons/microphone.png", QSize(30, 30)); diff --git a/selfdrive/ui/qt/util.cc b/selfdrive/ui/qt/util.cc index 493c20397..0a55b00f7 100644 --- a/selfdrive/ui/qt/util.cc +++ b/selfdrive/ui/qt/util.cc @@ -27,11 +27,11 @@ QString getVersion() { } QString getBrand() { - return QObject::tr("openpilot"); + return QObject::tr("dragonpilot"); } QString getUserAgent() { - return "openpilot-" + getVersion(); + return "dragonpilot-" + getVersion(); } std::optional getDongleId() { diff --git a/selfdrive/ui/qt/widgets/controls.h b/selfdrive/ui/qt/widgets/controls.h index 3342de532..4158d7d4e 100644 --- a/selfdrive/ui/qt/widgets/controls.h +++ b/selfdrive/ui/qt/widgets/controls.h @@ -88,6 +88,10 @@ public: label.setText(text); label.setAlignment(Qt::AlignRight | Qt::AlignVCenter); hlayout->addWidget(&label); + if (text == "") { + setContentsMargins(0, 50, 0, 0); // 30px top margin, 10px bottom margin + // This will create space above and below the entire header control. + } } void setText(const QString &text) { label.setText(text); } @@ -317,3 +321,136 @@ public: setLayout(l); } }; + +#include +class SpinBoxControl : public AbstractControl { + Q_OBJECT + +public: + SpinBoxControl(const QString &title, const QString &desc = "", const QString &icon = "", const int val = 0, QWidget *parent = nullptr) : AbstractControl(title, desc, icon, parent) { + spinbox.setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + spinbox.setAlignment(Qt::AlignCenter); + spinbox.setStyleSheet(R"( + QSpinBox { + width: 300px; + height: 80px; + padding: 0px; + border-radius:40px; + font-size: 36px; + } + QSpinBox::up-button { + subcontrol-origin: margin; + subcontrol-position: center right; + image: url(../../dragonpilot/selfdrive/assets/icons/icon_plus.png); + right: 1px; + height: 80px; + width: 80px; + } + QSpinBox::down-button { + subcontrol-origin: margin; + subcontrol-position: center left; + image: url(../../dragonpilot/selfdrive/assets/icons/icon_minus.png); + left: 1px; + height: 80px; + width: 80px; + } + )"); + + hlayout->addWidget(&spinbox); + QObject::connect(&spinbox, QOverload::of(&QSpinBox::valueChanged), this, &SpinBoxControl::valChanged); + } + +signals: + void valChanged(int val); + +protected: + QSpinBox spinbox; +}; + +class ParamSpinBoxControl : public SpinBoxControl { + Q_OBJECT + +public: + ParamSpinBoxControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, const int minimum = 0, const int maximum = 100, const int step = 1, const QString suffix = "", const QString minText = "", QWidget *parent = nullptr) : SpinBoxControl(title, desc, icon, 0, parent) { + spinbox.setRange(minimum, maximum); + spinbox.setSingleStep(step); + spinbox.setSuffix(suffix); + spinbox.setSpecialValueText(minText); + + std::string str_val = Params().get(param.toStdString().c_str()); + if (str_val != "") { + int val = std::stoi(str_val); + spinbox.setValue(val); + QObject::connect(this, &SpinBoxControl::valChanged, [=](int val) { + Params().put(param.toStdString(), std::to_string(val)); + }); + } + } +}; + +class DoubleSpinBoxControl : public AbstractControl { + Q_OBJECT + +public: + DoubleSpinBoxControl(const QString &title, const QString &desc = "", const QString &icon = "", const double val = 0.0, QWidget *parent = nullptr) : AbstractControl(title, desc, icon, parent) { + spinbox.setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + spinbox.setAlignment(Qt::AlignCenter); + spinbox.setStyleSheet(R"( + QDoubleSpinBox { + width: 300px; + height: 80px; + padding: 0px; + border-radius:40px; + font-size: 36px; + } + QDoubleSpinBox::up-button { + subcontrol-origin: margin; + subcontrol-position: center right; + image: url(../../dragonpilot/selfdrive/assets/icons/icon_plus.png); + right: 1px; + height: 80px; + width: 80px; + } + QDoubleSpinBox::down-button { + subcontrol-origin: margin; + subcontrol-position: center left; + image: url(../../dragonpilot/selfdrive/assets/icons/icon_minus.png); + left: 1px; + height: 80px; + width: 80px; + } + )"); + + hlayout->addWidget(&spinbox); + QObject::connect(&spinbox, QOverload::of(&QDoubleSpinBox::valueChanged), this, &DoubleSpinBoxControl::valChanged); + } + +signals: + void valChanged(double val); + +protected: + QDoubleSpinBox spinbox; +}; + +class ParamDoubleSpinBoxControl : public DoubleSpinBoxControl { + Q_OBJECT + +public: + ParamDoubleSpinBoxControl(const QString ¶m, const QString &title, const QString &desc, const QString &icon, const double minimum = 0.0, const double maximum = 100.0, const double step = 1.0, const QString suffix = "", const QString minText = "", QWidget *parent = nullptr) : DoubleSpinBoxControl(title, desc, icon, 0.0, parent) { + spinbox.setRange(minimum, maximum); + spinbox.setSingleStep(step); + spinbox.setSuffix(suffix); + spinbox.setSpecialValueText(minText); + + std::string str_val = Params().get(param.toStdString().c_str()); + if (str_val != "") { + double val = std::stod(str_val); + spinbox.setValue(val); + + QObject::connect(this, &DoubleSpinBoxControl::valChanged, [=](double val) { + Params().put(param.toStdString(), std::to_string(val)); + }); + } + } + void setValue(float v) { spinbox.setValue(v); } +}; diff --git a/system/manager/manager.py b/system/manager/manager.py index 36055d863..504cfc9a2 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -171,8 +171,10 @@ def manager_thread() -> None: # Exit main loop when uninstall/shutdown/reboot is needed shutdown = False - for param in ("DoUninstall", "DoShutdown", "DoReboot"): + for param in ("DoUninstall", "DoShutdown", "DoReboot", "dp_device_reset_conf"): if params.get_bool(param): + if param == "dp_device_reset_conf": + os.system("rm -fr /data/params/d/dp_*") shutdown = True params.put("LastManagerExitReason", f"{param} {datetime.datetime.now()}") cloudlog.warning(f"Shutting down manager - {param} set") diff --git a/system/manager/process_config.py b/system/manager/process_config.py index 5758512f2..679d4754b 100644 --- a/system/manager/process_config.py +++ b/system/manager/process_config.py @@ -19,7 +19,7 @@ def iscar(started: bool, params: Params, CP: car.CarParams) -> bool: return started and not CP.notCar def logging(started: bool, params: Params, CP: car.CarParams) -> bool: - run = (not CP.notCar) or not params.get_bool("DisableLogging") + run = not params.get_bool("DisableLogging") return started and run def ublox_available() -> bool: diff --git a/system/sentry.py b/system/sentry.py index 47d64ba0f..04d52c7c3 100644 --- a/system/sentry.py +++ b/system/sentry.py @@ -12,9 +12,9 @@ from openpilot.system.version import get_build_metadata, get_version class SentryProject(Enum): # python project - SELFDRIVE = "https://6f3c7076c1e14b2aa10f5dde6dda0cc4@o33823.ingest.sentry.io/77924" + SELFDRIVE = "https://980a0cba712a4c3593c33c78a12446e1@o273754.ingest.sentry.io/1488600" # native project - SELFDRIVE_NATIVE = "https://3e4b586ed21a4479ad5d85083b639bc6@o33823.ingest.sentry.io/157615" + SELFDRIVE_NATIVE = "https://980a0cba712a4c3593c33c78a12446e1@o273754.ingest.sentry.io/1488600" def report_tombstone(fn: str, message: str, contents: str) -> None: @@ -26,11 +26,16 @@ def report_tombstone(fn: str, message: str, contents: str) -> None: sentry_sdk.capture_message(message=message) sentry_sdk.flush() +def save_exception(exc_text): + log = "\n".join(exc_text.splitlines()) + "\n" + Params().put("dp_device_last_log", log) def capture_exception(*args, **kwargs) -> None: cloudlog.error("crash", exc_info=kwargs.get('exc_info', 1)) try: + import traceback + save_exception(traceback.format_exc()) sentry_sdk.capture_exception(*args, **kwargs) sentry_sdk.flush() # https://github.com/getsentry/sentry-python/issues/291 except Exception: diff --git a/system/ui/spinner.py b/system/ui/spinner.py index eb33f0834..29a5dba6f 100755 --- a/system/ui/spinner.py +++ b/system/ui/spinner.py @@ -26,7 +26,7 @@ def clamp(value, min_value, max_value): class Spinner(Widget): def __init__(self): super().__init__() - self._comma_texture = gui_app.texture("images/spinner_comma.png", TEXTURE_SIZE, TEXTURE_SIZE) + self._comma_texture = gui_app.texture("../../dragonpilot/selfdrive/assets/images/spinner_comma.png", TEXTURE_SIZE, TEXTURE_SIZE) self._spinner_texture = gui_app.texture("images/spinner_track.png", TEXTURE_SIZE, TEXTURE_SIZE, alpha_premultiply=True) self._rotation = 0.0 self._progress: int | None = None