IQ.Pilot Release Commit @ ab07000

This commit is contained in:
IQ.Lvbs CI [bot]
2026-08-08 11:48:21 -05:00
parent 31c07687c4
commit 9e52535231
42 changed files with 368 additions and 223 deletions
@@ -16,27 +16,27 @@
},
"python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "9368086c4cdd6cf46b6a6d0a1e1e83fdc7e7dff8d3bd67a42b3bffa91b45dc26",
"sha256": "e79be61e50cd0830197f44f8a6840b86a74b8059da45da65a4696587168ac466",
"size": 135536
},
"python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "291789f912304c72cd1e0da955bd58fa903cd99e7d6504e6c3c51d39befaf6e8",
"sha256": "ebfeedba6cc5cac6dca1cf8125879fcb2d6afdbaec31a98dd46c3d346f55c982",
"size": 67664
},
"python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "c47ec079040efee31673f55752a6215b3a8908c63c8373625ce5cb4cb1177aff",
"sha256": "11ffe8f261b78990aa743b43aed3a5534105da848be1450026090ae873ad0a2e",
"size": 204624
},
"python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "a0d5710938b32e56f2fc55c86ff8947787a3ebeb43850a94a90202c3773ff74e",
"sha256": "e62a6438c18b231f83cc873ac8170a64e670c8912ffba13edf47f163886aef19",
"size": 69752
},
"python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "ff345aa71ac599bdd16747368ceb92fae7b5b35657f81466fc0660b76d44aa22",
"sha256": "07195ca6d4e1ff26441e860d954e9c79e3da608244d110bfa62b3aa0818a79dc",
"size": 203072
},
"python/iqpilot_private/konn3kt/flockd/__init__.py": {
@@ -46,12 +46,12 @@
},
"python/iqpilot_private/konn3kt/flockd/flockd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "2aa26e4bc71870f639fca6e8e273deb59f50cf6a6d963ba77ce0949c65a52d63",
"sha256": "d18b8d67100f5906339dde577bc14f567168ff62e1b9166c011af853c016191e",
"size": 202168
},
"python/iqpilot_private/konn3kt/flockd/signatures.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "96b47ec40dd7e3430cebf3979b4fdfb0096e80029b40da6445cdf44dbcdb8917",
"sha256": "1a601a0de826fb41fadb3cef9e8b8645d99e41507befc36e87d077d49efd3025",
"size": 68080
},
"python/iqpilot_private/konn3kt/hephaestus/__init__.py": {
@@ -61,67 +61,67 @@
},
"python/iqpilot_private/konn3kt/hephaestus/_vendor/localapi_runtime.zip": {
"mode": 420,
"sha256": "f12e44b7a986616d6b3c4e127e4eeae793e346f31d5b821ad9c44249e4731ebd",
"sha256": "c3063f3d380627f604b0ae1cdd20fbfdfa7b64d212c86f20abd470230af8e169",
"size": 2100238
},
"python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "4ac192d102bde18d9b3215ff637e1c316a08eb0eb00c595c07eaa07284d1f28c",
"sha256": "57dbd02e130361d33c8a52635261ce85f3a91c577b70d5fad8a0e9e7557f9d46",
"size": 268064
},
"python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "6f2dccd9f85db9d4948ddb31f62b6059d9359f7f16df6d55455b05c6ae4f37b7",
"size": 340584
"sha256": "1febeeb24421c82a64416a7ab04def21d57a39acf0caaf2103b4ebfbae655fc2",
"size": 406216
},
"python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "abb3eb9033205d1c2903b619dbbab7e3de10b859493239c35533b75d00bc3305",
"sha256": "42656c3b54f6392e2311e4039296e4906558fd8c63ba6be04b157445b96d38c9",
"size": 68048
},
"python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "a631270d167cbd9a67db6111de57e5d6ddcdd554706fd9fd919d8f116733bf66",
"sha256": "acdf51e90428e4487f0daf6e0e43110ef5fc1c7705d16aa3b9880618030f41f3",
"size": 335728
},
"python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "c5c4f480275ddc00e2d7d44aee76808f2b4184b6a6354ef2e757d8b3a7ae8e44",
"sha256": "95afe64579cac0148c3de23867a333651dfed4606c218208dcf37b40a1cc6450",
"size": 271680
},
"python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "a9d9fdfcd6f154e093ed1cc678bf9a1e12c7a3e475a358c19941af7777c40807",
"sha256": "fd983039accfaa30abf3d46f41c70241d1c3fcf4e21a1de7d3270ab9fce9b03c",
"size": 134408
},
"python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "d3468f09df47814c161937306c776df5fe9a6a6d819859a596f7e33be6d253e8",
"sha256": "cc299f0d560bbd611cab099923bb1817229df3cbc15cef22d6909091e9de826b",
"size": 3581928
},
"python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "c7cf16d3b2297deafd87c53c8b61031d2af84ff04848bab34d9dde37ba939ed5",
"sha256": "0dbcb5d9ec1af832bcaceaa3ae96a4785a432778c1fb3cdc8b74e62b5d915158",
"size": 136448
},
"python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "113890a2fa588f0c3d6d0c6723aef63adb58fc3ad5355174effe5ac2d3d6d364",
"sha256": "cabf37e151994a223f890627c0128990e56505bc704108f050d2422e118a273a",
"size": 68136
},
"python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "e97f1650766b15b231657afd6530c019d09352dfa0d96deb2643893acf56efa4",
"sha256": "10af02f5daf288e465bcaa64509972a1a0b268f779b1c12c58bf63c79e52eb96",
"size": 67840
},
"python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "7be8a68c56f6ff37ef887b87275c78e517065995243e88d1ab6a10f3b028abe5",
"sha256": "855f128d248c94fbd00f550f7dd388ccf1a487935d7f11cac00e5240b526d674",
"size": 135648
},
"python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "2a1f6cbb8794a29a55decf6d04915e752360eac7701ed55c826355bb348e39a6",
"sha256": "8de50d50308777ff9dc22d4d5232cba38f2f332207313999ec8aaa67e5004f4e",
"size": 269568
},
"python/iqpilot_private/konn3kt/uploaderd/__init__.py": {
@@ -131,7 +131,7 @@
},
"python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "613141bdba6cabaf47fa07b438fe964e90796b7e0309c8f0fbfa60b6bf54e6ad",
"sha256": "11d16de5d29a37f64351acabfa6372966447a88cd7d799580a6f2f1fa745c15a",
"size": 204184
},
"runtime": {
@@ -171,25 +171,25 @@
}
},
"signatures": {
"python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so": "nSuJmlS6Uu7Z2hCUfo8ia0v3TtLy0k7vXuUtkRteuXr283FbjSL/SAnGZtotLam9QqWcKUZiX5AY7iKRxdJRDA==",
"python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so": "b4kzh2Ih+crCs71fFdIku1vWUarJheL2EFkX9K85ppio/t27Vml4wjdRXt6G9ImEIwXb0FwZQ5TO290oTS81DQ==",
"python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so": "Y4Z6VxELzmD2+MZKv/Uk7mE03ZFxxjXFiV21zHXbGTTQ8x+3OWSs+c43kfEFO7+Y0GRLAV/pFVdS4TJotL1bCA==",
"python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so": "uKdDonv7l3RV5Rk0p18w2B7OFo56b61Gdzj4Q2HCa4MkjzVv81Pe7kf+2AbRXJ+tV74P1Xg/S4uFYH9B03D7Cw==",
"python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so": "+HMqTUeIHFUo9Fr7/yzkI9tQ+/uCJI1dH06oRDg1xgU8YjuiI8XUZCpgsUR4nMn7O497qiCdL5TfiYJw/0j/AQ==",
"python/iqpilot_private/konn3kt/flockd/flockd.cpython-312-aarch64-linux-gnu.so": "EOxdzTbj5/I7gOu48kM3Z0G54cJ1pII4tikrDqYhVSFRiJopUPtjb2IAG/Lg0D6kwZaIzbkEVpRKq707MF2BAw==",
"python/iqpilot_private/konn3kt/flockd/signatures.cpython-312-aarch64-linux-gnu.so": "fZ8UhZhwmPn4IMxudbJkmrCsBj/A+EOH4cdzT8Vb75kI7SD9V5rR7gRCPFuVEL1nQ6lnlF2QW4Osmik2WOqeDA==",
"python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so": "bptAbc1grlaQ8cQoR1RZ1p5GKEvnHUGOpyRoCmkK2xW2HMRD9YmY+t7HrARFfr14Bkp0dgdVKswzZWa6aUR3Cg==",
"python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so": "4Q9ZzJhFaTqnaj66o+CHE/vtjY9qWOHO7UFYZrxs3uQdUaeIO5JUkXHtr4Fl7mDrZy0zaT8hL+R6g7zj8VLCCg==",
"python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so": "bzGWFkSPQg9xj1Rl8jBkGx3coMF6srLe509MLng4gQMqo8hHHWZTFI3235UsSJCkbnPjOolUWzVLtbDp5bMmDQ==",
"python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so": "pIB/KThS9GZ+HYf+SSd14rxawltaKKAZ1cFyYRPWpAnpEZ4q/Vz7G2o6bdEZ2r8bJsfBMMkzyPLRJQwpX0jODQ==",
"python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so": "FEbOGV+d8BvV4yurjBNz74nK0CT+yQSReXPRliMt9uuMNLKVuRMlUibmgD63sx7tv0hz7Z49VwYYZVlwEPNrDw==",
"python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so": "x17n17jSDgrTCCphHNWZQ4ibHMGITtrhaDK1wBmWFqj6uzr3cWWXV6THxNJy4qbj9/yHVLICGNuW7wIOb0tzDQ==",
"python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so": "ldjMNYlSmOa3XjWrcqlDMrNybvFZ3T9aVVZevwt9TYxVgUrz/5qMui7KIAPdEins39c4fu0jayqM/1V0kjsUCA==",
"python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so": "Cvq80OZLZ0rIywx1RjkV5cd6jKnpL0Rq9evyOxGqYwc0xGCGL1t2YqsoiyyODMeMphEdvdK+w+OMBge6OGk1DQ==",
"python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so": "17P0y74P0Ug92QlhioE6XJJ6p3tz8atS5Wp2SihaQZfnERG8CCjQ6RjVBSwINdvJuU05sGexOlb29Cjebc92DQ==",
"python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so": "wcXjEUKfLHopsy91qnShxa8/1D6wChOsFZcOkPnA0b61vPY7ceKlVMXcv+ECr35BiMsW4gHQG9MSMoyXo1ZJAw==",
"python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so": "8nTnxWCYCQ2mtzd8JL8kcRLsU6JrKVrfMNfI84ovoejxH7kAXCM6d3f1u6TFNPqrQjlIFlc1AyUoL7UoFsQJCA==",
"python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so": "fs6ZLA1aFyUMWRpeSduc0nnv4cJjb3OIdxmUGaCr58D5GAGBSOOUQszzMWDwrEOCQ0JOsW27TM3VmliIhP1cBA==",
"python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so": "YleZT+ZmBpdryTlsH4k+yoLYhyIJ1DMPYnEC8L2ixxJejAjcUBmn2GjXFSS+7JzK6g8aokV6NswVSqbuIVOJDQ=="
"python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so": "1DjE26Z6yX6VuP+Jx/DxxS2PjWXSXLd+bS1RgYEo9WNOEHENVDv1xeoyXjFmrXe6/QTILJpv+LnqWegfVSnFBQ==",
"python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so": "ytsUI7NI3t/9m+zEfMCbXVCIggeKSk8lnTrVYWQr0uryX5tTtQXyR+f+rIPSZWzzHu80z3GE0jmnQEEN2m6XCA==",
"python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so": "Y57ZaVfeeB1Mnu4vFIQNSZIuob+jmBkuuZ86Zc0sOWvqgkE8gT41pivlipr/R/du5+HSqXvTv/iuQS8ekTBpCg==",
"python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so": "PGjuQc316L/r8sSGF0Hg5EnFWj/Bhk27UYBgGvQ8xxLvoVJIkRKVJ/ZFLFZo6rdEWrd0GQECUYeR9ewU6ufFAA==",
"python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so": "CVrgu0dEypYq6IIA38Lh/w4KKVNpP5+dfV0dkOpDA4UkyH2IoX3Wiywpz3o1jfjrSXE3oiPdk52qRE+pzLLxDQ==",
"python/iqpilot_private/konn3kt/flockd/flockd.cpython-312-aarch64-linux-gnu.so": "+grQAam3UiFIBqGcvuAI+7aYW6UCU83YLlxCkPoo6YaX9SitDVqQk6bNQwqxYUzuUZ2s8BdhlbgseTuImRZMBw==",
"python/iqpilot_private/konn3kt/flockd/signatures.cpython-312-aarch64-linux-gnu.so": "yhxeGAidy3Auu+i2wZgxD1bK18VeWknYuQQpeiylNyWNfzN/xPUDGFyyV0CpNY3FqEqH8LcHLzsa8Bz4JTbWDw==",
"python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so": "OX/9GfQQf/krppHPChnXqvvHCs+8LqdpnRtRxJ9AYeqRLwNMrTgCSLOsU3YGlHiF78U5jIldNdkr4aOGBHRVAg==",
"python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so": "n06LgyR6cPqHLaGsiEXlSFiNKFkT3S14mPEz+xtLw0y3bAuNod5Jpp6KiVuoTcVdzHjXPFWwYLgqbtDxSZe/BQ==",
"python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so": "JJ8eaFR2wkJW4/gw31a35LvyHLKTLfPwFwIC3cE5Y4AYbLkrVuVbizPefhUrcFMF0ZxzjQulU0YNAL7EMbzOAA==",
"python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so": "Vr/pX91mN1D0Qcl9PNJiT2DUq9LxP13qjO5g7Ve/KDPwAqL9nKJXeAqbhKXIqFyRHp82PAHKaVhHsF39QtLRAA==",
"python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so": "yjHeFmvqDWSEXIft0n93zTSZemP4L9hmXZtauDFL7bRnGHMnTVvrq7olJJoXvQITVGyGzDl+BuDF5pjOKau+AQ==",
"python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so": "7sVJ5qadF1T48RP8FlwynsJEC0w6OtN+BGBf93YABFXgYDPY/YAMm5aAicR6YmGvgkFqtfCf5g8ozdrz5fIuBg==",
"python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so": "54+MaaeOIEbj+uZrcphTbHQ8K1jm4gRe2JYZyYNkwxPcT6dkcWLM6NZiNVzXiD6Ph87hTxUbecJnhVeT80pDAw==",
"python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so": "xJnkGTaVVWne7p83UhTU2C/miZg4XR7pLrd6A7j7TvetRCFvQPxyuAeFi5lJsKKwhaWV3dInGZcVWrGV+kV0AA==",
"python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so": "P+LVQJc3vD5Z9i/jxNxziNbgCiGrI+5P9saUGHMPMKUoWhVEBAAVU8xuVyd6GjSd8M5VrximPVrJyMCE9fEfAw==",
"python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so": "vfDMFKWuTD2XSE7JF/qmHxcOXgdXRZN9fi3FTSffmr6t22Tz0N7v8MwVayiPKrYNt2gHixFZ9aAkvF2SC+yDBg==",
"python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so": "Orgr5aTB5g3NRH8AdsuNkpcmIfSQDBFHzegDN875SxuvHuCOfsVVYgx2TtRiT0wqSR9hlQQwhelyRHRQjcMCAQ==",
"python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so": "tZNbbDyMxkFOcrvWCEBQz6ZTGdLZVesuz0dbUMO1OBaSYAG4MRBQ5y9fZwRQZAvcEa+NMlNZK2SGoC6r5BxgDA==",
"python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so": "sgYjdE7ZRvdKlehs1/h3z/n14fksR+Z+KhCzi0BvFPcbMcx0Pod/L42IQeEDfcQfoFBURPNoI1OTwWc31H/NAQ=="
}
}
@@ -245,6 +245,9 @@ class CarController(CarControllerBase):
self.leadDistanceBars = 0
self.lead_distance_bars_last = None
self.distance_bar_frame = 0
self.mlb_hud_text = 0
self.mlb_hud_text_frame = 0
self.mlb_set_speed_last = 0
self.speed_limit_last = 0
self.speed_limit_changed_timer = 0
self.blinkerActive = None
@@ -280,6 +283,19 @@ class CarController(CarControllerBase):
return float(np.interp(v_ego, [0.4, 3.5, 4.0], [0.8, 0.95, 1.0]))
return 1.0
def _mlb_acc_hud_text(self, hud_control, set_speed: float) -> int:
# ACC_02 primary display text, briefly surfaced on a follow distance or set speed change
if hud_control.leadDistanceBars != self.lead_distance_bars_last:
self.mlb_hud_text_frame = self.frame
self.mlb_hud_text = self.CCP.ACC_HUD_TEXT_DISTANCE.get(hud_control.leadDistanceBars, self.CCP.ACC_HUD_TEXTS["none"])
elif set_speed != self.mlb_set_speed_last and hud_control.speedVisible:
self.mlb_hud_text_frame = self.frame
self.mlb_hud_text = self.CCP.ACC_HUD_TEXTS["setSpeed"]
elif self.frame - self.mlb_hud_text_frame >= self.CCP.ACC_HUD_TEXT_STEP:
self.mlb_hud_text = self.CCP.ACC_HUD_TEXTS["none"]
self.mlb_set_speed_last = set_speed
return self.mlb_hud_text
def _should_spam_mqb_a0_resume(self, CS, enabled: bool) -> bool:
return bool(
enabled and
@@ -429,8 +445,9 @@ class CarController(CarControllerBase):
can_sends.append(self.CCS.create_blinker_control(self.packer_pt, self.CAN.pt, CS.ea_hud_stock_values, CS.ea_control_stock_values,
left_blinker, right_blinker, self.hide_ea_error))
if self.CP.openpilotLongitudinalControl and self.CCS == mqbcan and not self.acc_counter_seeded and CS.acc_stock_counters:
for name in ("ACC_02", "ACC_06", "ACC_07", "ACC_10"):
if self.CP.openpilotLongitudinalControl and self.CCS in (mqbcan, mlbcan) and not self.acc_counter_seeded and CS.acc_stock_counters:
seed_msgs = ("ACC_01", "ACC_02") if self.CCS is mlbcan else ("ACC_02", "ACC_06", "ACC_07", "ACC_10")
for name in seed_msgs:
addr = self.packer_pt.dbc.name_to_msg[name].address
self.packer_pt.counters[addr] = (CS.acc_stock_counters[name] + 1) % 16
self.acc_counter_seeded = True
@@ -499,6 +516,8 @@ class CarController(CarControllerBase):
self.long_deviation, self.long_jerklimit, eBrakeActive,
esp_starting_override=esp_starting_override, esp_stopping_override=esp_stopping_override,
))
elif self.CCS == mlbcan:
can_sends.extend(self.CCS.create_acc_accel_control(self.packer_pt, self.CAN.pt, accel, acc_control, stopping))
else:
accel = apply_pq_stopping_accel(self.CP.carFingerprint, accel, stopping)
@@ -577,7 +596,10 @@ class CarController(CarControllerBase):
acc_hud_status = self.CCS.acc_hud_status_value(CS.out.cruiseState.available, CS.out.accFaulted, CC.longActive, CC.cruiseControl.override)
set_speed = hud_control.setSpeed * CV.MS_TO_KPH
decel = dVisual(self.CCS, CS)
can_sends.append(self.CCS.create_acc_hud_control(self.packer_pt, self.CAN.pt, acc_hud_status, set_speed, leadDistance, self.leadDistanceBars, fcw_alert, hud_control.leadVisible, self.unavailable, decel, d_unresponsive))
hud_kwargs = {"hud_text": self._mlb_acc_hud_text(hud_control, set_speed)} if self.CCS is mlbcan else {}
can_sends.append(self.CCS.create_acc_hud_control(self.packer_pt, self.CAN.pt, acc_hud_status, set_speed, leadDistance,
self.leadDistanceBars, fcw_alert, hud_control.leadVisible, self.unavailable,
decel, d_unresponsive, **hud_kwargs))
if self.CP.flags & VolkswagenFlags.PQ:
iq_lvbs_commander.update_turn_signals(self, CC, CS, can_sends)
+16 -6
View File
@@ -675,9 +675,12 @@ class CarState(CarStateBase):
else:
ret.gearShifter = GearShifter.drive
# ACC okay but disabled (1), ACC ready (2), a radar visibility or other fault/disruption (6 or 7)
# currently regulating speed (3), driver accel override (4), brake only (5)
if self.CP.carFingerprint == CAR.PORSCHE_MACAN_MK1:
cruise_main_switch = bool(pt_cp.vl["LS_01"]["LS_Hauptschalter"])
if not self.CP.pcmCruise:
ret.cruiseState.available = cruise_main_switch
ret.cruiseState.enabled = False
ret.accFaulted = False
elif self.CP.carFingerprint == CAR.PORSCHE_MACAN_MK1:
ret.cruiseState.available = ext_cp.vl["ACC_05"]["ACC_Status_ACC"] in (2, 3, 4, 5)
ret.cruiseState.enabled = ext_cp.vl["ACC_05"]["ACC_Status_ACC"] in (3, 4, 5)
ret.accFaulted = ext_cp.vl["ACC_05"]["ACC_Status_ACC"] in (6, 7)
@@ -687,6 +690,12 @@ class CarState(CarStateBase):
ret.cruiseState.speed = ext_cp.vl["ACC_02"]["ACC_Wunschgeschw_02"] * CV.KPH_TO_MS
ret.accFaulted = pt_cp.vl["TSK_02"]["TSK_Status"] in (3,)
ret.cruiseState.nonAdaptive = bool(pt_cp.vl["LS_01"]["LS_Limiter"])
if not self.CP.pcmCruise:
self.acc_stock_counters["ACC_01"] = int(ext_cp.vl["ACC_01"]["COUNTER"])
self.acc_stock_counters["ACC_02"] = int(ext_cp.vl["ACC_02"]["COUNTER"])
self.esp_hold_confirmation = bool(pt_cp.vl["ESP_02"]["ESP_Stillstandsflag"])
self.parse_mlb_mqb_steering_state(ret, pt_cp)
self._update_mlb_iq_alc_state(pt_cp)
@@ -728,9 +737,10 @@ class CarState(CarStateBase):
ret.cruiseState.standstill = self.CP.pcmCruise and self.esp_hold_confirmation
ret.standstill = ret.vEgoRaw == 0
ret.cruiseFaultLateralMode = False
ret.lateralAvailable = ret.cruiseState.available
ret.blockPcmEnable = False
allow_lat_only = self._params.get_bool("AllowLateralWhenLongUnavailable") and self._params.get_bool("AolEnabled")
ret.cruiseFaultLateralMode = allow_lat_only and ret.accFaulted and cruise_main_switch
ret.lateralAvailable = ret.cruiseState.available or ret.cruiseFaultLateralMode
ret.blockPcmEnable = ret.cruiseFaultLateralMode
self.cruise_faulted = ret.accFaulted
self.frame += 1
@@ -91,6 +91,7 @@ class CarInterface(CarInterfaceBase):
safety_configs = [get_safety_config(structs.CarParams.SafetyModel.volkswagenMlb)]
ret.enableBsm = 0x30F in fingerprint[0] # SWA_01
ret.networkLocation = NetworkLocation.gateway
ret.transmissionType = TransmissionType.automatic
ret.dashcamOnly = False
elif ret.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
+54 -11
View File
@@ -1,4 +1,11 @@
from iqdbc.car.volkswagen.mqbcan import (volkswagen_mqb_meb_checksum, xor_checksum, create_lka_hud_control as mqb_create_lka_hud_control)
from iqdbc.car.volkswagen.mqbcan import (volkswagen_mqb_meb_checksum, xor_checksum,
acc_control_value as mqb_acc_control_value,
acc_hud_status_value as mqb_acc_hud_status_value,
create_lka_hud_control as mqb_create_lka_hud_control)
# ACC_01.ACC_Sollbeschleunigung one increment above range max, "no acceleration request"
ACC_INACTIVE_ACCEL = 3.01
def create_hca_steering_control(packer, bus, apply_steer, HCA_Status):
values = {
@@ -11,8 +18,10 @@ def create_hca_steering_control(packer, bus, apply_steer, HCA_Status):
return packer.make_can_msg("HCA_01", bus, values)
def create_lka_hud_control(packer, bus, ldw_stock_values, enabled, steering_pressed, hud_alert, hud_control, entering=False, special_mode=False, special_active=False):
return mqb_create_lka_hud_control(packer, bus, ldw_stock_values, enabled, steering_pressed, hud_alert, hud_control, entering, special_mode, special_active)
def create_lka_hud_control(packer, bus, ldw_stock_values, enabled, steering_pressed, hud_alert, hud_control,
entering=False, special_mode=False, special_active=False):
return mqb_create_lka_hud_control(packer, bus, ldw_stock_values, enabled, steering_pressed, hud_alert, hud_control,
entering, special_mode, special_active)
def create_acc_buttons_control(packer, bus, gra_stock_values, cancel=False, resume=False, set_button=False):
@@ -32,23 +41,57 @@ def create_acc_buttons_control(packer, bus, gra_stock_values, cancel=False, resu
return packer.make_can_msg("LS_01", bus, values)
def acc_control_value(main_switch_on, long_active, cruiseOverride):
return 0
def acc_control_value(main_switch_on, long_active, cruiseOverride, accFaulted):
# ACC_01.ACC_Status_ACC uses the same enum as MQB ACC_06: 0 off, 2 standby, 3 active, 4 driver override, 6 fault
return mqb_acc_control_value(main_switch_on, long_active, cruiseOverride, accFaulted)
def acc_hud_status_value(main_switch_on, acc_faulted, longActive, longOverride):
return 0
return mqb_acc_hud_status_value(main_switch_on, acc_faulted, longActive, longOverride)
def create_acc_accel_control(packer, bus, acc_type, accel, acc_control, stopping, starting, esp_hold, comfortBand, jerkLimit):
values = {}
return [packer.make_can_msg("ACC_05", bus, values)]
def create_acc_accel_control(packer, bus, accel, acc_control, stopping):
acc_enabled = acc_control in (3, 4)
acc_01_values = {
"ACC_Status_ACC": acc_control,
"ACC_Sollbeschleunigung": accel if acc_enabled else ACC_INACTIVE_ACCEL,
"ACC_zul_Regelabw_unten": 0.2,
"ACC_zul_Regelabw_oben": 0.2,
"ACC_neg_Sollbeschl_Grad": 4.0 if acc_enabled else 0,
"ACC_pos_Sollbeschl_Grad": 4.0 if acc_enabled else 0,
"ACC_Dynamik": 3,
"ACC_Anhalten": stopping if acc_enabled else False,
"ACC_Minimale_Bremsung": 0,
}
return [packer.make_can_msg("ACC_01", bus, acc_01_values)]
def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, leadDistance, distanceBars, fcw_alert, leadVisible, unavailable, decel, d_unresponsive):
values = {}
def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, leadDistance, distanceBars, fcw_alert, leadVisible,
unavailable, decel, d_unresponsive, hud_text=0):
engaged = acc_hud_status in (3, 4)
priodisp = 0 if fcw_alert else 1 if (acc_hud_status == 4 or decel or leadVisible) else 2 if (acc_hud_status in (3, 2)) else 0
leadDistanceBars = distanceBars + 1 if distanceBars in (1, 2, 3) else 2
values = {
"ACC_Status_Anzeige": acc_hud_status,
"ACC_Wunschgeschw_02": set_speed if set_speed < 250 else 327.36,
"ACC_Gesetzte_Zeitluecke": leadDistanceBars,
"ACC_Anzeige_Zeitluecke": 1 if engaged else 0,
"ACC_Tachokranz": 1 if engaged else 0,
"ACC_Display_Prio": priodisp,
"ACC_Abstandsindex": leadDistance if leadVisible else 0,
"ACC_Relevantes_Objekt": 2 if fcw_alert else (1 if leadVisible else 0), # lead car: 1 green, 2 red, 0 off
"ACC_Status_Prim_Anz": 2 if fcw_alert else (1 if engaged else 0), # ACC symbol: 1 green, 2 red, 0 off
"ACC_Optischer_Fahrerhinweis": 1 if fcw_alert else 0,
"ACC_Akustik": 1 if (fcw_alert or d_unresponsive) else 0,
"ACC_Texte_Primaeranz": hud_text,
}
return packer.make_can_msg("ACC_02", bus, values)
def volkswagen_mlb_checksum(address: int, sig, d: bytearray) -> int:
xor_starting_value = {
0x109: 0x08, # ACC_01
+9 -1
View File
@@ -2,7 +2,7 @@ from collections import defaultdict, namedtuple
from dataclasses import dataclass, field
from enum import Enum, IntFlag, StrEnum
from iqdbc.car import ACCELERATION_DUE_TO_GRAVITY, Bus, CanBusBase, CarSpecs, DbcDict, PlatformConfig, Platforms, structs, uds
from iqdbc.car import ACCELERATION_DUE_TO_GRAVITY, Bus, CanBusBase, CarSpecs, DbcDict, DT_CTRL, PlatformConfig, Platforms, structs, uds
from iqdbc.car.lateral import CurvatureSteeringLimits
from iqdbc.can import CANDefine
from iqdbc.car.common.conversions import Conversions as CV
@@ -204,6 +204,7 @@ class CarControllerParams:
self.STEER_DRIVER_ALLOWANCE = 60 # Driver intervention threshold 0.6 Nm
self.STEER_DELTA_UP = 9 # Max HCA reached in 0.66s (STEER_MAX / (50Hz * 0.66))
self.STEER_DELTA_DOWN = 10 # Min HCA reached in 0.60s (STEER_MAX / (50Hz * 0.60))
self.ACC_HUD_TEXT_STEP = int(2.0 / DT_CTRL) # ACC_02 primary display text dwell time
if CP.carFingerprint == CAR.PORSCHE_MACAN_MK1:
self.shifter_values = can_define.dv["Getriebe_03"]["GE_Waehlhebel"]
@@ -219,6 +220,13 @@ class CarControllerParams:
Button(structs.CarState.ButtonEvent.Type.gapAdjustCruise, "LS_01", "LS_Verstellung_Zeitluecke", [1, 2, 3]),
]
# ACC_02.ACC_Texte_Primaeranz, primary ACC display text at the bottom of the cluster
self.ACC_HUD_TEXTS = {
"none": 0,
"setSpeed": 21,
}
self.ACC_HUD_TEXT_DISTANCE = {1: 2, 2: 3, 3: 4, 4: 5} # follow distance bars to display text
else:
self.STEER_DRIVER_ALLOWANCE = 80 # Driver intervention threshold 0.8 Nm
self.STEER_DELTA_UP = 4 # Max HCA reached in 1.50s (STEER_MAX / (50Hz * 1.50))
+2 -2
View File
@@ -35,7 +35,7 @@ BS_:
BU_: Airbag_D4 EPB_D4 ESP_D4 Gateway_D4C7 Getriebe_AL551_951_D4_C7 Getriebe_DL501_C7 Getriebe_VL381_C7 LWS_D4 Motor_EDC17_D4 Motor_ME17_BY Motor_MED17_SIMOS8_D4 Motor_Slave_D4 QSP_D4 SAK_C7 SCR_C7 SCU_D4
BO_ 265 ACC_01: 8 Gateway_B8
SG_ ACC_01_CHK : 0|8@1+ (1,0) [0|255] "" Magnetic_Ride_LB,Motor_MLB_AU48_AU416_Diesel,Motor_MLB_B8_Q5_Otto,Motor_MLB_Q5_Hybrid
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" Magnetic_Ride_LB,Motor_MLB_AU48_AU416_Diesel,Motor_MLB_B8_Q5_Otto,Motor_MLB_Q5_Hybrid
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" Magnetic_Ride_LB,Motor_MLB_AU48_AU416_Diesel,Motor_MLB_B8_Q5_Otto,Motor_MLB_Q5_Hybrid
SG_ ACC_zul_Regelabw_unten : 16|6@1+ (0.024,0) [0|1.512] "Unit_MeterPerSeconSquar" Motor_MLB_AU48_AU416_Diesel,Motor_MLB_B8_Q5_Otto,Motor_MLB_Q5_Hybrid
SG_ ACC_Sollbeschleunigung : 24|11@1+ (0.005,-7.22) [-7.22|3.01] "Unit_MeterPerSeconSquar" Magnetic_Ride_LB,Motor_MLB_AU48_AU416_Diesel,Motor_MLB_B8_Q5_Otto,Motor_MLB_Q5_Hybrid
@@ -48,7 +48,7 @@ BO_ 265 ACC_01: 8 Gateway_B8
SG_ ACC_Minimale_Bremsung : 63|1@1+ (1,0) [0|1] "" Motor_MLB_AU48_AU416_Diesel,Motor_MLB_B8_Q5_Otto,Motor_MLB_Q5_Hybrid
BO_ 780 ACC_02: 8 Gateway_D4C7
SG_ ACC_02_CHK : 0|8@1+ (1,0) [0|255] "" HUD_C7,Kombi_D4
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" HUD_C7,Kombi_D4
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" HUD_C7,Kombi_D4
SG_ ACC_Wunschgeschw_02 : 12|10@1+ (0.32,0) [0.00|326.72] "Unit_KiloMeterPerHour" HUD_C7,Kombi_D4
SG_ ACC_Status_Prim_Anz : 22|2@1+ (1.0,0.0) [0.0|3] "" HUD_C7,Kombi_D4
@@ -100,7 +100,7 @@ void can_set_checksum(CANPacket_t *packet);
#define MSG_MOTOR_03 0x105U // RX from ECU, for driver throttle input and brake switch status
#define MSG_TSK_02 0x10CU // RX from ECU, for ACC status from drivetrain coordinator
#define MSG_ACC_05 0x10DU // RX from radar, for ACC status
#define MSG_ACC_01 0x109U // RX from radar, for ACC status (Audi B8)
#define MSG_ACC_01 0x109U // TX by OP, ACC control instructions to the drivetrain coordinator
static void volkswagen_common_init(void) {
volkswagen_set_button_prev = false;
+46 -4
View File
@@ -9,6 +9,9 @@ static safety_config volkswagen_mlb_init(uint16_t param) {
static const CanMsg VOLKSWAGEN_MLB_STOCK_TX_MSGS[] = {{MSG_HCA_01, 0, 8, .check_relay = true}, {MSG_LDW_02, 0, 8, .check_relay = true},
{MSG_LS_01, 0, 4, .check_relay = false}, {MSG_LS_01, 2, 4, .check_relay = false}};
static const CanMsg VOLKSWAGEN_MLB_LONG_TX_MSGS[] = {{MSG_HCA_01, 0, 8, .check_relay = true}, {MSG_LDW_02, 0, 8, .check_relay = true},
{MSG_ACC_01, 0, 8, .check_relay = true}, {MSG_ACC_02, 0, 8, .check_relay = true}};
static RxCheck volkswagen_mlb_rx_checks[] = {
// TODO: implement checksum validation
{.msg = {{MSG_ESP_03, 0, 8, 50U, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
@@ -19,10 +22,17 @@ static safety_config volkswagen_mlb_init(uint16_t param) {
{.msg = {{MSG_LS_01, 0, 4, 10U, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
};
SAFETY_UNUSED(param);
volkswagen_common_init();
return BUILD_SAFETY_CFG(volkswagen_mlb_rx_checks, VOLKSWAGEN_MLB_STOCK_TX_MSGS);
#ifdef ALLOW_DEBUG
volkswagen_longitudinal = GET_FLAG(param, FLAG_VOLKSWAGEN_LONG_CONTROL);
volkswagen_allow_long_accel_with_gas_pressed = GET_FLAG(param, FLAG_VOLKSWAGEN_ALLOW_LONG_ACCEL_WITH_GAS_PRESSED);
#else
SAFETY_UNUSED(param);
#endif
return volkswagen_longitudinal ? BUILD_SAFETY_CFG(volkswagen_mlb_rx_checks, VOLKSWAGEN_MLB_LONG_TX_MSGS) : \
BUILD_SAFETY_CFG(volkswagen_mlb_rx_checks, VOLKSWAGEN_MLB_STOCK_TX_MSGS);
}
static void volkswagen_mlb_rx_hook(const CANPacket_t *msg) {
@@ -44,6 +54,27 @@ static void volkswagen_mlb_rx_hook(const CANPacket_t *msg) {
}
if (msg->addr == MSG_LS_01) {
// If using openpilot longitudinal, the stock ACC coordinator is relayed out, so the stalk main
// switch is the only remaining source of truth. Enter controls on falling edge of Set or Resume.
// Signal: LS_01.LS_Hauptschalter
// Signal: LS_01.LS_Tip_Setzen
// Signal: LS_01.LS_Tip_Wiederaufnahme
if (volkswagen_longitudinal) {
acc_main_on = GET_BIT(msg, 12U);
bool set_button = GET_BIT(msg, 16U);
bool resume_button = GET_BIT(msg, 19U);
if ((volkswagen_set_button_prev && !set_button) || (volkswagen_resume_button_prev && !resume_button)) {
controls_allowed = acc_main_on;
}
volkswagen_set_button_prev = set_button;
volkswagen_resume_button_prev = resume_button;
if (!acc_main_on) {
controls_allowed = false;
}
}
// Always exit controls on rising edge of Cancel
// Signal: LS_01.LS_Abbrechen
if (GET_BIT(msg, 13U)) {
@@ -64,7 +95,7 @@ static void volkswagen_mlb_rx_hook(const CANPacket_t *msg) {
brake_pressed = volkswagen_brake_pedal_switch || volkswagen_brake_pressure_detected;
if (msg->addr == MSG_TSK_02) {
if ((msg->addr == MSG_TSK_02) && !volkswagen_longitudinal) {
// When using stock ACC, enter controls on rising edge of stock ACC engage, exit on disengage
// Always exit controls on main switch off
// Signal: TSK_02.TSK_Status
@@ -80,7 +111,7 @@ static void volkswagen_mlb_rx_hook(const CANPacket_t *msg) {
if (msg->bus == 2U) {
// TODO: See if there's a bus-agnostic TSK message we can use instead
if (msg->addr == MSG_ACC_05) {
if ((msg->addr == MSG_ACC_05) && !volkswagen_longitudinal) {
// When using stock ACC, enter controls on rising edge of stock ACC engage, exit on disengage
// Always exit controls on main switch off
// Signal: ACC_05.ACC_Status_ACC
@@ -123,6 +154,17 @@ static bool volkswagen_mlb_tx_hook(const CANPacket_t *msg) {
}
}
// Safety check for ACC_01 acceleration request
// Signal: ACC_01.ACC_Sollbeschleunigung (acceleration in m/s^2, scale 0.005, offset -7.22)
// To avoid floating point math, scale upward and compare to pre-scaled safety m/s^2 boundaries
if (msg->addr == MSG_ACC_01) {
int desired_accel = ((((msg->data[4] & 0x07U) << 8) | msg->data[3]) * 5U) - 7220U;
if (volkswagen_iq_long_accel_check(desired_accel)) {
tx = false;
}
}
// FORCE CANCEL: ensuring that only the cancel button press is sent when controls are off.
// This avoids unintended engagements while still allowing resume spam
if ((msg->addr == MSG_LS_01) && !controls_allowed) {
+4 -4
View File
@@ -926,12 +926,12 @@ class SafetyTest(SafetyTestBase):
if attr.startswith('TestSubaru') and current_test == 'TestVolkswagenMqbLongSafety':
tx = list(filter(lambda m: m[0] not in [0x122, ], tx))
# Volkswagen MQB and Honda Nidec ACC HUD messages overlap
if attr == 'TestVolkswagenMqbLongSafety' and current_test.startswith('TestHondaNidec'):
# Volkswagen MQB/MLB and Honda Nidec ACC HUD messages overlap
if attr in ('TestVolkswagenMqbLongSafety', 'TestVolkswagenMlbLongSafety') and current_test.startswith('TestHondaNidec'):
tx = list(filter(lambda m: m[0] not in [0x30c, ], tx))
# Volkswagen MQB and Honda Bosch Radarless ACC HUD messages overlap
if attr == 'TestVolkswagenMqbLongSafety' and current_test.startswith('TestHondaBoschRadarless'):
# Volkswagen MQB/MLB and Honda Bosch Radarless ACC HUD messages overlap
if attr in ('TestVolkswagenMqbLongSafety', 'TestVolkswagenMlbLongSafety') and current_test.startswith('TestHondaBoschRadarless'):
tx = list(filter(lambda m: m[0] not in [0x30c, ], tx))
# TODO: Temporary, should be fixed in panda firmware, safety_honda.h
@@ -1,17 +1,24 @@
#!/usr/bin/env python3
import unittest
import numpy as np
from iqdbc.car.structs import CarParams
from iqdbc.safety.tests.libsafety import libsafety_py
import iqdbc.safety.tests.common as common
from iqdbc.safety.tests.common import CANPackerSafety
from iqdbc.car.volkswagen.values import VolkswagenSafetyFlags
MAX_ACCEL = 2.0
MIN_ACCEL = -3.5
MSG_LH_EPS_03 = 0x9F # RX from EPS, for driver steering torque
MSG_ACC_01 = 0x109 # TX by OP, ACC acceleration request to the drivetrain coordinator
MSG_ESP_03 = 0x103 # RX from ABS, for wheel speeds
MSG_MOTOR_03 = 0x105 # RX from ECU, for driver throttle input and driver brake input
MSG_ESP_05 = 0x106 # RX from ABS, for brake light state
MSG_LS_01 = 0x10B # TX by OP, ACC control buttons for cancel/resume
MSG_TSK_02 = 0x10C # RX from ECU, for ACC status from drivetrain coordinator
MSG_HCA_01 = 0x126 # TX by OP, Heading Control Assist steering torque
MSG_ACC_02 = 0x30C # TX by OP, ACC HUD data to the instrument cluster
MSG_LDW_02 = 0x397 # TX by OP, Lane line recognition and text alerts
@@ -72,10 +79,16 @@ class TestVolkswagenMlbSafetyBase(common.CarSafetyTest, common.DriverTorqueSteer
return self.packer.make_can_msg_safety("HCA_01", 0, values)
# Cruise control buttons
def _ls_01_msg(self, cancel=0, resume=0, _set=0, bus=2):
values = {"LS_Abbrechen": cancel, "LS_Tip_Setzen": _set, "LS_Tip_Wiederaufnahme": resume}
def _ls_01_msg(self, cancel=0, resume=0, _set=0, main_switch=1, bus=2):
values = {"LS_Abbrechen": cancel, "LS_Tip_Setzen": _set, "LS_Tip_Wiederaufnahme": resume,
"LS_Hauptschalter": main_switch}
return self.packer.make_can_msg_safety("LS_01", bus, values)
# Acceleration request to drivetrain coordinator
def _acc_01_msg(self, accel):
values = {"ACC_Sollbeschleunigung": accel}
return self.packer.make_can_msg_safety("ACC_01", 0, values)
# Verify brake_pressed is true if either the switch or pressure threshold signals are true
def test_redundant_brake_signals(self):
test_combinations = [(True, True, True), (True, True, False), (True, False, True), (False, False, False)]
@@ -137,5 +150,63 @@ class TestVolkswagenMlbStockSafety(TestVolkswagenMlbSafetyBase):
self.assertFalse(self.safety.get_controls_allowed(), "controls allowed after cancel")
class TestVolkswagenMlbLongSafety(TestVolkswagenMlbSafetyBase):
TX_MSGS = [[MSG_HCA_01, 0], [MSG_LDW_02, 0], [MSG_ACC_01, 0], [MSG_ACC_02, 0]]
FWD_BLACKLISTED_ADDRS = {2: [MSG_HCA_01, MSG_LDW_02, MSG_ACC_01, MSG_ACC_02]}
FWD_BUS_LOOKUP = {0: 2, 2: 0}
RELAY_MALFUNCTION_ADDRS = {0: (MSG_HCA_01, MSG_LDW_02, MSG_ACC_01, MSG_ACC_02)}
INACTIVE_ACCEL = 3.01
def setUp(self):
self.packer = CANPackerSafety("vw_mlb")
self.safety = libsafety_py.libsafety
safety_param = VolkswagenSafetyFlags.LONG_CONTROL | VolkswagenSafetyFlags.ALLOW_LONG_ACCEL_WITH_GAS_PRESSED
self.safety.set_safety_hooks(CarParams.SafetyModel.volkswagenMlb, safety_param)
self.safety.init_tests()
# stock cruise controls are entirely bypassed under openpilot longitudinal control
def test_disable_control_allowed_from_cruise(self):
pass
def test_enable_control_allowed_from_cruise(self):
pass
def test_cruise_engaged_prev(self):
pass
def test_set_and_resume_buttons(self):
for button in ["set", "resume"]:
# ACC main switch must be on, engage on falling edge
self.safety.set_controls_allowed(0)
self._rx(self._ls_01_msg(_set=(button == "set"), resume=(button == "resume"), main_switch=0, bus=0))
self.assertFalse(self.safety.get_controls_allowed(), f"controls allowed on {button} with main switch off")
self._rx(self._ls_01_msg(main_switch=0, bus=0))
self._rx(self._ls_01_msg(_set=(button == "set"), resume=(button == "resume"), bus=0))
self.assertFalse(self.safety.get_controls_allowed(), f"controls allowed on {button} rising edge")
self._rx(self._ls_01_msg(bus=0))
self.assertTrue(self.safety.get_controls_allowed(), f"controls not allowed on {button} falling edge")
def test_main_switch(self):
# Disable as soon as the ACC main switch turns off
self._rx(self._ls_01_msg(bus=0))
self.safety.set_controls_allowed(1)
self._rx(self._ls_01_msg(main_switch=0, bus=0))
self.assertFalse(self.safety.get_controls_allowed(), "controls allowed after ACC main switch off")
def test_accel_safety_check(self):
for controls_allowed in [True, False]:
for accel in np.concatenate((np.arange(MIN_ACCEL - 2, MAX_ACCEL + 2, 0.03), [0, self.INACTIVE_ACCEL])):
accel = round(accel, 2)
is_inactive_accel = accel == self.INACTIVE_ACCEL
send = (controls_allowed and MIN_ACCEL <= accel <= MAX_ACCEL) or is_inactive_accel
self.safety.set_controls_allowed(controls_allowed)
self.assertEqual(send, self._tx(self._acc_01_msg(accel)), (controls_allowed, accel))
def test_accel_allowed_with_gas_pressed(self):
self._rx(self._user_gas_msg(1))
self.safety.set_controls_allowed(True)
self.assertTrue(self._tx(self._acc_01_msg(0.5)))
if __name__ == "__main__":
unittest.main()
+4 -10
View File
@@ -121,19 +121,13 @@ def _install_signal_handlers() -> None:
signal.signal(signal.SIGTERM, _handle_shutdown_signal)
class _QuietSpinner:
def update(self, *args, **kwargs) -> None:
pass
def close(self, *args, **kwargs) -> None:
pass
def ensure_vendor_runtime() -> None:
# verify-only: a hash-mismatched binary is quarantined, never replaced from
# the network — the updater restores the checked-in one
try:
VendorMapdInstaller(_QuietSpinner()).check_and_download()
VendorMapdInstaller().verify()
except Exception:
cloudlog.exception("iq_maps: vendor runtime install/download failed")
cloudlog.exception("iq_maps: vendor runtime verification failed")
params = Params()
mem_params = Params("/dev/shm/params") if platform.system() != "Darwin" else params
+4 -2
View File
@@ -2,8 +2,10 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
Maintainer utility: pin a new pfeiferj/mapd release tag and refresh the checked-in
binary hash. Not used at runtime.
Maintainer utility: pin a new mapd release tag and refresh the checked-in binary
hash. Not used at runtime. Binaries come from the gitlvb teal/mapd CI (built
against teal/gomsgq) drop the artifact at third_party/mapd_pfeiferj/mapd, then
run this so the hash pin moves in the same commit.
"""
import argparse
import os
+59 -127
View File
@@ -2,36 +2,30 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
Provisions the `mapd` routing binary authored by Jacob Pfeifer (github.com/pfeiferj/mapd).
The binary itself is his work; this module only fetches, verifies and stages it on-device.
Verifies the vendored `mapd` routing binary authored by Jacob Pfeifer
(github.com/pfeiferj/mapd), built from the gitlvb teal/mapd fork against
teal/gomsgq. The only accepted binary is the checked-in one matching the pinned
hash; nothing is ever downloaded at runtime. Jacob's stock release build embeds
a 15-reader msgq header layout on this fork (NUM_READERS=32) its registration
writes land inside other processes' reader slots, so a wrong binary is
quarantined rather than left where manager could start it.
"""
import hashlib
import logging
import os
import stat
import time
from pathlib import Path
import sys
import requests
from cereal import messaging
from openpilot.common.basedir import BASEDIR
from openpilot.common.params import Params
from openpilot.common.spinner import Spinner
from openpilot.system.hardware.hw import Paths
from openpilot.system.version import is_prebuilt
from openpilot.iqpilot.iq_maps import VENDOR_MAPD_BIN_DIR, VENDOR_MAPD_PATH
from openpilot.common.swaglog import cloudlog
from openpilot.iqpilot.iq_maps import VENDOR_MAPD_PATH
import openpilot.system.sentry as sentry
VENDOR_RELEASE_TAG = "v2.0.6"
VENDOR_RELEASE_URL = f"https://github.com/pfeiferj/mapd/releases/download/{VENDOR_RELEASE_TAG}/mapd"
VENDOR_RELEASE_TAG = "v2.0.6-iq1"
_VERSION_PARAM = "MapdVersion"
_HASH_FILE = os.path.join(BASEDIR, "iqpilot", "iq_maps", "tests", "mapd_hash")
_HTTP_TIMEOUT_S = 60
_FETCH_ATTEMPTS = 5
_NET_PROBE_ATTEMPTS = 10
_NET_PROBE_INTERVAL_S = 2
QUARANTINE_PATH = VENDOR_MAPD_PATH + ".quarantined"
def sha256_of_file(path: str) -> str:
@@ -48,45 +42,58 @@ def stamp_vendor_version(version: str, params: Params | None = None) -> None:
class VendorMapdInstaller:
def __init__(self, spinner_ref: Spinner):
def __init__(self, spinner_ref: Spinner | None = None, params: Params | None = None):
self._spinner = spinner_ref
self._params = Params()
self._params = params if params is not None else Params()
# --- externally consumed surface -----------------------------------------
def get_installed_version(self) -> str:
return str(self._params.get(_VERSION_PARAM) or "")
@staticmethod
def ensure_directories_exist() -> None:
for directory in (Paths.mapd_root(), VENDOR_MAPD_BIN_DIR):
os.makedirs(directory, exist_ok=True)
def verify(self) -> bool:
"""True iff the on-disk binary matches the pinned hash; quarantines a wrong one."""
expected = self._expected_hash()
if not expected:
cloudlog.error("iq_maps: pinned mapd hash missing, vendor binary cannot be verified")
return False
def check_and_download(self) -> None:
if not self._binary_up_to_date():
self._provision()
def non_prebuilt_install(self) -> None:
if self._on_metered_link():
self._say("Metered connection detected — offline maps engine will not download here.")
time.sleep(5)
return
if not os.path.isfile(VENDOR_MAPD_PATH):
# the binary is a tracked file: the updater/bundle restores it
self._say("Offline maps engine missing; it will be restored by the next update.")
self._params.remove(_VERSION_PARAM)
return False
try:
self.ensure_directories_exist()
if self._binary_up_to_date():
self._say("Offline maps engine already present and current.")
time.sleep(0.1)
return
current = sha256_of_file(VENDOR_MAPD_PATH)
except OSError:
cloudlog.exception("iq_maps: vendor mapd unreadable")
return False
if self._block_until_online():
self._say(f"Retrieving offline maps engine [{self.get_installed_version() or 'none'}] -> [{VENDOR_RELEASE_TAG}]")
time.sleep(0.1)
self._provision()
self._spinner.close()
except Exception as exc: # noqa: BLE001
self._announce_failure(exc)
if current == expected:
stamp_vendor_version(VENDOR_RELEASE_TAG, self._params)
try:
os.remove(QUARANTINE_PATH)
except OSError:
pass
self._say(f"Offline maps engine verified [{VENDOR_RELEASE_TAG}]")
return True
# a foreign binary — e.g. a stock release download from the retired fetch
# path — must never run: quarantine it where manager can't start it
cloudlog.error(f"iq_maps: vendor mapd hash {current[:12]} != pinned {expected[:12]}, quarantining")
self._say("Offline maps engine failed verification; quarantined until the next update.")
try:
os.replace(VENDOR_MAPD_PATH, QUARANTINE_PATH)
except OSError:
cloudlog.exception("iq_maps: vendor mapd quarantine failed")
return False
self._params.remove(_VERSION_PARAM)
try:
raise RuntimeError(f"vendor mapd hash mismatch quarantined: {current}")
except RuntimeError as exc:
sentry.init(sentry.SentryProject.SELFDRIVE)
sentry.capture_exception(exc)
return False
# --- internal ------------------------------------------------------------
def _expected_hash(self) -> str:
try:
with open(_HASH_FILE) as f:
@@ -94,88 +101,13 @@ class VendorMapdInstaller:
except OSError:
return ""
def _binary_up_to_date(self) -> bool:
if not os.path.exists(VENDOR_MAPD_PATH):
return False
if self.get_installed_version() != VENDOR_RELEASE_TAG:
return False
reference = self._expected_hash()
if not reference:
return True
try:
return sha256_of_file(VENDOR_MAPD_PATH) == reference
except OSError:
return False
def _provision(self) -> None:
self.ensure_directories_exist()
if self._retrieve_binary():
stamp_vendor_version(VENDOR_RELEASE_TAG, self._params)
def _retrieve_binary(self) -> bool:
staging = Path(f"{VENDOR_MAPD_PATH}.part")
last_error: Exception | None = None
for attempt in range(1, _FETCH_ATTEMPTS + 1):
try:
with requests.get(VENDOR_RELEASE_URL, stream=True, timeout=_HTTP_TIMEOUT_S) as resp:
resp.raise_for_status()
with open(staging, "wb") as out:
for chunk in resp.iter_content(chunk_size=1 << 16):
out.write(chunk)
out.flush()
os.fsync(out.fileno())
os.chmod(staging, os.lstat(staging).st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
staging.replace(VENDOR_MAPD_PATH)
return True
except requests.exceptions.RequestException as exc:
last_error = exc
self._say(f"offline maps fetch attempt {attempt}/{_FETCH_ATTEMPTS} did not complete ({exc})")
time.sleep(0.5)
staging.unlink(missing_ok=True)
logging.error("offline maps engine could not be fetched after %d attempts: %s", _FETCH_ATTEMPTS, last_error)
return False
def _on_metered_link(self) -> bool:
sm = messaging.SubMaster(["deviceState"])
return bool(sm["deviceState"].networkMetered)
def _block_until_online(self) -> bool:
for i in range(1, _NET_PROBE_ATTEMPTS + 1):
self._say(f"Waiting for a usable network connection... [{i}/{_NET_PROBE_ATTEMPTS}]")
if self._link_reachable():
return True
time.sleep(_NET_PROBE_INTERVAL_S)
return False
@staticmethod
def _link_reachable() -> bool:
try:
requests.head(VENDOR_RELEASE_URL, timeout=10, allow_redirects=True)
return True
except requests.exceptions.RequestException as exc:
logging.debug("network probe failed: %s", exc)
return False
def _announce_failure(self, exc: Exception) -> None:
for remaining in range(5, 0, -1):
self._say(f"Offline maps engine unavailable; navigation stays online-only. Boot continues in {remaining}s...")
time.sleep(1)
logging.exception("vendor mapd install failed")
sentry.init(sentry.SentryProject.SELFDRIVE)
sentry.capture_exception(exc)
def _say(self, text: str) -> None:
self._spinner.update(text)
if self._spinner is not None:
self._spinner.update(text)
if __name__ == "__main__":
spinner = Spinner()
installer = VendorMapdInstaller(spinner)
installer.ensure_directories_exist()
if is_prebuilt():
spinner.update(f"[DEBUG] Prebuilt build; vendor mapd install skipped. "
f"target [{VENDOR_RELEASE_TAG}], param [{installer.get_installed_version()}]")
stamp_vendor_version(VENDOR_RELEASE_TAG)
else:
spinner.update(f"Verifying vendor mapd install. prebuilt [{is_prebuilt()}]")
installer.non_prebuilt_install()
ok = VendorMapdInstaller(spinner).verify()
spinner.close()
sys.exit(0 if ok else 1)
+1 -1
View File
@@ -4,6 +4,6 @@
"dmonitoring_model_metadata.pkl": "31a86ab7a92dc0af088b15787a440dd3b210aa662e445a15145900e559a1b5c3",
"dmonitoring_model_tinygrad.pkl": "806c0ea75df6bf6dfeb81b832314c68e31df5865a52d0359e6eeb76d93ad2b52"
},
"signature": "e1eeb5ce45774a816c8da2394e6ee35ebf700b71dff345e0141dbab8ff592349"
"signature": "64740782bfd5b1720978aab24a2b1b37c99542f97db3c8637227c7412bb30bbf"
}
}
+4 -2
View File
@@ -29,10 +29,12 @@ def _file_sha256(path: Path) -> str:
@functools.lru_cache(maxsize=1)
def _tinygrad_digest() -> str:
h = hashlib.sha256()
# mirror the SConscript glob: no hidden files/dirs (also excludes .git, which differs per clone), no pycache
# mirror the SConscript glob: no hidden files/dirs (also excludes .git, which differs per clone), no pycache.
# 'weights' holds untracked/gitignored model weights (e.g. iqvd yolov8n .safetensors) present on dev machines
# but absent from a clean CI/device clone — hashing them makes the signature unreproducible (false STALE).
def _included(p: Path) -> bool:
rel = p.relative_to(TINYGRAD_DIR).parts
return p.is_file() and '__pycache__' not in rel and not any(part.startswith('.') for part in rel)
return p.is_file() and '__pycache__' not in rel and 'weights' not in rel and not any(part.startswith('.') for part in rel)
files = sorted(p for p in TINYGRAD_DIR.rglob('*') if _included(p))
for p in files:
h.update(str(p.relative_to(BASEDIR)).encode())
+5 -1
View File
@@ -6,7 +6,11 @@ class FanController:
def __init__(self) -> None:
self.last_ignition = False
def update(self, cur_temp: float, ignition: bool) -> int:
def update(self, cur_temp: float, ignition: bool, max_cool: bool = False) -> int:
if max_cool:
self.last_ignition = ignition
return 100
if cur_temp < 70.0:
fan_pwr_out = 0
elif cur_temp > 85.0:
+4 -2
View File
@@ -432,8 +432,6 @@ def hardware_thread(end_event, hw_queue) -> None:
all_comp_temp = all_temp_filter.update(max(temp_sources))
msg.deviceState.maxTempC = all_comp_temp
msg.deviceState.fanSpeedPercentDesired = fan_controller.update(all_comp_temp, onroad_conditions["ignition"])
is_offroad_for_5_min = (started_ts is None) and ((not started_seen) or (off_ts is None) or (time.monotonic() - off_ts > 60 * 5))
if is_offroad_for_5_min and offroad_comp_temp > OFFROAD_DANGER_TEMP:
# if device is offroad and already hot without the extra onroad load,
@@ -447,6 +445,10 @@ def hardware_thread(end_event, hw_queue) -> None:
elif current_band.max_temp is not None and all_comp_temp > current_band.max_temp:
thermal_status = list(THERMAL_BANDS.keys())[band_idx + 1]
# the car is running but temperature is blocking the start, so cool as fast as we can
max_cool = (started_ts is None) and onroad_conditions["ignition"] and thermal_status >= ThermalStatus.red
msg.deviceState.fanSpeedPercentDesired = fan_controller.update(all_comp_temp, onroad_conditions["ignition"], max_cool)
# **** starting logic ****
startup_conditions["up_to_date"] = True
@@ -41,6 +41,13 @@ class TestFanController:
self.wind_up(controller, True)
assert controller.update(100, True) == 100
@pytest.mark.parametrize("controller_class", ALL_CONTROLLERS)
def test_max_cool(self, mocker, controller_class):
controller = patched_controller(mocker, controller_class)
self.wind_down(controller)
assert controller.update(80, True, True) == 100
assert controller.update(80, False, True) == 100
@pytest.mark.parametrize("controller_class", ALL_CONTROLLERS)
def test_windup_speed(self, mocker, controller_class):
controller = patched_controller(mocker, controller_class)
+7 -2
View File
@@ -85,8 +85,13 @@ def affine_irq(val, action):
@lru_cache
def get_device_type():
# lru_cache and cache can cause memory leaks when used in classes
with open("/sys/firmware/devicetree/base/model") as f:
model = f.read().strip('\x00')
try:
with open("/sys/firmware/devicetree/base/model") as f:
model = f.read().strip('\x00')
except FileNotFoundError:
# off-device (e.g. the prebuilt build container fakes /TICI but has no
# devicetree); import must not crash. Not a real device type.
return "unknown"
return model.split('comma ')[-1]
class Tici(HardwareBase):
BIN
View File
Binary file not shown.