IQ.Pilot Release Commit @ d400490

This commit is contained in:
IQ.Lvbs CI [bot]
2026-07-25 14:42:10 -05:00
parent f0ef157344
commit 729bde8fb9
66 changed files with 435 additions and 538 deletions
@@ -16,27 +16,27 @@
},
"python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "3153fede975ec92281e8b33acf9dfd6305a24696f4b877df651f3742a67f368e",
"sha256": "8f9c7215f23878cf3ca3a07f013850f7e889a9e10deb4c1ec8bdabae488723e6",
"size": 135536
},
"python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "37d32ea795dddce22b47ad2bdec838d360894b325719f48bab6d1be8427d3026",
"sha256": "c0d031c33712c71abcad3f9e10aa8e987ee801e20407a98344295e008657aab9",
"size": 67664
},
"python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "c71f7680e32cee7117409c399e915ad3740120c76a3e74af843d7f04644f0d08",
"sha256": "e049af92c953da53db2728f23484d8d691c9834d4130e3b6caa19c3ae69ce86d",
"size": 204624
},
"python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "71d52c82a254f0a66bc78dd947623747131a8883579f73fa61915d17bd2f4787",
"sha256": "a73a6a7ba5ac0a87d114db02e895921f0c452e9a8c6bd622116d94c347216ef1",
"size": 69752
},
"python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "1163d7ffafaa9179812c65362c3b99d47bd880747731009bf7d81cdef872f2d0",
"sha256": "692bde7a464bcef05c8b684224cc8fd6a6c05d226775ed3e81b6a02c748e11c5",
"size": 203072
},
"python/iqpilot_private/konn3kt/hephaestus/__init__.py": {
@@ -46,67 +46,67 @@
},
"python/iqpilot_private/konn3kt/hephaestus/_vendor/localapi_runtime.zip": {
"mode": 420,
"sha256": "a6f2e86d5f44caabab7070263d9cc17c9222365e8f1ef04a1a6d27db0d2c2e88",
"sha256": "832067fea89470fc6224abc8b49c2624e0278e0027ea4e0bb93f939e03938230",
"size": 2100238
},
"python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "fbe4f442f7914a0238b7e78bfebe7b99f19e517122bfa5b2467c46ed73df1f05",
"sha256": "92b5f941d9198bdd12915996216014d4bbc9b13c1b2435c20b9a2811661b23e3",
"size": 268064
},
"python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "3c4a6df8c4458fbefefe8761aaf99732b5f62bcb4bb4a5b1068b5f42b0fc9da7",
"sha256": "4a71f1c7f88fdbd51707812370e733d30b22c0c46a2f22ce32d1757debc14cff",
"size": 340584
},
"python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "79a9ec735831f904ae635d6628695fe7a985430a0ee81e7d7e58842f7588d61e",
"sha256": "25d6899e8ebb8c0c5d813d522033d115502d9b622882c0e59f276406702d9e57",
"size": 68048
},
"python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "a93df625aca20374031343cbbbef4f8c2a819d69680205f9ac5c92a3841c24d9",
"sha256": "abee9f335c9ddabaa85f341cb33aaf5eebc433b2397b71c921667329728808bc",
"size": 335728
},
"python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "116dbd9cd287c4bb55672233b66601d2af9e023be03b78d6aec39d8c2a4eef04",
"sha256": "b5900c92a037f7ac88199b515f91692c0f86c45981ca3c929b6cbeb6ad6002a0",
"size": 271680
},
"python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "c9d3e1cfdd36e30b6546e43a9cf51c2608a08210ac97d818bbbf098b6cc0a50f",
"sha256": "d8ebf16a39d29f9932fd1277bd0d552b60a748b0bad6d5c6314cfe5e80859ce2",
"size": 134408
},
"python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "b3f2772b58d09c27042e4e0f9147a6ff45bcd6d198e32a6993bc9ca411110e6a",
"sha256": "6f50c91b87b5e37033b2f7a9db22f01aba9bf5e31733b6e753a23c211ae71492",
"size": 3514416
},
"python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "d37822e6fc68f07b22145fb7aaac87795af585221dc148d4ef2477580509dda6",
"sha256": "63eb11f7251748dab6ad9ba7483ace77b0709f0a3f59492d5a9f2b50bfd9e1ad",
"size": 136448
},
"python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "8c3c93cce17f873983c70396fe194c705ae19bc180ec6c4658183777a6d3fa03",
"sha256": "88d2df85126983f2036badc3fac85ee25d79119c95bbe983030c6ea756da111b",
"size": 68136
},
"python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "1ac1dcdc3983907a0e653b9769c1bf32e46ad5e4302b7993805a8e1f02958f47",
"sha256": "f0aa1d1e50f73a27fff17a40c16affafbfdd56239da484ac04315e55a7018e0e",
"size": 67840
},
"python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "f81235f79eb78c77a3811e3676b5c76c49e09ca20c9cf3c01e5aa4640ef3de6c",
"sha256": "5e4f675dbc70a3cd21156727f430fec31ecee99f28af3873fea89fb185dba39d",
"size": 135648
},
"python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "fd1683c047a47b54c17581e749d8448c664f4f84549e6129ff0c50f9e335f324",
"sha256": "6f9d47e0d6c4156335fcfd6562022dbfad2dd40c860fac20288be43823195443",
"size": 269568
},
"python/iqpilot_private/konn3kt/uploaderd/__init__.py": {
@@ -116,7 +116,7 @@
},
"python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "515f4e9a3865c8c5b34926005471df7328d2061034d8d490ad6c6556e4754fad",
"sha256": "995b9bcfa8544066a4b71565e834bedc4c1c3dd6b54e14765ef2365d32ccfe05",
"size": 204184
},
"runtime": {
@@ -148,23 +148,23 @@
}
},
"signatures": {
"python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so": "szqc9yDkYsxkYPyEfqBdz1B/T8WcrjvKjja+ORcUqAXVr4kPz5MQu2oT5HyJJ02NnR2QQ+OcVWgIR85aUg/VBA==",
"python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so": "S+fnijAxAphfMnzAB/zXpi8tPX2GGZUecpPwhfdO1eNnzuFyqPiV6Q6q7vSr3dD86lG3BPTfJZCFRmGwc0rpBg==",
"python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so": "4xbYBIqUjczGMGWoz2P2PCCh+NGrPOKnWGluwPStk+oJHzZlVBnpj389tSqzJJzOyAJo2hA1GYeuMkfG8ETcCQ==",
"python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so": "VdS8oqeVMuNiLyrU9REZ4YV84XLSV8MyaKTTWDk20lYGJpQU4wBRLwla6Tq8WrwlaRgZmdX9H1msMwV0WVFHBQ==",
"python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so": "btwzW4V9KItwXYbRVjA8oYfI1y0xhvNfFseIuxO5o4uVsZ2h3W5WWoeZ3m+h1GvjcT/Ucdhn6lC3XbJxxfWgDQ==",
"python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so": "1andY86F9L840fIgJekSJQSvpRDZMr4JbNYZn40K/9dcs5F/dQ6s5IyiZwpS2+4W/hDCZiVqCz05f5o96+E+DQ==",
"python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so": "JcJPlG9hSIWbcR8038As7VDvYVJNBg6L9qMr0ElBtHSvewFqcJ5tK4/swIo3IJS4DZpLjCwtIMmu+DqGQsnGCg==",
"python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so": "KuA+FLmbERkD5+C+Bl9G+GNGHPEbbc79onDNkUTMtZNr7YxTIx7Py71K0WQkP0qa5sgxr17/hF7kQszTBtzFAg==",
"python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so": "O2p0H5siPJtTC0x72el2IEyoFSa/N+wvL9/G+XMgurZI6DQqqQrs+igpYvFFI1U2UO6lJwhxZxb2RbKaIhT8Bw==",
"python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so": "XVgvLfvS1KtjzGCYXLanTWE392+DBZGQxP41cTvUiyzf+MXUo9jRjV8xXVpVTmCjN6sqFhJccIcYdUh2cTp1BA==",
"python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so": "iAlR196MOtgXdBLyOUhk19M2PAT1HjBQRlbEmuLrtKFCeHQC124ewsjClYVq/Hy6N+ksqzhSMeAL2hU6NcfTCQ==",
"python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so": "ymo9xAJEpoER5GLSWNLsOSxnZZ+Rwe0GUVTsxLGX7/tuLUNMPq0Og/yQ8D5EpTgaPGV3wPUFLsLBiWv//OXZDA==",
"python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so": "PUPoFMxOzzmgaIFa0aTaKZDN81v2qTLj6j4jZkXnGlHXKfGbVpBLBYq8ytujJvamGevvVa5cssEA3XbMLFq8CQ==",
"python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so": "JGyDxUcUXvCd8lwNaLscpIo9vKTNRvtKd9roHI+kLa9OImJfk1XFAn7qY/LFEfqcpga0vRcucZLqa5T1YB/gDw==",
"python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so": "9Kb9lnsLYhTCC7ctxVYvwO2iODIW0Z6NJ7+R+6BvIBV3ejL4yc8YVxjde0skgdjN5SvqlvRO1uG/ZE6aqK3VCQ==",
"python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so": "8u8bDBQ7SxYTWX+cEMeAH0DQ+hoZDfjYyOzU+sBzrtZylUVZyzlRjohciDDQXF2bpxnuNQUWb4GgE41Y60hlCg==",
"python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so": "8PyCivu4UmKF+biAg5aTRFRf6pSM6jt65/n0lrXgo4Ftpk4mNd623b/K/jPf+6wjgC8Sbqp40wNFwel0RUifAg==",
"python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so": "GpPbShzcrAK4tP9pRg+SJh0WZ8Me0mxEVEL6ED7v/tK3Az3KTDf4jU5a3Bhg/Q/IrWxqNlBg/RPdOv2RYMBPDA=="
"python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so": "UehTRkDLBq77ERDm+ZSjxDU3+5EpJUOIzs5zk7Fz8Aru6yQX9ytRexns4dGse8BlIveGuHpWq+L+GvjG0Hf4Bw==",
"python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so": "uddHEDnsMjWbMeWotUzZES/3hyLuPmZM1ENCkcTxMYXzM0g0YfbyOJlzq2FuSL4Zg2Hl+PyM/nmnEYbi88NIBg==",
"python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so": "2gPFBBZeMfvlnGtQkP6JMI/8c6uanTylvVtZ+1cifaK/ixsGDyfw051gv28uorxjDvRHbgGab/q2n3QYZj8EBA==",
"python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so": "KwOoTQlcNJA//GwfMeS8e1yw9agzaJDa/oUXXhiEFyrdEgZurmLbV0slgxUR+hC/LLrrzqqsw1BjQcYuqVXdCw==",
"python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so": "BbNS1vTfoizdCnZE3j/2kbY84uXDcGk0WgQ+nmBtySNBBJgT/5HspuY/AOxHukgVyjh7vm7BCnBuJO6/Gm30AQ==",
"python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so": "HU6uqhzgAx6mA9ScihdhYvmknQ9kZbI2p4a/ViB4BLo1OTZnfhFecQQ3rnvXNLGOyfbacqooz+s+JRuSOqEmDw==",
"python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so": "Nw/QTfb9gk1QgTWKvacfS4BlKZ3DuWJKf5ll/H4Hb8YEaXmYz1xU0klwcybjHPs4twA5qsYUnjmzL110llD+Cw==",
"python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so": "WE552SVLgy0vmwvrJv54kW4bDyjB9bKUhMnGa+OI/L7WZT/ReWm3H2NbT0TzWZEGbzFHKr4I01Zmi+MHJGVrAQ==",
"python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so": "N9u9KO1e4Xc9su7MndJ6MfyDMY1eV89xbIy6Qo5F5eg0xqfl8QGyYcUU6btIOFdrpRdpWxXTukff9FbU0c+RBg==",
"python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so": "t9HmTDU8a0a3rhm9rxzbUaYalAmjASZRbgCku8rg6AxQJohJo3eMVmH7dy7A6vtFvhYvvD9Ywi9kKeUaPTvPCQ==",
"python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so": "Oq2wyp4UTAQg/Q16pgCJ9+C/4zi4ljCOHJRcnYXhUk997Tq/5LuBHBstfxrq9ZLubF2ntLLw5UhePtehjLliDg==",
"python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so": "n2X6vqTFDy3dGiTiI9kWfAYySl0srw30k5aDqN/YWTzZomQabwZ1ETmUC6TIG3Wag074XNEJgrZhiguN1wgeAg==",
"python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so": "ami2SR9/GUXkFRDB5hN/JrJO4rz2piQNtEYJFAsvssLmcqzVPHehRIy61gctjKr5kBLOfUGJjpNU3ceswOUWBg==",
"python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so": "wCeURfEwJlXuy7FYiJ3ZWUJZUp8ehKehKqWH/nNyo+GlSlC8YhAGNvQxwZ9FH0agOsSQVHMExnL4ofLvJOytAA==",
"python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so": "+G2me3BkbbjwwtVfjGz/ePsXQwNde7Y9bLELSRk8tDxLdGHWkFCU9i8ba8vue7uqfMTnRq5opCDFdIXvY7CwDg==",
"python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so": "lh63nHd0YApA9e9+C8SnRd+DILlprzpzt2PR8S6x8VSMQAzAySS9xuJ8Jw76JMpIItzW030n5/wazi4i/gK+Aw==",
"python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so": "3fYQP73XdXlWREMsM+P7D9EUSAwrLuih17DqmbDfQDa0S0TKbXcWJgRMbeOHRUDMZ04sUDrli82OfAkz6vlyBQ==",
"python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so": "UtM9t4Db3LX6RfiMkADMI7Skre5FtPvjPB2xNuJofd4fVtrLo7r4YYcSOmq7jo4+UviYp4N3CPiGGoOc6WHzAA=="
}
}
+53
View File
@@ -4,6 +4,59 @@ collect_ignore_glob = [
"iqdbc/safety/tests/misra/cppcheck/",
]
# --- host test harness -------------------------------------------------------
# tesla/volkswagen carstate+carcontroller import the closed-source ALC / odometer
# runtime via import_verified_module(), which gates on a rootfs integrity manifest
# that only exists on-device. Off-device (host CI / dev), install minimal stubs so
# the whole car interface set is importable and test_car_interfaces can collect and
# run. On-device the manifest is present and these stubs are never installed, so the
# real verified modules are used.
import os as _os
if not _os.path.exists("/usr/libexec/iqpilot/runtime_integrity.json"):
import sys as _sys
import types as _types
def _stub_module(name, attrs):
mod = _types.ModuleType(name)
for key, value in attrs.items():
setattr(mod, key, value)
_sys.modules[name] = mod
_noop = lambda *args, **kwargs: None # noqa: E731
class _VehicleOdometerStoreStub:
def __init__(self, *args, **kwargs):
pass
def record(self, km):
return km
_stub_module("iqpilot_private.konn3kt.iqlvbs.vehicle_state",
{"VehicleOdometerStore": _VehicleOdometerStoreStub})
_stub_module("iqpilot_private.konn3kt.iqlvbs.alc", {
"angle_lateral_control_enabled": lambda *a, **k: False,
"update_vw_alc": _noop,
"append_private_apd": _noop,
"update_mqb_carstate_alc_state": _noop,
"update_mlb_carstate_alc_state": _noop,
"update_pq_carstate_alc_state": _noop,
})
_stub_module("iqpilot_private.konn3kt.iqlvbs.iqlvbs_commander", {})
_stub_module("iqpilot_private.konn3kt.hephaestus.vw_pq_flasher", {})
try:
from openpilot.system.proprietary_runtime import _verified_import as _vi
_real_import_verified_module = _vi.import_verified_module
def _import_verified_module(bundle, module):
return _sys.modules.get(module) or _real_import_verified_module(bundle, module)
_vi.import_verified_module = _import_verified_module
except Exception:
pass
# --- end host test harness ---------------------------------------------------
_ABSTRACT_BASES = frozenset(("CarSafetyTest", "AolSafetyTestBase", "SafetyTest", "SafetyTestBase"))
def _method_from_base(cls, method_name):
+6 -3
View File
@@ -4,8 +4,8 @@ from iqdbc.car.chrysler.values import DBC, STEER_THRESHOLD, RAM_CARS
from iqdbc.car.common.conversions import Conversions as CV
from iqdbc.car.interfaces import CarStateBase
from iqdbc.iqpilot.car.chrysler.carstate_ext import CarStateExt
from iqdbc.iqpilot.car.chrysler.aol import AolCarState
from iqdbc.iqpilot.car.chrysler.carstate_ext import CarStateExt
ButtonType = structs.CarState.ButtonEvent.Type
@@ -114,7 +114,10 @@ class CarState(CarStateBase, AolCarState, CarStateExt):
@staticmethod
def get_can_parsers(CP, CP_IQ):
pt_messages: list = []
cam_messages: list = []
AolCarState.get_parser(CP, pt_messages, cam_messages)
return {
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 0),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 2),
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], pt_messages, 0),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], cam_messages, 2),
}
@@ -1,10 +1,10 @@
""" AUTO-FORMATTED USING iqdbc/car/debug/format_fingerprints.py, EDIT STRUCTURE THERE."""
from iqdbc.car.structs import CarParams
from iqdbc.car.chrysler.values import CAR
from iqdbc.iqpilot.car.fingerprints_ext import merge_fw_versions
from iqdbc.iqpilot.car.chrysler.fingerprints_ext import FW_VERSIONS_EXT
Ecu = CarParams.Ecu
FW_VERSIONS = {
@@ -789,4 +789,6 @@ FW_VERSIONS = {
},
}
FW_VERSIONS = merge_fw_versions(FW_VERSIONS, FW_VERSIONS_EXT)
+2 -1
View File
@@ -100,9 +100,10 @@ class CarInterface(CarInterfaceBase):
stock_cp.wheelbase = 3.79
stock_cp.steerRatio = 19.
# LKAS heartbeat on bus 0 (msg 0x4FF) means the camera is on the ADAS bus and
# IQ.Pilot can steer down to a standstill.
if 0x4FF in fingerprint[0]:
ret.flags |= ChryslerFlagsIQ.NO_MIN_STEERING_SPEED.value
stock_cp.minSteerSpeed = 0.
return ret
+1 -6
View File
@@ -5,17 +5,14 @@ from iqdbc.car.ford.fordcan import CanBus
from iqdbc.car.ford.values import DBC, CarControllerParams, FordFlags
from iqdbc.car.interfaces import CarStateBase
from iqdbc.iqpilot.car.ford.aol import AolCarState
ButtonType = structs.CarState.ButtonEvent.Type
GearShifter = structs.CarState.GearShifter
TransmissionType = structs.CarParams.TransmissionType
class CarState(CarStateBase, AolCarState):
class CarState(CarStateBase):
def __init__(self, CP, CP_IQ):
CarStateBase.__init__(self, CP, CP_IQ)
AolCarState.__init__(self, CP, CP_IQ)
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
if CP.transmissionType == TransmissionType.automatic:
self.shifter_values = can_define.dv["PowertrainData_10"]["TrnRng_D_Rq"]
@@ -112,8 +109,6 @@ class CarState(CarStateBase, AolCarState):
self.acc_tja_status_stock_values = cp_cam.vl["ACCDATA_3"]
self.lkas_status_stock_values = cp_cam.vl["IPMA_Data"]
AolCarState.update_aol(self, ret, can_parsers)
ret.buttonEvents = [
*create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise}),
*create_button_events(self.lc_button, prev_lc_button, {1: ButtonType.lkas}),
+4 -1
View File
@@ -1,7 +1,6 @@
# ruff: noqa: E501
""" AUTO-FORMATTED USING iqdbc/car/debug/format_fingerprints.py, EDIT STRUCTURE THERE."""
from iqdbc.car.gm.values import CAR
from iqdbc.iqpilot.car.fingerprints_ext import merge_fingerprints
from iqdbc.iqpilot.car.gm.fingerprints_ext import FINGERPRINTS_EXT
@@ -54,6 +53,9 @@ FINGERPRINTS = {
}],
CAR.CHEVROLET_SILVERADO: [{
190: 6, 193: 8, 197: 8, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 460: 5, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 528: 5, 532: 6, 534: 2, 560: 8, 562: 8, 563: 5, 565: 5, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 761: 7, 789: 5, 800: 6, 801: 8, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 869: 4, 880: 6, 977: 8, 1001: 8, 1011: 6, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1611: 8, 1930: 7
},
{
190: 6, 193: 8, 197: 8, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 3, 288: 5, 289: 8, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 460: 5, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 528: 5, 532: 6, 534: 2, 560: 8, 562: 8, 563: 5, 565: 5, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 761: 7, 789: 5, 800: 6, 801: 8, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 869: 4, 880: 6, 977: 8, 1001: 8, 1011: 6, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1611: 8, 1930: 7
}],
CAR.CHEVROLET_EQUINOX: [{
190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 510: 8, 528: 5, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 789: 5, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 880: 6, 977: 8, 1001: 8, 1011: 6, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1611: 8, 1930: 7
@@ -78,4 +80,5 @@ FINGERPRINTS = {
FW_VERSIONS: dict[str, dict[tuple, list[bytes]]] = {
}
FINGERPRINTS = merge_fingerprints(FINGERPRINTS, FINGERPRINTS_EXT)
+7 -8
View File
@@ -16,7 +16,7 @@ from iqdbc.iqpilot.car.gm.values_ext import GMFlagsIQ, GMSafetyFlagsIQ
TransmissionType = structs.CarParams.TransmissionType
NetworkLocation = structs.CarParams.NetworkLocation
# iqpilot-specific torque parameters for Bolt cars that actually use the d parameter
# Bolt Non-ACC uses the 4th (d) tune parameter; stock tunes zero it out.
NON_LINEAR_TORQUE_PARAMS_IQ = {
CAR.CHEVROLET_BOLT_NON_ACC: [2.24, 1.1, 0.28, -0.07],
CAR.CHEVROLET_BOLT_NON_ACC_1ST_GEN: [1.8, 1.1, 0.3, -0.045],
@@ -241,11 +241,10 @@ class CarInterface(CarInterfaceBase, CarInterfaceExt):
CAR.CHEVROLET_BOLT_NON_ACC_2ND_GEN, CAR.CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN):
stock_cp.steerActuatorDelay = 0.2
CarInterfaceBase.configure_torque_tune(candidate, stock_cp.lateralTuning)
elif candidate in (CAR.CHEVROLET_EQUINOX_NON_ACC_3RD_GEN, ):
CarInterfaceBase.configure_torque_tune(candidate, stock_cp.lateralTuning)
# NON_ACC vehicles should use camera car speed thresholds
# Non-ACC cars steer/long via the forward camera and pcmCruise, not the ASCM.
if ret.flags & GMFlagsIQ.NON_ACC:
stock_cp.dashcamOnly = False
stock_cp.alphaLongitudinalAvailable = False
@@ -254,13 +253,13 @@ class CarInterface(CarInterfaceBase, CarInterfaceExt):
stock_cp.pcmCruise = True
stock_cp.safetyConfigs[0].safetyParam |= GMSafetyFlags.HW_CAM.value
ret.iqSafetyFlags |= GMSafetyFlagsIQ.NON_ACC
stock_cp.minEnableSpeed = 24 * CV.MPH_TO_MS # 24 mph
stock_cp.minSteerSpeed = 3.0 # ~6 mph
stock_cp.minEnableSpeed = 24 * CV.MPH_TO_MS
stock_cp.minSteerSpeed = 3.0
# dashcamOnly platforms: untested platforms, need user validations
# Untested Non-ACC platforms ship dashcam-only pending user validation.
if candidate in (CAR.CHEVROLET_BOLT_NON_ACC_2ND_GEN, CAR.CHEVROLET_EQUINOX_NON_ACC_3RD_GEN,
CAR.CHEVROLET_SUBURBAN_NON_ACC_11TH_GEN, CAR.CADILLAC_CT6_NON_ACC_1ST_GEN, CAR.CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN,
CAR.CADILLAC_XT5_NON_ACC_1ST_GEN):
CAR.CHEVROLET_SUBURBAN_NON_ACC_11TH_GEN, CAR.CADILLAC_CT6_NON_ACC_1ST_GEN,
CAR.CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN, CAR.CADILLAC_XT5_NON_ACC_1ST_GEN):
stock_cp.dashcamOnly = True
return ret
+10 -17
View File
@@ -4,9 +4,8 @@ from enum import Enum, IntFlag
from iqdbc.car import Bus, PlatformConfig, DbcDict, Platforms, CarSpecs
from iqdbc.car.structs import CarParams
from iqdbc.car.docs_definitions import CarDocs, CarFootnote, CarHarness, CarParts, Column, SupportType
from iqdbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
from iqdbc.iqpilot.car.gm.values_ext import GMFlagsIQ
from iqdbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
Ecu = CarParams.Ecu
@@ -88,13 +87,6 @@ class GMCarDocs(CarDocs):
self.car_parts = CarParts.common([CarHarness.obd_ii])
@dataclass
class GMNonAccCarDocs(GMCarDocs):
package: str = "No Adaptive Cruise Control (Non-ACC)"
support_type: SupportType = SupportType.COMMUNITY
support_link: str = "community"
@dataclass(frozen=True, kw_only=True)
class GMCarSpecs(CarSpecs):
tireStiffnessFactor: float = 0.444 # not optimized yet
@@ -123,6 +115,13 @@ class GMSDGMPlatformConfig(GMPlatformConfig):
self.car_docs = []
@dataclass
class GMNonAccCarDocs(GMCarDocs):
package: str = "No Adaptive Cruise Control (Non-ACC)"
support_type: SupportType = SupportType.COMMUNITY
support_link: str = "community"
@dataclass
class GMNonSccPlatformConfig(GMPlatformConfig):
def init(self):
@@ -209,13 +208,7 @@ class CAR(Platforms):
GMCarSpecs(mass=2490, wheelbase=2.94, steerRatio=17.3, centerToFrontRatio=0.5, tireStiffnessFactor=1.0),
)
# port extensions
# Separate car def is required when there is no ASCM
# (for now) unless there is a way to detect it when it has been unplugged...
# CHEVROLET_VOLT_CC = GMNonSccPlatformConfig(
# [GMNonAccCarDocs("Chevrolet Volt LT 2017-18")],
# CHEVROLET_VOLT.specs,
# )
# IQ.Pilot Non-ACC camera-harness ports (no factory adaptive cruise).
CHEVROLET_BOLT_NON_ACC = GMNonSccPlatformConfig(
[GMNonAccCarDocs("Chevrolet Bolt EV Non-ACC 2017")],
CHEVROLET_BOLT_EUV.specs,
@@ -333,7 +326,7 @@ FW_QUERY_CONFIG = FwQueryConfig(
# TODO: detect most of these sets live
EV_CAR = {CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT_2019, CAR.CHEVROLET_BOLT_EUV,
# port extensions, Non-ACC
# Non-ACC EV ports
CAR.CHEVROLET_BOLT_NON_ACC, CAR.CHEVROLET_BOLT_NON_ACC_1ST_GEN, CAR.CHEVROLET_BOLT_NON_ACC_2ND_GEN}
# We're integrated at the camera with VOACC on these cars (instead of ASCM w/ OBD-II harness)
+1
View File
@@ -5,6 +5,7 @@ from iqdbc.car import Bus, create_button_events, structs
from iqdbc.car.common.conversions import Conversions as CV
from iqdbc.car.interfaces import CarStateBase
from iqdbc.car.nissan.values import CAR, DBC, CarControllerParams
from iqdbc.iqpilot.car.nissan.carstate_ext import CarStateExt
ButtonType = structs.CarState.ButtonEvent.Type
+2
View File
@@ -39,6 +39,8 @@ class CarInterface(CarInterfaceBase):
@staticmethod
def _get_params_iq(stock_cp: structs.CarParams, ret: structs.IQCarParams, candidate, fingerprint: dict[int, dict[int, int]],
car_fw: list[structs.CarParams.CarFw], alpha_long: bool, is_release_iq: bool, docs: bool) -> structs.IQCarParams:
# Longitudinal harness upgrade advertises msg 0x31a on bus 5; when present it
# unlocks radar, blind-spot and openpilot longitudinal on Rivian.
if 0x31a in fingerprint[5]:
ret.flags |= RivianFlagsIQ.LONGITUDINAL_HARNESS_UPGRADE.value
stock_cp.radarUnavailable = False
@@ -99,3 +99,14 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"SUBARU_FORESTER_PREGLOBAL" = "SUBARU_IMPREZA"
"SUBARU_LEGACY_PREGLOBAL" = "SUBARU_IMPREZA"
"SUBARU_ASCENT" = "SUBARU_FORESTER"
# IQ.Pilot GM Non-ACC ports borrow their base platform's lateral tune
"CHEVROLET_BOLT_NON_ACC" = "CHEVROLET_BOLT_EUV"
"CHEVROLET_BOLT_NON_ACC_1ST_GEN" = "CHEVROLET_BOLT_EUV"
"CHEVROLET_BOLT_NON_ACC_2ND_GEN" = "CHEVROLET_BOLT_EUV"
"CHEVROLET_EQUINOX_NON_ACC_3RD_GEN" = "CHEVROLET_EQUINOX"
"CHEVROLET_SUBURBAN_NON_ACC_11TH_GEN" = "CHEVROLET_SILVERADO"
"CADILLAC_CT6_NON_ACC_1ST_GEN" = "CHEVROLET_VOLT"
"CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN" = "CHEVROLET_TRAILBLAZER"
"CHEVROLET_MALIBU_NON_ACC_9TH_GEN" = "CHEVROLET_VOLT"
"CADILLAC_XT5_NON_ACC_1ST_GEN" = "CADILLAC_XT4"
+1 -1
View File
@@ -171,7 +171,7 @@ class CarInterface(CarInterfaceBase):
ret.steerLimitTimer = 0.4
if ret.flags & VolkswagenFlags.PQ:
ret.steerActuatorDelay = 0.2
ret.longitudinalTuning.kfDEPRECATED = 1.2
ret.longitudinalTuning.kf = 1.2
ret.longitudinalTuning.kpBP = [0.]
ret.longitudinalTuning.kpV = [.45]
ret.longitudinalTuning.kiBP = [0.]
@@ -1,5 +1,6 @@
import pytest
from iqdbc.car.volkswagen.interface import CarInterface
from iqdbc.car.volkswagen.values import (
CAR, PASSAT_B7_STOP_ACCEL, PASSAT_B7_STOPPING_SPEED, PQ_STOPPING_SPEED,
VolkswagenFlags, apply_pq_stopping_accel, get_longitudinal_stopping_speed_override,
@@ -20,3 +21,13 @@ def test_passat_b7_stop_accel_is_exact():
assert apply_pq_stopping_accel(CAR.VOLKSWAGEN_PASSAT_B7, -0.2, True) == PASSAT_B7_STOP_ACCEL == -0.55
assert apply_pq_stopping_accel(CAR.VOLKSWAGEN_PASSAT_B7, -0.2, False) == -0.2
assert apply_pq_stopping_accel(CAR.VOLKSWAGEN_JETTA_MK6, -0.2, True) == -0.2
@pytest.mark.parametrize("candidate", [
CAR.VOLKSWAGEN_JETTA_MK6,
CAR.VOLKSWAGEN_PASSAT_NMS,
])
def test_pq_longitudinal_feedforward_uses_active_schema_field(candidate):
fingerprint = {bus: {} for bus in range(8)}
cp = CarInterface.get_params(candidate, fingerprint, [], alpha_long=True, is_release=False, docs=False)
assert cp.longitudinalTuning.kf == pytest.approx(1.2)
@@ -1,3 +0,0 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
+18 -34
View File
@@ -1,21 +1,23 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
Always-on-Lateral adapter for Chrysler. CarState reads the LKAS toggle button
(and the forwarded LKAS heartbeat); CarController tracks the AOL state and, when
AOL is available, drives the LKAS_DISABLED bit the dash reads from the heartbeat.
"""
from enum import StrEnum
from collections import namedtuple
from iqdbc.car import Bus, structs
from iqdbc.car.chrysler.values import RAM_CARS
from iqdbc.iqpilot.aol_base import AolCarStateBase
from iqdbc.can.parser import CANParser
AolDataIQ = namedtuple("AolDataIQ",
["enable_aol", "paused", "lkas_disabled"])
AolDataIQ = namedtuple("AolDataIQ", ["enable_aol", "paused", "lkas_disabled"])
ButtonType = structs.CarState.ButtonEvent.Type
_HEARTBIT_FIELDS = ("LKAS_DISABLED", "AUTO_HIGH_BEAM", "FORWARD_1", "FORWARD_2", "FORWARD_3")
class AolCarController:
def __init__(self):
@@ -23,28 +25,18 @@ class AolCarController:
@staticmethod
def create_lkas_heartbit(packer, lkas_heartbit, aol):
# LKAS_HEARTBIT (0x2D9) LKAS heartbeat
values = {s: lkas_heartbit[s] for s in [
"LKAS_DISABLED",
"AUTO_HIGH_BEAM",
"FORWARD_1",
"FORWARD_2",
"FORWARD_3",
]}
values = {name: lkas_heartbit[name] for name in _HEARTBIT_FIELDS}
if aol.enable_aol:
values["LKAS_DISABLED"] = 1 if aol.lkas_disabled else 0
return packer.make_can_msg("LKAS_HEARTBIT", 0, values)
@staticmethod
def aol_status_update(CC: structs.CarControl, CC_IQ: structs.IQCarControl, CS) -> AolDataIQ:
enable_aol = CC_IQ.aol.available
paused = CC_IQ.aol.enabled and not CC.latActive
# A tap of the LKAS button flips the driver's "LKAS disabled" preference.
if any(be.type == ButtonType.lkas and be.pressed for be in CS.out.buttonEvents):
CS.lkas_disabled = not CS.lkas_disabled
return AolDataIQ(enable_aol, paused, CS.lkas_disabled)
def update(self, CC: structs.CarControl, CC_IQ: structs.IQCarControl, CS) -> None:
@@ -55,35 +47,27 @@ class AolCarState(AolCarStateBase):
def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
super().__init__(CP, CP_IQ)
self.lkas_heartbit = 0
self.init_lkas_disabled = False
self.lkas_disabled = False
@staticmethod
def get_parser(CP, pt_messages, cam_messages) -> None:
if CP.carFingerprint in RAM_CARS:
pt_messages += [
("Center_Stack_2", 1),
]
pt_messages.append(("Center_Stack_2", 1))
else:
pt_messages.append(("TRACTION_BUTTON", 1))
cam_messages.append(("LKAS_HEARTBIT", 1))
def get_lkas_button(self, cp, cp_cam):
def _read_lkas_button(self, cp, cp_cam) -> int:
if self.CP.carFingerprint in RAM_CARS:
lkas_button = cp.vl["Center_Stack_2"]["LKAS_Button"]
else:
lkas_button = cp.vl["TRACTION_BUTTON"]["TOGGLE_LKAS"]
self.lkas_heartbit = cp_cam.vl["LKAS_HEARTBIT"]
if not self.init_lkas_disabled:
self.lkas_disabled = cp_cam.vl["LKAS_HEARTBIT"]["LKAS_DISABLED"]
self.init_lkas_disabled = True
return cp.vl["Center_Stack_2"]["LKAS_Button"]
return lkas_button
self.lkas_heartbit = cp_cam.vl["LKAS_HEARTBIT"]
if not self.init_lkas_disabled:
self.lkas_disabled = cp_cam.vl["LKAS_HEARTBIT"]["LKAS_DISABLED"]
self.init_lkas_disabled = True
return cp.vl["TRACTION_BUTTON"]["TOGGLE_LKAS"]
def update_aol(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
cp = can_parsers[Bus.pt]
cp_cam = can_parsers[Bus.cam]
self.prev_lkas_button = self.lkas_button
self.lkas_button = self.get_lkas_button(cp, cp_cam)
self.lkas_button = self._read_lkas_button(can_parsers[Bus.pt], can_parsers[Bus.cam])
@@ -1,5 +1,8 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
Chrysler low-speed steering gate: overrides the stock LKAS control bit when the
no-min-steering-speed option is set, and holds the RAM DT engagement window.
"""
from iqdbc.car import structs
from iqdbc.car.interfaces import CarStateBase
@@ -16,8 +19,9 @@ class CarControllerExt:
def get_lkas_control_bit(self, CS: CarStateBase, CC: structs.CarControl, lkas_control_bit: bool) -> bool:
if self.CP_IQ.flags & ChryslerFlagsIQ.NO_MIN_STEERING_SPEED:
lkas_control_bit = CC.latActive
elif self.CP.carFingerprint in RAM_DT:
return CC.latActive
if self.CP.carFingerprint in RAM_DT:
if self.CP.minEnableSpeed <= CS.out.vEgo <= self.CP.minEnableSpeed + 0.5:
lkas_control_bit = True
if self.CP.minEnableSpeed >= 14.5 and CS.out.gearShifter != GearShifter.drive:
@@ -1,13 +1,13 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
Chrysler cruise-button reader: emits edge ButtonEvents for the ACC steering-wheel
buttons so IQ.Pilot can react to accel/decel/cancel/resume.
"""
from enum import StrEnum
from iqdbc.car import Bus, structs
from iqdbc.can.parser import CANParser
from iqdbc.car.chrysler.values import RAM_HD
from iqdbc.iqpilot.car.chrysler.values_ext import BUTTONS
@@ -15,23 +15,18 @@ class CarStateExt:
def __init__(self, CP, CP_IQ):
self.CP = CP
self.CP_IQ = CP_IQ
self.button_events = []
self.button_events: list = []
self.button_states = {button.event_type: False for button in BUTTONS}
def update(self, ret: structs.CarState, ret_iq: structs.IQCarState, can_parsers: dict[StrEnum, CANParser]):
def update(self, ret: structs.CarState, ret_iq: structs.IQCarState, can_parsers: dict[StrEnum, CANParser]) -> None:
cp = can_parsers[Bus.pt]
button_events = []
events = []
for button in BUTTONS:
state = (cp.vl[button.can_addr][button.can_msg] in button.values)
if self.button_states[button.event_type] != state:
pressed = cp.vl[button.can_addr][button.can_msg] in button.values
if pressed != self.button_states[button.event_type]:
event = structs.CarState.ButtonEvent.new_message()
event.type = button.event_type
event.pressed = state
button_events.append(event)
self.button_states[button.event_type] = state
self.button_events = button_events
if self.CP.carFingerprint in RAM_HD:
ret.steeringAngleDeg = cp.vl["STEERING"]["STEERING_ANGLE"]
event.pressed = pressed
events.append(event)
self.button_states[button.event_type] = pressed
self.button_events = events
@@ -1,7 +1,9 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
IQ.Pilot Chrysler extension flags + the cruise-button table read by the AOL
cruise-button reader.
"""
from collections import namedtuple
from enum import IntFlag
@@ -20,5 +22,3 @@ BUTTONS = [
class ChryslerFlagsIQ(IntFlag):
NO_MIN_STEERING_SPEED = 1
@@ -1,3 +0,0 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
-21
View File
@@ -1,21 +0,0 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
from enum import StrEnum
from iqdbc.car import Bus,structs
from iqdbc.iqpilot.aol_base import AolCarStateBase
from iqdbc.can.parser import CANParser
class AolCarState(AolCarStateBase):
def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
super().__init__(CP, CP_IQ)
def update_aol(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
cp = can_parsers[Bus.pt]
self.prev_lkas_button = self.lkas_button
self.lkas_button = cp.vl["Steering_Data_FD1"]["TjaButtnOnOffPress"]
@@ -1,3 +0,0 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
@@ -1,5 +1,8 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
Non-ACC GM carState: these cars have no adaptive cruise, so cruise engage/set
speed come from the stock (non-adaptive) ECM cruise message.
"""
from enum import StrEnum
@@ -15,9 +18,9 @@ class CarStateExt:
self.CP_IQ = CP_IQ
def update(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
if not self.CP_IQ.flags & GMFlagsIQ.NON_ACC:
return
pt_cp = can_parsers[Bus.pt]
if self.CP_IQ.flags & GMFlagsIQ.NON_ACC:
ret.cruiseState.enabled = pt_cp.vl["ECMCruiseControl"]["CruiseActive"] != 0
ret.cruiseState.speed = pt_cp.vl["ECMCruiseControl"]["CruiseSetSpeed"] * CV.KPH_TO_MS
ret.accFaulted = False
ret.cruiseState.enabled = pt_cp.vl["ECMCruiseControl"]["CruiseActive"] != 0
ret.cruiseState.speed = pt_cp.vl["ECMCruiseControl"]["CruiseSetSpeed"] * CV.KPH_TO_MS
ret.accFaulted = False
@@ -1,18 +1,19 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
GM torque-space feed-forward for the IQ.Pilot lateral extension: a sigmoid+linear
lat-accel -> torque curve for the tuned platforms, else the linear default.
"""
import os
from math import exp
from iqdbc.car import structs
from iqdbc.car.common.basedir import BASEDIR
from iqdbc.car.gm.interface import CAR
from iqdbc.iqpilot.car.interfaces import LatControlInputs, NanoFFModel, TorqueFromLateralAccelCallbackTypeTorqueSpace
from iqdbc.iqpilot.car.interfaces import LatControlInputs, TorqueFromLateralAccelCallbackTypeTorqueSpace
NON_LINEAR_TORQUE_PARAMS = {
_NON_LINEAR_TORQUE_PARAMS = {
CAR.CHEVROLET_BOLT_EUV: [2.6531724862969748, 1.0, 0.1919764879840985, 0.009054123646805178],
CAR.GMC_ACADIA: [4.78003305, 1.0, 0.3122, 0.05591772],
CAR.CHEVROLET_SILVERADO: [3.29974374, 1.0, 0.25571356, 0.0465122]
CAR.CHEVROLET_SILVERADO: [3.29974374, 1.0, 0.25571356, 0.0465122],
}
@@ -20,39 +21,23 @@ class CarInterfaceExt:
def __init__(self, CP: structs.CarParams, CI_Base):
self.CP = CP
self.CI_Base = CI_Base
self.neural_ff_model = None
def torque_from_lateral_accel_siglin(self, latcontrol_inputs: LatControlInputs, torque_params: structs.CarParams.LateralTorqueTuning,
@staticmethod
def _centered_sigmoid(val: float) -> float:
# sigmoid shifted to pass through the origin; branch keeps exp() from overflowing
if val >= 0:
return 1.0 / (1.0 + exp(-val)) - 0.5
z = exp(val)
return z / (1.0 + z) - 0.5
def torque_from_lateral_accel_siglin(self, latcontrol_inputs: LatControlInputs,
torque_params: structs.CarParams.LateralTorqueTuning,
gravity_adjusted: bool) -> float:
def sig(val):
# https://timvieira.github.io/blog/post/2014/02/11/exp-normalize-trick
if val >= 0:
return 1 / (1 + exp(-val)) - 0.5
else:
z = exp(val)
return z / (1 + z) - 0.5
# The "lat_accel vs torque" relationship is assumed to be the sum of "sigmoid + linear" curves
# An important thing to consider is that the slope at 0 should be > 0 (ideally >1)
# This has big effect on the stability about 0 (noise when going straight)
# ToDo: To generalize to other GMs, explore tanh function as the nonlinear
non_linear_torque_params = NON_LINEAR_TORQUE_PARAMS.get(self.CP.carFingerprint)
assert non_linear_torque_params, "The params are not defined"
a, b, c, _ = non_linear_torque_params
steer_torque = (sig(latcontrol_inputs.lateral_acceleration * a) * b) + (latcontrol_inputs.lateral_acceleration * c)
return float(steer_torque)
def torque_from_lateral_accel_neural(self, latcontrol_inputs: LatControlInputs, orque_params: structs.CarParams.LateralTorqueTuning,
gravity_adjusted: bool) -> float:
inputs = list(latcontrol_inputs)
if gravity_adjusted:
inputs[0] += inputs[1]
return float(self.neural_ff_model.predict(inputs))
a, b, c, _ = _NON_LINEAR_TORQUE_PARAMS[self.CP.carFingerprint]
lat_accel = latcontrol_inputs.lateral_acceleration
return float(self._centered_sigmoid(lat_accel * a) * b + lat_accel * c)
def torque_from_lateral_accel_in_torque_space(self) -> TorqueFromLateralAccelCallbackTypeTorqueSpace:
if self.CP.carFingerprint == CAR.CHEVROLET_BOLT_EUV:
return self.torque_from_lateral_accel_neural
elif self.CP.carFingerprint in NON_LINEAR_TORQUE_PARAMS:
if self.CP.carFingerprint in _NON_LINEAR_TORQUE_PARAMS:
return self.torque_from_lateral_accel_siglin
else:
return self.CI_Base.torque_from_lateral_accel_linear_in_torque_space
return self.CI_Base.torque_from_lateral_accel_linear_in_torque_space
@@ -1,7 +1,8 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
IQ.Pilot GM extension flags for the non-adaptive-cruise (Non-ACC) camera-harness port.
"""
from enum import IntFlag
@@ -11,5 +12,3 @@ class GMFlagsIQ(IntFlag):
class GMSafetyFlagsIQ:
NON_ACC = 1
+10 -9
View File
@@ -96,16 +96,17 @@ def _initialize_coop_steering(CP: structs.CarParams, CP_IQ: structs.IQCarParams,
def _initialize_stop_and_go(CP: structs.CarParams, CP_IQ: structs.IQCarParams, params_dict: dict[str, str]) -> None:
if CP.brand == 'subaru' and not CP.flags & (SubaruFlags.GLOBAL_GEN2 | SubaruFlags.HYBRID):
stop_and_go = int(params_dict.get("SubaruStopAndGo", 0)) == 1
stop_and_go_manual_parking_brake = int(params_dict.get("SubaruStopAndGoManualParkingBrake", 0)) == 1
# Subaru stop-and-go; unsupported on gen2-global and hybrid platforms.
if CP.brand != 'subaru' or CP.flags & (SubaruFlags.GLOBAL_GEN2 | SubaruFlags.HYBRID):
return
if stop_and_go:
CP_IQ.flags |= SubaruFlagsIQ.STOP_AND_GO.value
if stop_and_go_manual_parking_brake:
CP_IQ.flags |= SubaruFlagsIQ.STOP_AND_GO_MANUAL_PARKING_BRAKE.value
if stop_and_go or stop_and_go_manual_parking_brake:
CP_IQ.safetyParam |= SubaruSafetyFlagsIQ.STOP_AND_GO
if int(params_dict.get("SubaruStopAndGo", 0)) == 1:
CP_IQ.flags |= SubaruFlagsIQ.STOP_AND_GO.value
if int(params_dict.get("SubaruStopAndGoManualParkingBrake", 0)) == 1:
CP_IQ.flags |= SubaruFlagsIQ.STOP_AND_GO_MANUAL_PARKING_BRAKE.value
if CP_IQ.flags & (SubaruFlagsIQ.STOP_AND_GO | SubaruFlagsIQ.STOP_AND_GO_MANUAL_PARKING_BRAKE):
CP_IQ.iqSafetyFlags |= SubaruSafetyFlagsIQ.STOP_AND_GO
def _initialize_toyota(CP: structs.CarParams, CP_IQ: structs.IQCarParams, params_dict: dict[str, str]) -> None:
@@ -1,3 +0,0 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
@@ -1,3 +0,0 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
@@ -1,7 +1,8 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
Nissan cruise-button reader: emits edge ButtonEvents for the RES/SET buttons.
"""
from enum import StrEnum
from iqdbc.car import Bus, structs
@@ -13,20 +14,18 @@ class CarStateExt:
def __init__(self, CP, CP_IQ):
self.CP = CP
self.CP_IQ = CP_IQ
self.button_events = []
self.button_events: list = []
self.button_states = {button.event_type: False for button in BUTTONS}
def update(self, ret: structs.CarState, ret_iq: structs.IQCarState, can_parsers: dict[StrEnum, CANParser]):
def update(self, ret: structs.CarState, ret_iq: structs.IQCarState, can_parsers: dict[StrEnum, CANParser]) -> None:
cp = can_parsers[Bus.pt]
button_events = []
events = []
for button in BUTTONS:
state = (cp.vl[button.can_addr][button.can_msg] in button.values)
if self.button_states[button.event_type] != state:
pressed = cp.vl[button.can_addr][button.can_msg] in button.values
if pressed != self.button_states[button.event_type]:
event = structs.CarState.ButtonEvent.new_message()
event.type = button.event_type
event.pressed = state
button_events.append(event)
self.button_states[button.event_type] = state
self.button_events = button_events
event.pressed = pressed
events.append(event)
self.button_states[button.event_type] = pressed
self.button_events = events
@@ -1,8 +1,10 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
IQ.Pilot Nissan extension: safety flag + cruise-button table.
"""
from collections import namedtuple
from iqdbc.car import structs
@@ -11,12 +13,9 @@ class NissanSafetyFlagsIQ:
LEAF = 1
ButtonType = structs.CarState.ButtonEvent.Type
Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values'])
BUTTONS = [
Button(ButtonType.accelCruise, "CRUISE_THROTTLE", "RES_BUTTON", [1]),
Button(ButtonType.decelCruise, "CRUISE_THROTTLE", "SET_BUTTON", [1]),
@@ -1,3 +0,0 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
+14 -17
View File
@@ -1,33 +1,30 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
Always-on-Lateral output adapter for Rivian: derives the per-frame lateral-active
and lane-keep icon state the LKAS command needs from the shared AOL state.
"""
from collections import namedtuple
from iqdbc.car import structs
from iqdbc.car.interfaces import CarStateBase
MAX_STEERING_ANGLE = 90.0
# Rivian EPAS rejects large-angle torque, so lateral is dropped past this bound.
_MAX_STEERING_ANGLE = 90.0
AolDataIQ = namedtuple("AolDataIQ",
["lka_icon_states", "lat_active"])
AolDataIQ = namedtuple("AolDataIQ", ["lka_icon_states", "lat_active"])
class AolCarController:
def __init__(self):
self.aol = AolDataIQ(False, False)
self.lka_icon_states = False
self.lat_active = False
def aol_status_update(self, CC: structs.CarControl, CC_IQ: structs.IQCarControl, CS: CarStateBase) -> AolDataIQ:
if CC_IQ.aol.available:
self.lka_icon_states = self.lat_active
self.lat_active = CC.latActive and abs(CS.out.steeringAngleDeg) < MAX_STEERING_ANGLE
else:
self.lka_icon_states = CC.enabled
self.lat_active = CC.latActive
return AolDataIQ(self.lka_icon_states, self.lat_active)
def update(self, CC: structs.CarControl, CC_IQ: structs.IQCarControl, CS: CarStateBase) -> None:
self.aol = self.aol_status_update(CC, CC_IQ, CS)
prev_active = self.aol.lat_active
if CC_IQ.aol.available:
lat_active = CC.latActive and abs(CS.out.steeringAngleDeg) < _MAX_STEERING_ANGLE
lka_icon = prev_active
else:
lat_active = CC.latActive
lka_icon = CC.enabled
self.aol = AolDataIQ(lka_icon, lat_active)
@@ -1,5 +1,9 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
Rivian longitudinal-harness-upgrade carState reader: with the upgrade harness the
right steering-wheel controls and the drive stalk drive the openpilot set speed,
and the harness exposes blind-spot indicators. Only active behind the upgrade flag.
"""
import math
from enum import StrEnum
@@ -12,8 +16,10 @@ from iqdbc.iqpilot.car.rivian.values import RivianFlagsIQ
ButtonType = structs.CarState.ButtonEvent.Type
MAX_SET_SPEED = 85 * CV.MPH_TO_MS
MIN_SET_SPEED = 20 * CV.MPH_TO_MS
_SET_SPEED_MAX = 85 * CV.MPH_TO_MS
_SET_SPEED_MIN = 20 * CV.MPH_TO_MS
_LONG_PRESS_FRAMES = 66
_STALK_HOLD_FRAMES = 50
class CarStateExt:
@@ -29,57 +35,57 @@ class CarStateExt:
self.decrease_counter = 0
self.stalk_down_counter = 0
def _apply_set_speed_buttons(self, ret: structs.CarState, cp_park, cp_adas) -> None:
was_increasing = self.increase_button
was_decreasing = self.decrease_button
self.increase_button = cp_park.vl["WheelButtons"]["RightButton_RightClick"] == 2
self.decrease_button = cp_park.vl["WheelButtons"]["RightButton_LeftClick"] == 2
self.increase_counter = self.increase_counter + 1 if self.increase_button else 0
self.decrease_counter = self.decrease_counter + 1 if self.decrease_button else 0
metric = cp_adas.vl["Cluster"]["Cluster_Unit"] == 0
conversion = CV.KPH_TO_MS if metric else CV.MPH_TO_MS
step = 10.0 if metric else 5.0
shown = self.set_speed * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH)
# A held button steps to the next round multiple; a tap nudges by one unit.
if self.increase_button:
if self.increase_counter % _LONG_PRESS_FRAMES == 0:
self.set_speed = math.ceil((shown + 1) / step) * step * conversion
elif not was_increasing:
self.set_speed += conversion
if self.decrease_button:
if self.decrease_counter % _LONG_PRESS_FRAMES == 0:
self.set_speed = math.floor((shown - 1) / step) * step * conversion
elif not was_decreasing:
self.set_speed -= conversion
def update_longitudinal_upgrade(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
cp_park = can_parsers[Bus.alt]
cp_adas = can_parsers[Bus.adas]
cp = can_parsers[Bus.pt]
prev_increase_button = self.increase_button
prev_decrease_button = self.decrease_button
if self.CP.openpilotLongitudinalControl:
# distance scroll wheel
right_scroll = cp_park.vl["WheelButtons"]["RightButton_Scroll"]
if right_scroll != 255:
if self.distance_button != right_scroll:
ret.buttonEvents = [structs.CarState.ButtonEvent(pressed=False, type=ButtonType.gapAdjustCruise)]
self.distance_button = right_scroll
# button logic for set-speed
self.increase_button = cp_park.vl["WheelButtons"]["RightButton_RightClick"] == 2
self.decrease_button = cp_park.vl["WheelButtons"]["RightButton_LeftClick"] == 2
self.increase_counter = self.increase_counter + 1 if self.increase_button else 0
self.decrease_counter = self.decrease_counter + 1 if self.decrease_button else 0
metric = cp_adas.vl["Cluster"]["Cluster_Unit"] == 0
conversion = CV.KPH_TO_MS if metric else CV.MPH_TO_MS
long_press_step = 10.0 if metric else 5.0
set_speed_converted = self.set_speed * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH)
if self.increase_button:
if self.increase_counter % 66 == 0:
self.set_speed = (int(math.ceil((set_speed_converted + 1) / long_press_step)) * long_press_step) * conversion
elif not prev_increase_button:
self.set_speed += conversion
if self.decrease_button:
if self.decrease_counter % 66 == 0:
self.set_speed = (int(math.floor((set_speed_converted - 1) / long_press_step)) * long_press_step) * conversion
elif not prev_decrease_button:
self.set_speed -= conversion
self._apply_set_speed_buttons(ret, cp_park, cp_adas)
if not ret.cruiseState.enabled:
self.set_speed = ret.vEgoCluster
# VDM_UserAdasRequest: 0=IDLE, 1=UP_1, 2=UP_2, 3=DOWN_1, 4=DOWN_2
# Drive stalk held down (VDM_UserAdasRequest 3/4) for ~0.5s snaps set speed
# up to the current speed, matching stock Rivian ACC (it never lowers it).
stalk_down = int(cp.vl["VDM_AdasSts"]["VDM_UserAdasRequest"]) in (3, 4)
self.stalk_down_counter = self.stalk_down_counter + 1 if stalk_down else 0
if self.stalk_down_counter == 50:
# Mimic Rivian ACC: holding stalk 0.5s sets speed to current speed (never decreases)
if self.stalk_down_counter == _STALK_HOLD_FRAMES:
self.set_speed = max(self.set_speed, ret.vEgoCluster)
self.set_speed = max(MIN_SET_SPEED, min(self.set_speed, MAX_SET_SPEED))
self.set_speed = max(_SET_SPEED_MIN, min(self.set_speed, _SET_SPEED_MAX))
ret.cruiseState.speed = self.set_speed
if self.CP.enableBsm:
@@ -92,9 +98,7 @@ class CarStateExt:
@staticmethod
def get_parser(CP, CP_IQ) -> dict[StrEnum, CANParser]:
messages = {}
messages: dict[StrEnum, CANParser] = {}
if CP_IQ.flags & RivianFlagsIQ.LONGITUDINAL_HARNESS_UPGRADE:
messages[Bus.alt] = CANParser(DBC[CP.carFingerprint][Bus.alt], [], 5)
return messages
@@ -1,10 +1,10 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
IQ.Pilot Rivian extension flags.
"""
from enum import IntFlag
class RivianFlagsIQ(IntFlag):
LONGITUDINAL_HARNESS_UPGRADE = 1
@@ -1,3 +0,0 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
+20 -29
View File
@@ -1,45 +1,36 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
Always-on-Lateral input adapter for Subaru: turns the dashboard LKAS button into
a carState lkas ButtonEvent so the shared AOL state machine can toggle lateral.
"""
from enum import StrEnum
from iqdbc.car import Bus, structs
from iqdbc.car import Bus, structs
from iqdbc.car.subaru.values import SubaruFlags
from iqdbc.iqpilot.aol_base import AolCarStateBase
from iqdbc.can.parser import CANParser
ButtonType = structs.CarState.ButtonEvent.Type
_LKAS = structs.CarState.ButtonEvent.Type.lkas
# ES_LKAS_State/LKAS_Dash_State: 0 = neutral, 1 = LKAS shown on, 2 = LKAS shown off
_DASH_ON = 1
_DASH_OFF = 2
class AolCarState(AolCarStateBase):
def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
super().__init__(CP, CP_IQ)
@staticmethod
def create_lkas_button_events(cur_btn: int, prev_btn: int,
buttons_dict: dict[int, structs.CarState.ButtonEvent.Type]) -> list[structs.CarState.ButtonEvent]:
events: list[structs.CarState.ButtonEvent] = []
if cur_btn == prev_btn:
return events
state_changes = [
{"pressed": prev_btn != cur_btn and cur_btn != 2 and not (prev_btn == 2 and cur_btn == 1)},
{"pressed": prev_btn != cur_btn and cur_btn == 2 and cur_btn != 1},
]
for change in state_changes:
if change["pressed"]:
events.append(structs.CarState.ButtonEvent(pressed=change["pressed"],
type=buttons_dict.get(cur_btn, ButtonType.unknown)))
return events
def update_aol(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
cp_cam = can_parsers[Bus.cam]
if self.CP.flags & SubaruFlags.PREGLOBAL:
return
self.prev_lkas_button = self.lkas_button
if not self.CP.flags & SubaruFlags.PREGLOBAL:
self.lkas_button = cp_cam.vl["ES_LKAS_State"]["LKAS_Dash_State"]
self.lkas_button = can_parsers[Bus.cam].vl["ES_LKAS_State"]["LKAS_Dash_State"]
ret.buttonEvents = self.create_lkas_button_events(self.lkas_button, self.prev_lkas_button, {1: ButtonType.lkas})
if self._is_toggle_edge():
ret.buttonEvents = [*ret.buttonEvents, structs.CarState.ButtonEvent(type=_LKAS, pressed=True)]
def _is_toggle_edge(self) -> bool:
# every dash-state change is a deliberate press except the off->on rebound (2 -> 1)
if self.lkas_button == self.prev_lkas_button:
return False
return not (self.prev_lkas_button == _DASH_OFF and self.lkas_button == _DASH_ON)
@@ -1,7 +1,11 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
IQ.Pilot Subaru stop-and-go: nudges the ACC out of a standstill it would
otherwise hold. Two variants gated by user flags — an electronic-parking-brake
resume pulse (distance/lead triggered) and a manual-parking-brake hold-timer
resume. Both work by spoofing the camera-bus throttle/brake frames.
"""
import copy
from enum import StrEnum
@@ -14,93 +18,64 @@ from iqdbc.iqpilot.car.subaru import subarucan_ext
from iqdbc.iqpilot.car.subaru.values_ext import SubaruFlagsIQ
from iqdbc.can.parser import CANParser
_SNG_ACC_MIN_DIST = 3
_SNG_ACC_MAX_DIST = 4.5
# EPB resume fires only while the lead is pulling away within this gap band (m).
_RESUME_GAP_MIN = 3.0
_RESUME_GAP_MAX = 4.5
_EPB_PULSE_FRAMES = 15
class SnGCarController:
def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
self.CP = CP
self.CP_IQ = CP_IQ
self.enabled = CP_IQ.flags & (SubaruFlagsIQ.STOP_AND_GO | SubaruFlagsIQ.STOP_AND_GO_MANUAL_PARKING_BRAKE)
self.manual_parking_brake = CP_IQ.flags & SubaruFlagsIQ.STOP_AND_GO_MANUAL_PARKING_BRAKE
self.enabled = bool(CP_IQ.flags & (SubaruFlagsIQ.STOP_AND_GO | SubaruFlagsIQ.STOP_AND_GO_MANUAL_PARKING_BRAKE))
self.manual_parking_brake = bool(CP_IQ.flags & SubaruFlagsIQ.STOP_AND_GO_MANUAL_PARKING_BRAKE)
self.last_standstill_frame = 0
self.epb_resume_frames_remaining = -1
self.prev_close_distance = 0.0
self.standstill_since = 0
self._pulse_left = 0
self.prev_gap = 0.0
def update_epb_resume_sequence(self, should_resume: bool) -> bool:
def _epb_pulse(self, trigger: bool) -> bool:
# A trigger arms a fixed-length resume pulse; the pulse then plays out frame by frame.
if self.manual_parking_brake:
return False
if trigger:
self._pulse_left = _EPB_PULSE_FRAMES
if self._pulse_left > 0:
self._pulse_left -= 1
return True
return False
if should_resume:
self.epb_resume_frames_remaining = 15
send_resume = self.epb_resume_frames_remaining > 0
if self.epb_resume_frames_remaining > 0:
self.epb_resume_frames_remaining -= 1
return send_resume
def update_stop_and_go(self, CC: structs.CarControl, CS: CarStateBase, frame: int) -> bool:
"""
Manages stop-and-go functionality for adaptive cruise control (ACC).
Args:
CC: Car control data
CS: Car state data
frame: Current frame number
Returns:
bool: True if resume command should be sent, False otherwise
"""
def _want_resume(self, CC: structs.CarControl, CS: CarStateBase, frame: int) -> bool:
if not CC.enabled or not CC.hudControl.leadVisible:
return False
close_distance = CS.es_distance_msg["Close_Distance"]
in_standstill = CS.out.standstill
gap = CS.es_distance_msg["Close_Distance"]
standing = CS.out.standstill
if not standing:
self.standstill_since = frame
if not in_standstill:
self.last_standstill_frame = frame
hold_arm, hold_reset = (0.75, 0.8) if self.CP.flags & SubaruFlags.PREGLOBAL else (0.5, 0.55)
held_for = (frame - self.standstill_since) * DT_CTRL
held_long_enough = held_for > hold_arm
if held_for >= hold_reset:
self.standstill_since = frame
# Check if we've been in standstill long enough
mpb_standstill_timers = (0.75, 0.8) if self.CP.flags & SubaruFlags.PREGLOBAL else (0.5, 0.55)
standstill_duration = (frame - self.last_standstill_frame) * DT_CTRL
in_standstill_hold = standstill_duration > mpb_standstill_timers[0]
if (frame - self.last_standstill_frame) * DT_CTRL >= mpb_standstill_timers[1]:
self.last_standstill_frame = frame
# Car state distance-based conditions (EPB only)
in_resume_distance = _SNG_ACC_MIN_DIST < close_distance < _SNG_ACC_MAX_DIST
distance_increasing = close_distance > self.prev_close_distance
distance_resume_allowed = in_resume_distance and distance_increasing
lead_pulling_away = _RESUME_GAP_MIN < gap < _RESUME_GAP_MAX and gap > self.prev_gap
self.prev_gap = gap
if self.manual_parking_brake:
# Manual parking brake: Direct resume when the standstill hold threshold is reached to prevent ACC fault
send_resume = in_standstill_hold
else:
# EPB: Resume sequence with trigger on distance with lead car increasing
should_resume = CS.out.standstill and distance_resume_allowed
send_resume = self.update_epb_resume_sequence(should_resume)
self.prev_close_distance = close_distance
return send_resume
return held_long_enough
return self._epb_pulse(standing and lead_pulling_away)
def create_stop_and_go(self, packer, CC: structs.CarControl, CS: CarStateBase, frame: int) -> list[CanData]:
can_sends = []
if not self.enabled:
return can_sends
send_resume = self.update_stop_and_go(CC, CS, frame)
can_sends.append(subarucan_ext.create_throttle(packer, self.CP, CS.throttle_msg, send_resume and not self.manual_parking_brake))
return []
resume = self._want_resume(CC, CS, frame)
can_sends = [subarucan_ext.create_throttle(packer, self.CP, CS.throttle_msg, resume and not self.manual_parking_brake)]
if frame % 2 == 0:
can_sends.append(subarucan_ext.create_brake_pedal(packer, self.CP, CS.brake_pedal_msg, send_resume and self.manual_parking_brake))
can_sends.append(subarucan_ext.create_brake_pedal(packer, self.CP, CS.brake_pedal_msg, resume and self.manual_parking_brake))
return can_sends
@@ -108,14 +83,11 @@ class SnGCarState:
def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
self.CP = CP
self.CP_IQ = CP_IQ
self.brake_pedal_msg: dict[str, float] = {}
self.throttle_msg: dict[str, float] = {}
def update(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
cp = can_parsers[Bus.pt]
self.brake_pedal_msg = copy.copy(cp.vl["Brake_Pedal"])
if not self.CP.flags & SubaruFlags.HYBRID:
self.throttle_msg = copy.copy(cp.vl["Throttle"])
@@ -1,68 +1,41 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
Camera-bus message spoofers for Subaru stop-and-go: re-emit the stock Throttle
and Brake_Pedal frames, nudging a single field to trigger an ACC resume from a
standstill. Field sets mirror the DBC message layout.
"""
from iqdbc.car.subaru.values import CanBus, SubaruFlags
_THROTTLE_FIELDS_PREGLOBAL = ("Throttle_Pedal", "Signal1", "Not_Full_Throttle", "Signal2", "Engine_RPM",
"Off_Throttle", "Signal3", "Throttle_Cruise", "Throttle_Combo", "Throttle_Body",
"Off_Throttle_2", "Signal4")
_THROTTLE_FIELDS_GLOBAL = ("CHECKSUM", "Signal1", "Engine_RPM", "Neutral", "Throttle_Pedal", "Throttle_Cruise",
"Throttle_Combo", "Signal3", "Off_Accel")
_BRAKE_FIELDS_PREGLOBAL = ("Speed", "Brake_Pedal", "Signal1")
_BRAKE_FIELDS_GLOBAL = ("CHECKSUM", "Signal1", "Speed", "Signal2", "Brake_Lights", "Signal3", "Brake_Pedal", "Signal4")
def create_counter(msg):
def _next_counter(msg):
return (msg["COUNTER"] + 1) % 0x10
def create_throttle(packer, CP, throttle_msg, send_resume):
if CP.flags & SubaruFlags.PREGLOBAL:
values = {s: throttle_msg[s] for s in [
"Throttle_Pedal",
"Signal1",
"Not_Full_Throttle",
"Signal2",
"Engine_RPM",
"Off_Throttle",
"Signal3",
"Throttle_Cruise",
"Throttle_Combo",
"Throttle_Body",
"Off_Throttle_2",
"Signal4",
]}
else:
values = {s: throttle_msg[s] for s in [
"CHECKSUM",
"Signal1",
"Engine_RPM",
"Neutral",
"Throttle_Pedal",
"Throttle_Cruise",
"Throttle_Combo",
"Signal3",
"Off_Accel",
]}
values["COUNTER"] = create_counter(throttle_msg)
preglobal = bool(CP.flags & SubaruFlags.PREGLOBAL)
fields = _THROTTLE_FIELDS_PREGLOBAL if preglobal else _THROTTLE_FIELDS_GLOBAL
values = {name: throttle_msg[name] for name in fields}
values["COUNTER"] = _next_counter(throttle_msg)
if send_resume:
values["Throttle_Pedal"] = 5
return packer.make_can_msg("Throttle", CanBus.camera, values)
def create_brake_pedal(packer, CP, brake_pedal_msg, send_resume):
if CP.flags & SubaruFlags.PREGLOBAL:
values = {s: brake_pedal_msg[s] for s in [
"Speed",
"Brake_Pedal",
"Signal1",
]}
else:
values = {s: brake_pedal_msg[s] for s in [
"CHECKSUM",
"Signal1",
"Speed",
"Signal2",
"Brake_Lights",
"Signal3",
"Brake_Pedal",
"Signal4",
]}
values["COUNTER"] = create_counter(brake_pedal_msg)
preglobal = bool(CP.flags & SubaruFlags.PREGLOBAL)
fields = _BRAKE_FIELDS_PREGLOBAL if preglobal else _BRAKE_FIELDS_GLOBAL
values = {name: brake_pedal_msg[name] for name in fields}
if not preglobal:
values["COUNTER"] = _next_counter(brake_pedal_msg)
if send_resume:
values["Speed"] = 1 if CP.flags & SubaruFlags.PREGLOBAL else 3
values["Speed"] = 1 if preglobal else 3
return packer.make_can_msg("Brake_Pedal", CanBus.camera, values)
@@ -1,14 +1,16 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
IQ.Pilot Subaru extension flags. Selected in setup_interfaces() from the user's
stop-and-go params and consumed by the stop-and-go controller and panda safety.
"""
from enum import IntFlag
class SubaruSafetyFlagsIQ:
STOP_AND_GO = 1
class SubaruFlagsIQ(IntFlag):
STOP_AND_GO = 1
STOP_AND_GO_MANUAL_PARKING_BRAKE = 2
class SubaruSafetyFlagsIQ:
STOP_AND_GO = 1
+3 -2
View File
@@ -7,7 +7,8 @@ from iqdbc.safety.tests.libsafety import libsafety_py
import iqdbc.safety.tests.common as common
from iqdbc.safety.tests.common import CANPackerSafety
from iqdbc.iqpilot.car.gm.values_ext import GMSafetyFlagsIQ
# GM_PARAM_IQ_NON_ACC in safety/modes/gm.h (IQ safety framework flag)
GM_PARAM_IQ_NON_ACC = 1
class Buttons:
@@ -236,7 +237,7 @@ class TestGmCameraNonACCSafety(TestGmCameraSafety):
self.packer = CANPackerSafety("gm_global_a_powertrain_generated")
self.packer_chassis = CANPackerSafety("gm_global_a_chassis")
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_iq(GMSafetyFlagsIQ.NON_ACC)
self.safety.set_current_safety_param_iq(GM_PARAM_IQ_NON_ACC)
self.safety.set_safety_hooks(CarParams.SafetyModel.gm, GMSafetyFlags.HW_CAM | self.EXTRA_SAFETY_PARAM)
self.safety.init_tests()
+4 -2
View File
@@ -2,8 +2,10 @@
import unittest
from iqdbc.car.nissan.values import NissanSafetyFlags
from iqdbc.iqpilot.car.nissan.values import NissanSafetyFlagsIQ
from iqdbc.car.structs import CarParams
# NISSAN_PARAM_IQ_LEAF in safety/modes/nissan.h (IQ safety framework flag)
NISSAN_PARAM_IQ_LEAF = 1
from iqdbc.safety.tests.libsafety import libsafety_py
import iqdbc.safety.tests.common as common
from iqdbc.safety.tests.common import CANPackerSafety
@@ -105,7 +107,7 @@ class TestNissanLeafSafety(TestNissanSafety):
def setUp(self):
self.packer = CANPackerSafety("nissan_leaf_2018_generated")
self.safety = libsafety_py.libsafety
self.safety.set_current_safety_param_iq(NissanSafetyFlagsIQ.LEAF)
self.safety.set_current_safety_param_iq(NISSAN_PARAM_IQ_LEAF)
self.safety.set_safety_hooks(CarParams.SafetyModel.nissan, 0)
self.safety.init_tests()
+10 -9
View File
@@ -872,10 +872,10 @@ class SteeringLayout(Widget):
lambda v: f"{int(round(v * (CV.MPH_TO_KPH if ui_state.is_metric else 1)))}"
f" {'km/h' if ui_state.is_metric else 'mph'}"
)
self._lagd_toggle = toggle_item(tr("Live Learning Steer Delay"), "", param="IQLiveSteerDelay")
self._steer_delay_toggle = toggle_item(tr("Self-Tuning Steer Delay"), "", param="IQLiveSteerDelay")
self._delay_control = option_item(
tr("Adjust Software Delay"), "IQSoftwareSteerDelay", 5, 50,
tr("Adjust the fixed software delay added to steer actuator delay when Live Learning Steer Delay is turned off. The default software delay value is 0.2 s."),
tr("Manual Delay Offset"), "IQSoftwareSteerDelay", 5, 50,
tr("How much lead time to add on top of the car's own steering rack delay while self-tuning is off. Default is 0.2 s."),
1, None, True, "", style.BUTTON_ACTION_WIDTH, None, True, lambda v: f"{float(v):.2f}s"
)
@@ -890,7 +890,7 @@ class SteeringLayout(Widget):
self._lane_turn_desire_toggle,
self._lane_turn_value_control,
IQLineSeparator(40),
self._lagd_toggle,
self._steer_delay_toggle,
self._delay_control,
]
return items
@@ -922,19 +922,20 @@ class SteeringLayout(Widget):
live_delay = ui_state.params.get_bool("IQLiveSteerDelay")
self._lane_turn_desire_toggle.action_item.set_state(turn_desire)
self._lane_turn_value_control.set_visible(turn_desire)
self._lagd_toggle.action_item.set_state(live_delay)
self._steer_delay_toggle.action_item.set_state(live_delay)
self._delay_control.set_visible(not live_delay)
new_step = int(round(100 / CV.MPH_TO_KPH)) if ui_state.is_metric else 100
if self._lane_turn_value_control.action_item.value_change_step != new_step:
self._lane_turn_value_control.action_item.value_change_step = new_step
lagd_desc = tr("Enable this for the car to learn and adapt its steering response time. Disable to use a fixed steering response time.")
delay_desc = tr("Let IQ.Pilot measure how long your steering takes to respond and keep that figure up to date. "
"Switch it off to pin the timing yourself.")
if live_delay:
lagd_desc += f"<br>{tr('Live Steer Delay:')} {ui_state.sm['liveDelay'].lateralDelay:.3f} s"
delay_desc += f"<br>{tr('Measured:')} {ui_state.sm['liveDelay'].lateralDelay:.3f} s"
elif ui_state.CP:
sw = float(ui_state.params.get("IQSoftwareSteerDelay", "0.2"))
cp = ui_state.CP.steerActuatorDelay
lagd_desc += f"<br>{tr('Actuator Delay:')} {cp:.2f} s + {tr('Software Delay:')} {sw:.2f} s = {tr('Total Delay:')} {cp + sw:.2f} s"
self._lagd_toggle.set_description(lagd_desc)
delay_desc += f"<br>{tr('Rack:')} {cp:.2f} s + {tr('Offset:')} {sw:.2f} s = {tr('Total:')} {cp + sw:.2f} s"
self._steer_delay_toggle.set_description(delay_desc)
def _render(self, rect):
if self._current_panel == PanelType.LANE_CHANGE:
+12 -12
View File
@@ -121,16 +121,16 @@ class ModelsLayoutMici(NavScroller):
self._clear.set_click_callback(self._confirm_clear_cache)
self._clear.set_enabled(lambda: ui_state.is_offroad())
self._lagd = BigParamControl("live learning steer delay", "IQLiveSteerDelay")
self._sw_delay = MappedParamToggle("software delay", "IQSoftwareSteerDelay", _DELAY_OPTIONS, _DELAY_VALUES)
self._sw_delay.set_visible(lambda: not self._lagd._checked)
self._steer_delay = BigParamControl("self-tuning steer delay", "IQLiveSteerDelay")
self._sw_delay = MappedParamToggle("manual delay offset", "IQSoftwareSteerDelay", _DELAY_OPTIONS, _DELAY_VALUES)
self._sw_delay.set_visible(lambda: not self._steer_delay._checked)
self._lane_turn = BigParamControl("use lane turn desires", "IQLaneTurnDesire")
self._lane_speed = MappedParamToggle("lane turn speed", "IQLaneTurnValue", _LANE_TURN_OPTIONS, _LANE_TURN_VALUES)
self._lane_speed.set_visible(lambda: self._lane_turn._checked)
self._main_items = [self._current, self._cancel, self._supercombo, self._vision, self._policy, self._redownload, self._refresh, self._clear,
self._lagd, self._sw_delay, self._lane_turn, self._lane_speed]
self._steer_delay, self._sw_delay, self._lane_turn, self._lane_speed]
self._scroller.add_widgets(self._main_items)
@property
@@ -368,7 +368,7 @@ class ModelsLayoutMici(NavScroller):
self._last_cache_t = now
self._clear.set_value(f"{self._calculate_cache_size():.1f} MB")
self._update_lagd_subtext()
self._update_steer_delay_subtext()
def _progress_target_bundle(self):
try:
@@ -445,21 +445,21 @@ class ModelsLayoutMici(NavScroller):
return f"failed: {_display_model_name(bundle)}"
return self._active_model_name()
def _update_lagd_subtext(self):
if self._lagd._checked:
def _update_steer_delay_subtext(self):
if self._steer_delay._checked:
try:
self._lagd.set_value(f"live {ui_state.sm['liveDelay'].lateralDelay:.3f} s")
self._steer_delay.set_value(f"measured {ui_state.sm['liveDelay'].lateralDelay:.3f} s")
except Exception:
self._lagd.set_value("")
self._steer_delay.set_value("")
return
try:
sw = float(ui_state.params.get("IQSoftwareSteerDelay", return_default=True))
except (TypeError, ValueError):
sw = 0.2
if ui_state.CP is not None:
self._lagd.set_value(f"total {ui_state.CP.steerActuatorDelay + sw:.2f} s")
self._steer_delay.set_value(f"total {ui_state.CP.steerActuatorDelay + sw:.2f} s")
else:
self._lagd.set_value(f"+{sw:.2f} s software")
self._steer_delay.set_value(f"+{sw:.2f} s offset")
def _active_model_name(self) -> str:
if not self._has_active_bundle_param():
@@ -495,5 +495,5 @@ class ModelsLayoutMici(NavScroller):
def show_event(self):
super().show_event()
for w in (self._lagd, self._sw_delay, self._lane_turn, self._lane_speed):
for w in (self._steer_delay, self._sw_delay, self._lane_turn, self._lane_speed):
w.refresh()
+6 -3
View File
@@ -43,7 +43,10 @@ struct EncoderSettings {
}
static EncoderSettings QcamEncoderSettings() {
int _qcam_bitrate = getenv("QCAM_BITRATE") ? atoi(getenv("QCAM_BITRATE")) : 3'200'000;
// Keep Konn3kt route uploads useful without turning each 60-second qcamera
// segment into a 26 MB file. This is still a substantial improvement over
// stock qcam, while CBR keeps storage and upload usage predictable.
int _qcam_bitrate = getenv("QCAM_BITRATE") ? atoi(getenv("QCAM_BITRATE")) : 2'400'000;
return EncoderSettings{.encode_type = cereal::EncodeIndex::Type::QCAMERA_H264, .bitrate = _qcam_bitrate, .gop_size = 15};
}
@@ -137,8 +140,8 @@ const EncoderInfo qcam_encoder_info = {
.filename = "qcamera.ts",
.cbr = true, // enforce the bitrate so upload size stays predictable (no VBR overshoot)
.get_settings = [](int){return EncoderSettings::QcamEncoderSettings();},
.frame_width = 1578, // 3x the stock 526x330, same road-cam aspect ratio
.frame_height = 990,
.frame_width = 1315, // 2.5x the stock 526x330, same road-cam aspect ratio
.frame_height = 825,
.include_audio = Params().getBool("RecordAudio"),
INIT_ENCODE_FUNCTIONS(QRoadEncode),
};
-55
View File
@@ -11,7 +11,6 @@ import threading
from openpilot.common.basedir import BASEDIR
from openpilot.common.params import Params
from openpilot.common.swaglog import cloudlog
def unblock_stdout() -> None:
# get a non-blocking stdout
@@ -103,57 +102,3 @@ def save_bootlog():
t = threading.Thread(target=fn, args=(tmp, ))
t.daemon = True
t.start()
# REVERT ME! ---------------------------------------------------------------
# One-shot migration carrying values across the sunny -> IQ param key renames.
# Old keys are no longer registered in params_keys.h, so their values are read
# straight off disk, copied to the new IQ key, and the stale file removed.
# Delete this block (and its manager_init() call) once fielded devices have
# booted past it at least once.
_RENAMED_PARAMS = {
"QuietMode": "IQAlertSilence",
"SpeedLimitMode": "IQSpeedAssistMode",
"SpeedLimitPolicy": "IQSpeedAssistPolicy",
"SpeedLimitOffsetType": "IQSpeedAssistOffsetType",
"SpeedLimitValueOffset": "IQSpeedAssistValueOffset",
"LaneTurnDesire": "IQLaneTurnDesire",
"LaneTurnValue": "IQLaneTurnValue",
"BlinkerPauseLateralControl": "IQBlinkerPauseLateral",
"BlinkerMinLateralControlSpeed": "IQBlinkerMinLateralSpeed",
"DevUIInfo": "IQDevUIInfo",
"OffroadMode": "IQAlwaysOffroad",
"AutoLaneChangeTimer": "IQLaneChangeTimer",
"AutoLaneChangeBsmDelay": "IQLaneChangeBsmDelay",
"LagdToggle": "IQLiveSteerDelay",
"LagdToggleDelay": "IQSoftwareSteerDelay",
"LagdValueCache": "IQSteerDelayCache",
}
def migrate_renamed_params(params: Params | None = None) -> None:
"""REVERT ME! carry stored values across the sunny->IQ key renames, then drop the old files.
Copies at the file level: on-disk param values are raw bytes, so this preserves the exact
stored representation and sidesteps put()'s typed-value check for BOOL/INT/FLOAT keys.
"""
p = params if params is not None else Params()
for old, new in _RENAMED_PARAMS.items():
try:
old_path = p.get_param_path(old)
if not os.path.isfile(old_path):
continue
new_path = p.get_param_path(new)
if not os.path.exists(new_path):
with open(old_path, "rb") as f:
value = f.read()
tmp = new_path + ".tmp"
with open(tmp, "wb") as f:
f.write(value)
f.flush()
os.fsync(f.fileno())
os.rename(tmp, new_path)
os.remove(old_path)
except Exception:
cloudlog.exception(f"param rename migration failed for {old} -> {new}")
# END REVERT ME! ------------------------------------------------------------
+1 -2
View File
@@ -17,7 +17,7 @@ from openpilot.common.params import Params, ParamKeyFlag
from openpilot.common.text_window import TextWindow
from openpilot.system.hardware import HARDWARE
from openpilot.system.loggerd.crash_recovery import recover_unclean_segments
from openpilot.system.manager.helpers import unblock_stdout, write_onroad_params, save_bootlog, heal_param_perms, migrate_renamed_params
from openpilot.system.manager.helpers import unblock_stdout, write_onroad_params, save_bootlog, heal_param_perms
from openpilot.system.manager.process import ensure_running
from openpilot.system.manager.process_config import managed_processes
from openpilot.iqpilot.konn3kt.registration import register, UNREGISTERED_DONGLE_ID
@@ -40,7 +40,6 @@ def manager_init() -> None:
build_metadata = get_build_metadata()
params = Params()
migrate_renamed_params(params) # REVERT ME! sunny->IQ param key migration (runs before defaults are filled)
params.clear_all(ParamKeyFlag.CLEAR_ON_MANAGER_START)
params.clear_all(ParamKeyFlag.CLEAR_ON_ONROAD_TRANSITION)
params.clear_all(ParamKeyFlag.CLEAR_ON_OFFROAD_TRANSITION)
+7 -1
View File
@@ -67,6 +67,9 @@ class MeteredType(IntEnum):
NO = 2
_WARNED_UNSUPPORTED_NETWORKS: set[tuple[int, int, int]] = set()
def get_security_type(flags: int, wpa_flags: int, rsn_flags: int) -> SecurityType:
wpa_props = wpa_flags | rsn_flags
@@ -83,7 +86,10 @@ def get_security_type(flags: int, wpa_flags: int, rsn_flags: int) -> SecurityTyp
# WPA2, WPA2+WPA3 mixed, or WPA — all handled via WPA key_mgmt (NM negotiates SAE if available)
return SecurityType.WPA2
else:
cloudlog.warning(f"Unsupported network! flags: {flags}, wpa_flags: {wpa_flags}, rsn_flags: {rsn_flags}")
_key = (flags, wpa_flags, rsn_flags)
if _key not in _WARNED_UNSUPPORTED_NETWORKS:
_WARNED_UNSUPPORTED_NETWORKS.add(_key)
cloudlog.warning(f"Unsupported network! flags: {flags}, wpa_flags: {wpa_flags}, rsn_flags: {rsn_flags}")
return SecurityType.UNSUPPORTED