mirror of
https://gitlvb.teallvbs.xyz/IQ.Lvbs/IQ.Pilot.git
synced 2026-07-24 13:02:07 +08:00
IQ.Pilot Release Commit @ b581b58
This commit is contained in:
@@ -16,18 +16,28 @@
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/alc.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "b7a1d9c89f0fb20719ed03104c150361ead436f4eaf758213c34270f857fce29",
|
||||
"sha256": "77a601a12a498f09f01c4b1618e164638d5d9702913b6d5bb30a3c729a1c7d54",
|
||||
"size": 401688
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/vehicle_state.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "ca91f99d94c8bb7842332a69896d4b3a31c109c027426d1d7386876f11710d80",
|
||||
"size": 69696
|
||||
},
|
||||
"runtime": {
|
||||
"entries": {
|
||||
"iqpilot_private.konn3kt.iqlvbs.alc": {
|
||||
"path": "python/iqpilot_private/konn3kt/iqlvbs/alc.cpython-312-aarch64-linux-gnu.so",
|
||||
"type": "python-module"
|
||||
},
|
||||
"iqpilot_private.konn3kt.iqlvbs.vehicle_state": {
|
||||
"path": "python/iqpilot_private/konn3kt/iqlvbs/vehicle_state.cpython-312-aarch64-linux-gnu.so",
|
||||
"type": "python-module"
|
||||
}
|
||||
}
|
||||
},
|
||||
"signatures": {
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/alc.cpython-312-aarch64-linux-gnu.so": "3aPgCbOFw97bTasyTd2NnljzjuHrF9qEzuZX1X2Vu1Nu0dz+btrOzgiwV7lekZ6SyJbCpIUYeI+5ifNW2MzaBQ=="
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/alc.cpython-312-aarch64-linux-gnu.so": "4KY001fMJhdkiQNoUXbvtOKQ2nWocmg9ZL0umWnDjAztueIstXBoc1iqW83plm2Xq0jR9NLk1Jd4yl3AydWFBA==",
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/vehicle_state.cpython-312-aarch64-linux-gnu.so": "JqSaxsDJT9q0UYgVJUo9Pqm0J0Aqwy5gIa2C8n9/ioOg/fV6PLn2KiVGn6470U4F5oNaaOgAmm+AM9jwYrZXAA=="
|
||||
}
|
||||
}
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -16,7 +16,7 @@
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/iqlvbs_commander.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "f452c3278cd5f8cc40db981cae2bd91f4796a91abaa76b6001dbb5dad80480d6",
|
||||
"sha256": "384571df8380e5eef92806f3fdb6c9d1bc879af2ebdce9259bcfc486d506a4d0",
|
||||
"size": 68080
|
||||
},
|
||||
"runtime": {
|
||||
@@ -28,6 +28,6 @@
|
||||
}
|
||||
},
|
||||
"signatures": {
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/iqlvbs_commander.cpython-312-aarch64-linux-gnu.so": "7DvAdsDSBnDIh3f7PqVWudkB+Njn6o7HAvtiZPrWpO0GW40B/DXhRLDvJ9rT+O2Lw3pLJBq04qA1szhbcFBhCw=="
|
||||
"python/iqpilot_private/konn3kt/iqlvbs/iqlvbs_commander.cpython-312-aarch64-linux-gnu.so": "cH88ob+s+ZRJaNgbrRN2CQqCiQMBlo9yXdBvN3gteSC7OYlJ5z8OZND7eZSEfeeq2O7E8ZeZDs9WDU0WfP8DCw=="
|
||||
}
|
||||
}
|
||||
|
||||
BIN
Binary file not shown.
@@ -16,27 +16,27 @@
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "ec590435888e03a83c9fbfb01102089b077de0840ae0bb2e0969e76213d633aa",
|
||||
"sha256": "70cbd719ded42c8fd7c841864ab88c334a2155be4a57c36df240233022a5e8d1",
|
||||
"size": 135536
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "7188e3de16f358a1dfb7130cf8aa7f12d2861bd68f056bff9a805c14883f3016",
|
||||
"sha256": "b6a02ca7f2adb8788c960e931b97f9b9f40164944ad9d2a7824689beaabc53b9",
|
||||
"size": 67664
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "7218ad7ac087c68fe7d466e4c3468a6ab3b48c0fe45711e546e53823039c365b",
|
||||
"sha256": "95187b8c5f81707a7fabbd9d1d8e281405ff382260ed43bef510c0089af95d13",
|
||||
"size": 204624
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "56d60b113a982e2d4fee8b4f00eaf111fd09834fbe8bf95f382b49e0bf13c121",
|
||||
"sha256": "cd215251153edb32ff7a2d417ccc3e2921f3e669e98fa508cecb169b21e0bf4a",
|
||||
"size": 69752
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "75f101e930d93044d2e074129207c8246ff7d94df77b0f83db7de665eef62ab6",
|
||||
"sha256": "49736fa1e12f39114a40814f142750312ac5544416bbccc6014f1337c19dc606",
|
||||
"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": "acc64ce2fe59583738ab5951f64e79d8043856317eb015dc1d0e6a4bffc51ee2",
|
||||
"sha256": "8c1a71f4be436f09054bda32748c4eb094bf0e26832147d7e28ca19ce91e805f",
|
||||
"size": 2100238
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "ee2330e3ba4f488336d18d887fc19291f76a1733a24c203a642634b7106a85a1",
|
||||
"sha256": "0109732b5e45e846531048a649e4cd188d394aa5e64df3b36b6f4f26542dc155",
|
||||
"size": 268064
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "71568e01b8c983ca80d825bea610334b140c87da9e6ac3047b21d9c56c136423",
|
||||
"sha256": "237166f1c645447f1467f7081bc71dedb7d090076ad135f83dc189cd3a904802",
|
||||
"size": 340584
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "7f47eb50931e9df19116736ef6564b2d5480a7424c24cd1d599424dc0da66537",
|
||||
"sha256": "4f493569b38e1e50e2fa6d752a30d495cb3fdf572daa94452e72db067674bc0f",
|
||||
"size": 68048
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "e4c0882530ab3097ecadbb586ac7e35955b587f81d9af2c57fea1b5450c2e5ef",
|
||||
"sha256": "bf42ea50717c7bac73bec9fd48874f43d963459f1a91cf9c92596018fbe4cd62",
|
||||
"size": 335728
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "62bbf38d79bece455bdb399d7124b37347c9ec2ebdf35ff2ce4b696b39c59462",
|
||||
"sha256": "11cc3a7a1c21f40a0b6719ec1b97776ab786a5c75f31b43af173bc4452697ca7",
|
||||
"size": 271680
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "b59b5d1bc50e5064206752cb30da118f2fa42f48c4cc2e6529ebbe04b28200a4",
|
||||
"sha256": "5098e97f036dffb92eca2fce847fcbe9bc13f9277a2ae39b42300cfe56e133df",
|
||||
"size": 134408
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "1d7b19f9d33649e91e5707574bdf436bc0e5b6dafd63d4b1aa63949bb6f7be20",
|
||||
"size": 3448272
|
||||
"sha256": "17605aaedb7b4324a4c2ea64c15c6a6f305f8d455060c7a280e2db228307a9e7",
|
||||
"size": 3513840
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "8a5e6e08eb15a8295f08bd4629f80f6bf2539ec7eea7b6a787af3ed5b2546e35",
|
||||
"sha256": "45022394525e297bff8af3f17710bfe31f63c3526985211e4eb8924490f54600",
|
||||
"size": 136448
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "ead654070e296ae23fd8afdbc0a1c2f3eb8d1ff04a905ca3f2fbd8e20316ed6b",
|
||||
"sha256": "f35fe3724a5a8f823b2ad42efc3a7bbeeba6d7f7fd61eda76596a296df51ca5a",
|
||||
"size": 68136
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "38c55fe55500aca574ab5bf3ed693e54ca192db276c247a31209470319d6578a",
|
||||
"sha256": "af53a0e6fef1bbb63cbdae857aeb7b2b4c93cfc290b3e27211a5df60af462a9d",
|
||||
"size": 67840
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "0547db3c95f399b9721ae4f7306b57d4124283adda0213f7df5069a3837a7f98",
|
||||
"sha256": "83f5129c7a2337e63ac79e4fd4cd430e96f9570bca6b5e6e3bc5224815030913",
|
||||
"size": 135648
|
||||
},
|
||||
"python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so": {
|
||||
"mode": 493,
|
||||
"sha256": "f7788e2023012537b40d6aa5109e9d913b7cb27e1de80eadc0ebe12a2ab7be1a",
|
||||
"sha256": "afb1b9cd772fe31c6845af195f6c62ef89aeef028cebc9ea7e25187ac108f90f",
|
||||
"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": "efbef0e4b63a65d846c4cd50f89cb3fdfe0d12da3301e8b1c9137f9a5f02c753",
|
||||
"sha256": "4c4589a6419e9501ec5a86385a6991a54a72b290e9de855e5aa303c2fac59cb0",
|
||||
"size": 204184
|
||||
},
|
||||
"runtime": {
|
||||
@@ -148,23 +148,23 @@
|
||||
}
|
||||
},
|
||||
"signatures": {
|
||||
"python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so": "tMSz9Dm9XQQkQzePUaDhhcM065JH2fcqAE3f+dlA2/+264m/j2ayWMYFMXTWZMTDm1YaQT8e9lvBe8sc4JSVDQ==",
|
||||
"python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so": "fvD5Ii/rNZuynr8Nh+K+yNC+AMji7v53spO7rj7Fs61CvO604fWnKVUO7A/2d7KHh26YpUcjbv8wRb8tRTzfCg==",
|
||||
"python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so": "KcxQfc5HVD8QOLY/KHWsrhWpbYETAxsxR9WjFOqqmYe0aEC7K4njmJPtU1eCU3B2S6MGMmUdABBHs8kr32ViDQ==",
|
||||
"python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so": "9jTowLTfwEw9Iu3wgfFordJmJ+/+O+nPvq4TP+3CDddW1jISzSMhiw418iyH1f0m7rwB3hGyZYgGLoJszSHpBw==",
|
||||
"python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so": "YvM513CnlMKSrIrCgrCNG/k7XyFjSlnEupgWH0Jhj0zKrE8dkeCiXek7iU9W+VpgXa6O8P3jTJUWchqLhnONBw==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so": "bhNLMkcIgi0F/CZsEDHRQsNHyPBD+pVh3DPowBz7mRYxQffVGzk1FeE2Gp3P7xxHsnyKsy635sAkdwKOlZLtBQ==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so": "Huy5oGlX55p5bhoMQipY9/doTBBAfwnQhgPdM6aeYTrzBS/QOUqwjyk3qjanftHA4m0V4Jab8cVvjEt1OiTsBw==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so": "2BmMUg8uOE4eoIW/OTbuwrZCMA+Rx4SOZWLBYs4GUbD8JR5Ei0nQ6VKLar31Ue7NYk7qBfpgqFdGPnV1uST/Dw==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so": "6nFN6dJAmGczneUwRtJr+1TLNrD9reuMQcoa2G2j0np9xaSU401MdBssdVFSFBpse95iqQX1uV8ojQD327z1CA==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so": "8nKxC5LPkwPihlIdJzcD6OTp42avONqDkNgZrmTaQr8oueczFwXnHsgJ9aZ8jrpDK/nN+GLJrniSdFxZjrUUDA==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so": "y8dA+6ahkX+Evzn8oSQEPyDB6+d+t//v5rsEdg4zRbjdeLeXs5kqraMEaAALVH80CvNJ6Gba1CcO1ebrK00EBQ==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so": "jczf5QX+Xm0tOLPBrmvJoPZmcKar5zTrxoX7RAOR1JQgHu3jWPFW+sWOTK8c8ByiVF5PdLeYOPdQgu+0KQvdCg==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so": "s4HcwSXfBowW/vfY5M4GKg7gEueRJnbmq6zO1dAXx6HrTXYsL9iDZTeGHi7dNu/rw8mUFSkkpWsaFTlaYdK0DA==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so": "LVgImFZgV/hgoBwMfMVWSEKuXUvc2jR/EPl6SOfmMncoyuIZUkpQa18jjdMTWqXbRGpFvAe+0KocmroFTrbqDg==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so": "vXffOAHGUAdEkv321fidnhZvUMaX73l2kO5/Y5Sk43+mr9V95Wcv4TR54/2Y2N4UfgtxnGFz8N0llK/DsQLEAw==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so": "wXVM74ZUEwSVnM7cMqzXQYCWhQwVovszTjxYyMhDFjwZlWtNPPGeq4WghHoghGolGSG9Q4SOLxh8uF67BU2RDw==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so": "1cBBo9W9EBxW7XF9o2MimKA9Xm26zaCEsUNHLF81zm2zWxkoSkeVlLyrxHE9ZxGhgMRMfW3lz4XUJbWRJpjGDA==",
|
||||
"python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so": "vqZyPMmER7bN7AvE4gwZVF4HypLwTxBfk4tidjRhVDZ2eKYbbG2yROd2z2xtk5Shf8GhdLsT7UhVrN+BKNnkBA=="
|
||||
"python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so": "fHETfdkKuvKTn8rv9E8G6c7xzCNGE2z4BV9YqbGN4Al5F+knIeiSh2EzKkjr8TVLMHmF1BpbYqO/Hk0Le9eqBw==",
|
||||
"python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so": "oXxKlxWYX8r6eFPfFWTUgUgykuIv4Fbn4LGdLzRQcO8gBNm6ZvF1+z5vlZ3A1eX/vdutp3nilP6PVz83kE+XDg==",
|
||||
"python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so": "A2qyZYHlLEheJ7MKAWJ/t435DBRud3DDWXZZIAnS0KQthX2hSjxeYPPToQAaBOVso2yGj+02Jr6d5XjAjfGlDQ==",
|
||||
"python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so": "yq0n30lKaAYI3uwYthCUY5w+DU52v80vQQdzdJ3HU/H4Yx//us+qoulgO4y5Lh6wIkcGyVxZM8qALf6tv/uICw==",
|
||||
"python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so": "dc9Uj1Mtzs/JqAhXrRypKVXcOeDz+LhQkoC9i480cm9xTD4CwHi0uMb0R0ug3Zy/a/T6kEb1dfeLaRu8bifsAQ==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so": "f8rBsEG6oV0FWBwF1UN/wNZstXb+I1RHgznD+IuFXdsSKD1ucPSIfu+BYzxDi9/DpPfxRXVoHS4cOgN1CadmBw==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so": "YFxsXCJUOlnws+cDf5MO8mkKSiOo27xUqo29lwZBP8y2+BPiiknCShaI4hC+ejzWd4+59smPaKUuUsXcdmPABQ==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so": "aC/O3UeBljXJ6QGSvJBULyPhSUmMOp6Y7pGtfXA1Nf5tw8qEAb/7kjiU6my5+f9w48fNAe1voSF1mO5eLCsLCg==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so": "lubN92tDcIPYnpq7LLPsgqxq5qj715kBljkie2yURge7SGluI6bWyO616OIVHjdG0Wvq58/EsmvH2qKH6EbKAg==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so": "51hAcDuyXxQcnPQUQV58KcRnIggvBJSVyRA/EzO22WgX1kLXCkhGsYbJ9lMHZH3IVUXzOpP16qEoxcdykyK/Bw==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so": "ExuQziX7rIwMiZGQjFTnr7Rw+LA4iluxeRPZ7zxnvdKo6qagECqmv5VdqxsevAYmH6KiwYDBH/Bjn4G4sLnQDg==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so": "T1QHRSyUFUhXl0Mw0CSrG3oIbcCuInWNdX1mMuYHKNf3O+iaAVDB7fgYB6jl9C3jzeiD2LH6jgpgvWEUqF9WAA==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so": "YlDNaD3dT6JuYRT7P3UEnha+/W13//OtYrkoGa8KwpDFhZy7FAyQkZiENHjIQi+K3K+I7qd2phlwrWcPXvaWAg==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so": "PxuLDE5We4EsluPRWPZBt2E9nBJTsEX0You50iDdWgjQp8+gJT5ZWfX3wG8cHF8JzOL4xZdg11SjdXpOKsoODg==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so": "Lsz5pL5pkh5n3aqJ+SQi4vixS2CTIG1Nou3+z8/OgnPq/8nF47NWuOgL2pT2ogeElgOqSHZgEVO4v4V/FQKHBg==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so": "hbCMagRzeN+JMb4Z/ZkiYo8WvA8ptT8r0NzwBlLRfY1LqkC1ZePGROG3Fq5RC9ylb1UotOmBcIVcOfiG3zDMCw==",
|
||||
"python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so": "zxtsmguucERIWEZXJiNU16fWzGDcbOWgsDa4oB90G1kAP73CTY9cMjchHsIkNZ+bkQNBFNSMmBsTavo6NeOTCQ==",
|
||||
"python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so": "mInwiS+voFDcEVMHBmHY4W69OQ+Vhl0N6cdmsetpX2YMS8zKfkDJIWvP7AwwX2ZFGkKJ/V8Wc2NTObJAIUqDBA=="
|
||||
}
|
||||
}
|
||||
|
||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -165,6 +165,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"IQCarParamsPersistent", {PERSISTENT, BYTES}},
|
||||
{"IQCarParamsPersistentV2", {PERSISTENT, BYTES}},
|
||||
{"CarPlatformBundle", {PERSISTENT, JSON}},
|
||||
{"Konn3ktVwOdometers", {PERSISTENT, JSON}},
|
||||
{"Konn3ktVehicleOdometers", {PERSISTENT, JSON}},
|
||||
{"ChevronInfo", {PERSISTENT, INT, "4"}},
|
||||
{"DeviceBootMode", {PERSISTENT, INT, "0"}},
|
||||
{"IQDevUIInfo", {PERSISTENT, INT, "0"}},
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
Wen
|
||||
@@ -1,3 +1,102 @@
|
||||
IQ.Lvbs License v0.1a
|
||||
|
||||
Copyright (c) 2026 IQ.Lvbs LLC, a part of Project Teal Lvbs Inc. All Rights Reserved.
|
||||
|
||||
DEFINITIONS
|
||||
|
||||
"Software" refers to IQ.Pilot, konn3kt, and all associated source code,
|
||||
documentation, and assets owned by the Copyright Holder.
|
||||
|
||||
"Open Components" refers to portions of the Software explicitly marked as
|
||||
open source.
|
||||
|
||||
"Proprietary Components" refers to all portions of the Software not made
|
||||
available to the public in source form.
|
||||
|
||||
"Copyright Holder" refers to IQ.Lvbs LLC, a part of Project Teal Lvbs Inc.
|
||||
|
||||
GRANT OF LICENSE
|
||||
|
||||
Subject to the terms of this license, you are granted a limited,
|
||||
non-exclusive, revocable license to:
|
||||
|
||||
1. View, study, and learn from the Open Components
|
||||
2. Modify the Open Components for personal, internal, or open-source public use
|
||||
3. Run the Software for personal, non-commercial purposes
|
||||
|
||||
RESTRICTIONS
|
||||
|
||||
You may NOT:
|
||||
|
||||
1. Claim ownership of any part of the Software, excluding your own
|
||||
modifications that do not incorporate Proprietary Components.
|
||||
|
||||
2. Reverse engineer, decompile, disassemble, or in any way attempt to
|
||||
circumvent the obfuscation of the Proprietary Components.
|
||||
|
||||
3. Use the Software or any derivative for commercial purposes without
|
||||
explicit written permission from the Copyright Holder.
|
||||
|
||||
4. Remove or alter any copyright notices or this license.
|
||||
|
||||
5. Sublicense, sell, or transfer rights to the Software.
|
||||
|
||||
6. Use the Software and/or its source code to compete with or create a
|
||||
substantially similar product.
|
||||
|
||||
7. Use the Software in closed source software not licensed by IQ.Lvbs LLC.
|
||||
|
||||
CONSEQUENCES OF VIOLATION
|
||||
|
||||
In the event any Restriction is violated, any product created using inspiration from, or source code from, IQ.Pilot or Konn3kt shall be subject to a licensing fee determined solely by the Copyright Holder. Additionally, the violating party hereby grants IQ.Lvbs LLC an exclusive, irrevocable, worldwide, royalty-free license to use any and all assets from the infringing product on IQ.Lvbs webpages, advertising materials, and in any other manner IQ.Lvbs sees fit.
|
||||
|
||||
OWNERSHIP
|
||||
|
||||
All rights, title, and interest in the Software remain exclusively with the
|
||||
Copyright Holder. Any modifications, improvements, or derivative works you
|
||||
create based on the Software are owned by the Copyright Holder. By
|
||||
contributing modifications, you irrevocably assign all rights to the
|
||||
Copyright Holder.
|
||||
|
||||
PROPRIETARY COMPONENTS
|
||||
|
||||
The Proprietary Components are provided in binary or obfuscated form only.
|
||||
Reverse engineering, decompilation, or disassembly of Proprietary Components
|
||||
is strictly prohibited. Violation of this provision entitles IQ.Lvbs LLC to
|
||||
pursue all available legal remedies to protect its intellectual property and
|
||||
trade secrets.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. THE COPYRIGHT
|
||||
HOLDER DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
|
||||
NON-INFRINGEMENT.
|
||||
|
||||
LIMITATION OF LIABILITY
|
||||
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES, OR
|
||||
OTHER LIABILITY ARISING FROM THE USE OF THE SOFTWARE. THE USER ACCEPTS FULL
|
||||
RESPONSIBILITY FOR ANY AND ALL LIABILITIES WHEN USING IQ.LVBS SOFTWARE.
|
||||
|
||||
TERMINATION
|
||||
|
||||
This license terminates automatically if you violate any of its terms. Upon
|
||||
termination, you must destroy all copies of the Software in your possession.
|
||||
|
||||
The Copyright Holder reserves the right to revoke this license at any time
|
||||
for any reason.
|
||||
|
||||
GOVERNING LAW
|
||||
|
||||
This license shall be governed by the laws of the State of Illinois, United
|
||||
States of America. Any disputes arising under this license shall be subject
|
||||
to the exclusive jurisdiction of the courts located in Henry County, Illinois.
|
||||
|
||||
---
|
||||
|
||||
For commercial licensing inquiries, contact: support@iqlvbs.com
|
||||
|
||||
Copyright (c) 2020, Comma.ai, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
@@ -96,3 +96,11 @@ to the exclusive jurisdiction of the courts located in Henry County, Illinois.
|
||||
---
|
||||
|
||||
For commercial licensing inquiries, contact: support@iqlvbs.com
|
||||
|
||||
Copyright (c) 2020, Comma.ai, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
include iqdbc/car/car.capnp
|
||||
include iqdbc/car/include/c++.capnp
|
||||
recursive-include iqdbc/safety *.h
|
||||
@@ -0,0 +1,100 @@
|
||||
## IQ.Pilot Car-Port Credits
|
||||
|
||||
This file is intended to track per-platform and per-tuning attribution inside the car-port-side included inside of IQ.Pilot.
|
||||
|
||||
It does not replace the repository-wide license files for IQ.Pilot itself or any other components not listed here.
|
||||
|
||||
## Credits:
|
||||
|
||||
### Hyundai / Kia / Genesis (HKG) - Sunnypilot
|
||||
|
||||
#### Contributors
|
||||
|
||||
Full credit for the Hyundai / Kia / Genesis port, along with the HKG-specific tuning work used in this tree, belongs to:
|
||||
|
||||
- Jason Wen
|
||||
- James Vecellio-Grant
|
||||
- sunnypilot
|
||||
|
||||
#### Attribution
|
||||
|
||||
This repository carries HKG-side tuning and port lineage that originated from, and/or is verbatim their work. They are the authors of the Sunnypilot-side HKG port and its tuning, and are accredited as such, IQ.Lvbs claims no copyright, credit, or authorship of the components listed below.
|
||||
|
||||
#### Upstream License Notice
|
||||
|
||||
The HKG work attributed above is acknowledged here under LICENSE notice:
|
||||
|
||||
```text
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Jason Wen, James Vecellio-Grant, Sunnypilot, and a number of other contributors.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
```
|
||||
|
||||
#### Scope
|
||||
|
||||
This licensing is limited to `iqdbc_repo/iqdbc/car/hyundai` and `iqdbc_repo/iqdbc/iqpilot/car/hyundai`.
|
||||
|
||||
### Hyundai / Kia / Genesis (HKG) - carrotpilot
|
||||
|
||||
#### Contributors
|
||||
|
||||
Full credit for the carrotpilot-side HKG tuning lineage carried in this tree belongs to:
|
||||
|
||||
- carrotpilot devs (ajoutam)
|
||||
|
||||
#### Attribution
|
||||
|
||||
This repository carries HKG-side tuning and port lineage that originated from, and/or is verbatim their work. They are the authors of the carrotpilot-side HKG tuning credited here, and are accredited as such, IQ.Lvbs claims no copyright, credit, or authorship of the components listed below.
|
||||
|
||||
#### Upstream License Notice
|
||||
|
||||
The HKG work attributed above is acknowledged here under LICENSE notice:
|
||||
|
||||
```text
|
||||
Copyright (c) 2018, Comma.ai, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
```
|
||||
|
||||
#### Scope
|
||||
|
||||
This licensing is limited to `iqdbc_repo/iqdbc/car/hyundai` and `iqdbc_repo/iqdbc/iqpilot/car/hyundai`.
|
||||
|
||||
### Honda
|
||||
|
||||
#### Contributors
|
||||
|
||||
Full credit for the Honda-specific tuning lineage carried in this tree belongs to:
|
||||
|
||||
- MVL-Boston on GitHub
|
||||
- mvl3c on Discord
|
||||
|
||||
#### Attribution
|
||||
|
||||
This repository carries Honda tuning work derived from MVL's tuning effort's, that originated from, and/or is verbatim their work, and are accredited as such, IQ.Lvbs claims no copyright, credit, or authorship of the components listed below.
|
||||
|
||||
#### Scope
|
||||
|
||||
This licensing is limited to `iqdbc_repo/iqdbc/car/honda` and `iqdbc_repo/iqdbc/iqpilot/car/honda`.
|
||||
@@ -1,441 +0,0 @@
|
||||
<!--- AUTOGENERATED FROM selfdrive/car/CARS_template.md, DO NOT EDIT. --->
|
||||
|
||||
# Support Information for 410 Known Cars
|
||||
|
||||
|Make|Model|Package|Support Level|
|
||||
|---|---|---|:---:|
|
||||
|Acura|ADX 2025-26|All|[Community](#community)|
|
||||
|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|[Upstream](#upstream)|
|
||||
|Acura|ILX 2019|All|[Upstream](#upstream)|
|
||||
|Acura|Integra 2023-25|All|[Community](#community)|
|
||||
|Acura|MDX 2015-16|Advance Package|[Community](#community)|
|
||||
|Acura|MDX 2017-20|All|[Community](#community)|
|
||||
|Acura|MDX 2022-24|All|[Community](#community)|
|
||||
|Acura|MDX 2025-26|All except Type S|[Upstream](#upstream)|
|
||||
|Acura|MDX Hybrid 2017-20|All|[Community](#community)|
|
||||
|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|[Upstream](#upstream)|
|
||||
|Acura|RDX 2019-21|All|[Upstream](#upstream)|
|
||||
|Acura|RDX 2022-25|All|[Community](#community)|
|
||||
|Acura|RLX 2017|Advance Package or Technology Package|[Community](#community)|
|
||||
|Acura|TLX 2015-17|Advance Package|[Community](#community)|
|
||||
|Acura|TLX 2018-20|All|[Community](#community)|
|
||||
|Acura|TLX 2021|All|[Upstream](#upstream)|
|
||||
|Acura|TLX 2022-23|All|[Community](#community)|
|
||||
|Acura|TLX 2025|All|[Upstream](#upstream)|
|
||||
|Acura|ZDX 2024|All|[Not compatible](#can-bus-security)|
|
||||
|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Audi|A4 2016-24|All|[Not compatible](#flexray)|
|
||||
|Audi|A5 2016-24|All|[Not compatible](#flexray)|
|
||||
|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Audi|Q3 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Audi|Q5 2017-24|All|[Not compatible](#flexray)|
|
||||
|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Cadillac|CT6 Non-ACC 2017-18|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)|
|
||||
|Cadillac|XT5 Non-ACC 2018|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)|
|
||||
|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim, without Super Cruise Package|[Upstream](#upstream)|
|
||||
|Chevrolet|Bolt EUV LT Non-ACC 2022-23|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)|
|
||||
|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|[Upstream](#upstream)|
|
||||
|Chevrolet|Bolt EV LT Non-ACC 2022-23|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)|
|
||||
|Chevrolet|Bolt EV Non-ACC 2017|No Adaptive Cruise Control (Non-ACC)|[Community](community)|
|
||||
|Chevrolet|Bolt EV Non-ACC 2018-21|No Adaptive Cruise Control (Non-ACC)|[Community](community)|
|
||||
|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Equinox Non-ACC 2019-22|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)|
|
||||
|Chevrolet|Malibu Non-ACC 2016-23|No Adaptive Cruise Control (Non-ACC)|[Community](community)|
|
||||
|Chevrolet|Silverado 1500 2020-21|Safety Package II|[Upstream](#upstream)|
|
||||
|Chevrolet|Suburban Non-ACC 2016-20|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)|
|
||||
|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chevrolet|Trailblazer Non-ACC 2021-22|No Adaptive Cruise Control (Non-ACC)|[Dashcam mode](#dashcam)|
|
||||
|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chrysler|Pacifica 2021-23|All|[Upstream](#upstream)|
|
||||
|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Chrysler|Pacifica Hybrid 2019-25|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|comma|body|All|[Upstream](#upstream)|
|
||||
|CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Dodge|Durango 2020-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Ford|Bronco Sport 2021-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||
|Ford|Escape 2020-22|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||
|Ford|Escape 2023-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||
|Ford|Escape Hybrid 2020-22|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||
|Ford|Escape Hybrid 2023-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||
|Ford|Escape Plug-in Hybrid 2020-22|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||
|Ford|Escape Plug-in Hybrid 2023-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||
|Ford|Expedition 2022-24|Co-Pilot360 Assist 2.0|[Upstream](#upstream)|
|
||||
|Ford|Explorer 2020-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||
|Ford|Explorer Hybrid 2020-24|Co-Pilot360 Assist+|[Upstream](#upstream)|
|
||||
|Ford|F-150 2021-23|Co-Pilot360 Assist 2.0|[Upstream](#upstream)|
|
||||
|Ford|F-150 Hybrid 2021-23|Co-Pilot360 Assist 2.0|[Upstream](#upstream)|
|
||||
|Ford|Focus 2018|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
||||
|Ford|Focus Hybrid 2018|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
||||
|Ford|Kuga 2020-23|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
||||
|Ford|Kuga Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
||||
|Ford|Kuga Hybrid 2024|All|[Upstream](#upstream)|
|
||||
|Ford|Kuga Plug-in Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
||||
|Ford|Kuga Plug-in Hybrid 2024|All|[Upstream](#upstream)|
|
||||
|Ford|Maverick 2022|LARIAT Luxury|[Upstream](#upstream)|
|
||||
|Ford|Maverick 2023-24|Co-Pilot360 Assist|[Upstream](#upstream)|
|
||||
|Ford|Maverick Hybrid 2022|LARIAT Luxury|[Upstream](#upstream)|
|
||||
|Ford|Maverick Hybrid 2023-24|Co-Pilot360 Assist|[Upstream](#upstream)|
|
||||
|Ford|Mustang Mach-E 2021-24|All|[Upstream](#upstream)|
|
||||
|Ford|Ranger 2024|Adaptive Cruise Control with Lane Centering|[Upstream](#upstream)|
|
||||
|Genesis|G70 2018|All|[Upstream](#upstream)|
|
||||
|Genesis|G70 2019-21|All|[Upstream](#upstream)|
|
||||
|Genesis|G70 2022-23|All|[Upstream](#upstream)|
|
||||
|Genesis|G70 Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Dashcam mode](#dashcam)|
|
||||
|Genesis|G80 2017|All|[Upstream](#upstream)|
|
||||
|Genesis|G80 2018-19|All|[Upstream](#upstream)|
|
||||
|Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Genesis|G90 2017-20|All|[Upstream](#upstream)|
|
||||
|Genesis|GV60 (Advanced Trim) 2023|All|[Upstream](#upstream)|
|
||||
|Genesis|GV60 (Performance Trim) 2022-23|All|[Upstream](#upstream)|
|
||||
|Genesis|GV70 (2.5T Trim, without HDA II) 2022-24|All|[Upstream](#upstream)|
|
||||
|Genesis|GV70 (3.5T Trim, without HDA II) 2022-23|All|[Upstream](#upstream)|
|
||||
|Genesis|GV70 Electrified (Australia Only) 2022|All|[Upstream](#upstream)|
|
||||
|Genesis|GV70 Electrified (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Genesis|GV80 2023|All|[Upstream](#upstream)|
|
||||
|GMC|Sierra 1500 2020-21|Driver Alert Package II|[Upstream](#upstream)|
|
||||
|GMC|Yukon 2019-20|Adaptive Cruise Control (ACC) & LKAS|[Dashcam mode](#dashcam)|
|
||||
|Honda|Accord 2016-17|Honda Sensing|[Community](#community)|
|
||||
|Honda|Accord 2018-22|All|[Upstream](#upstream)|
|
||||
|Honda|Accord 2023-25|All|[Upstream](#upstream)|
|
||||
|Honda|Accord Hybrid 2017|All|[Community](#community)|
|
||||
|Honda|Accord Hybrid 2018-22|All|[Upstream](#upstream)|
|
||||
|Honda|Accord Hybrid 2023-25|All|[Upstream](#upstream)|
|
||||
|Honda|City (Brazil only) 2023|All|[Upstream](#upstream)|
|
||||
|Honda|Civic 2016-18|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|Civic 2019-21|All|[Upstream](#upstream)|
|
||||
|Honda|Civic 2022-24|All|[Upstream](#upstream)|
|
||||
|Honda|Civic Hatchback 2017-18|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|Civic Hatchback 2019-21|All|[Upstream](#upstream)|
|
||||
|Honda|Civic Hatchback 2022-24|All|[Upstream](#upstream)|
|
||||
|Honda|Civic Hatchback Hybrid 2025-26|All|[Upstream](#upstream)|
|
||||
|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|[Upstream](#upstream)|
|
||||
|Honda|Civic Hybrid 2025-26|All|[Upstream](#upstream)|
|
||||
|Honda|Clarity 2018-21|Honda Sensing|[Community](community)|
|
||||
|Honda|Clarity 2018-21|All|[Community](#community)|
|
||||
|Honda|CR-V 2015-16|Touring Trim|[Upstream](#upstream)|
|
||||
|Honda|CR-V 2017-22|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|CR-V 2023-26|All|[Upstream](#upstream)|
|
||||
|Honda|CR-V Hybrid 2017-22|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|CR-V Hybrid 2023-26|All|[Upstream](#upstream)|
|
||||
|Honda|e 2020|All|[Upstream](#upstream)|
|
||||
|Honda|Fit 2018-20|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|Freed 2020|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|HR-V 2019-22|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|HR-V 2023-25|All|[Upstream](#upstream)|
|
||||
|Honda|Insight 2019-22|All|[Upstream](#upstream)|
|
||||
|Honda|Inspire 2018|All|[Upstream](#upstream)|
|
||||
|Honda|N-Box 2018|All|[Upstream](#upstream)|
|
||||
|Honda|Odyssey 2018-20|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|Odyssey 2021-26|All|[Upstream](#upstream)|
|
||||
|Honda|Odyssey (Taiwan) 2018-19|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|Passport 2019-25|All|[Upstream](#upstream)|
|
||||
|Honda|Passport 2026|All|[Upstream](#upstream)|
|
||||
|Honda|Pilot 2016-22|Honda Sensing|[Upstream](#upstream)|
|
||||
|Honda|Pilot 2023-25|All|[Upstream](#upstream)|
|
||||
|Honda|Prologue 2024-25|All|[Not compatible](#can-bus-security)|
|
||||
|Honda|Ridgeline 2017-25|Honda Sensing|[Upstream](#upstream)|
|
||||
|Hyundai|Azera 2022|All|[Upstream](#upstream)|
|
||||
|Hyundai|Azera Hybrid 2019|All|[Upstream](#upstream)|
|
||||
|Hyundai|Azera Hybrid 2020|All|[Upstream](#upstream)|
|
||||
|Hyundai|Bayon Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Dashcam mode](#dashcam)|
|
||||
|Hyundai|Custin 2023|All|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Elantra Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24|All|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq 5 (with HDA II) 2022-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq 5 (without HDA II) 2022-24|Highway Driving Assist|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq 6 (with HDA II) 2023-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq Electric 2020|All|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|[Upstream](#upstream)|
|
||||
|Hyundai|Kona 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Electric (with HDA II, Korea only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Electric Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Kona Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Hyundai|Nexo 2021|All|[Upstream](#upstream)|
|
||||
|Hyundai|Palisade 2020-22|All|[Upstream](#upstream)|
|
||||
|Hyundai|Palisade 2023-24|Highway Driving Assist II|[Community](#community)|
|
||||
|Hyundai|Santa Cruz 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Fe 2019-20|All|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Fe 2021-23|All|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Fe Hybrid 2022-23|All|[Upstream](#upstream)|
|
||||
|Hyundai|Santa Fe Plug-in Hybrid 2022-23|All|[Upstream](#upstream)|
|
||||
|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Sonata 2020-23|All|[Upstream](#upstream)|
|
||||
|Hyundai|Sonata Hybrid 2020-23|All|[Upstream](#upstream)|
|
||||
|Hyundai|Staria 2023|All|[Upstream](#upstream)|
|
||||
|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Tucson 2022|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Tucson 2023-24|All|[Upstream](#upstream)|
|
||||
|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Hyundai|Tucson Hybrid 2022-24|All|[Upstream](#upstream)|
|
||||
|Hyundai|Tucson Plug-in Hybrid 2024|All|[Upstream](#upstream)|
|
||||
|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Kia|Carnival 2022-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Carnival (China only) 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Ceed Plug-in Hybrid Non-SCC 2022|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Kia|EV6 (Southeast Asia only) 2022-24|All|[Upstream](#upstream)|
|
||||
|Kia|EV6 (with HDA II) 2022-24|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Kia|EV6 (without HDA II) 2022-24|Highway Driving Assist|[Upstream](#upstream)|
|
||||
|Kia|Forte 2019-21|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Forte 2022-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Forte Non-SCC 2019|No Smart Cruise Control (Non-SCC)|[Community](community)|
|
||||
|Kia|Forte Non-SCC 2021|No Smart Cruise Control (Non-SCC)|[Dashcam mode](#dashcam)|
|
||||
|Kia|K5 2021-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|K8 Hybrid (with HDA II) 2023|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Kia|Niro EV 2019|All|[Upstream](#upstream)|
|
||||
|Kia|Niro EV 2020|All|[Upstream](#upstream)|
|
||||
|Kia|Niro EV 2021|All|[Upstream](#upstream)|
|
||||
|Kia|Niro EV 2022|All|[Upstream](#upstream)|
|
||||
|Kia|Niro EV (with HDA II) 2025|Highway Driving Assist II|[Upstream](#upstream)|
|
||||
|Kia|Niro EV (without HDA II) 2023-25|All|[Upstream](#upstream)|
|
||||
|Kia|Niro Hybrid 2018|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Niro Hybrid 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Niro Plug-in Hybrid 2018-19|All|[Upstream](#upstream)|
|
||||
|Kia|Niro Plug-in Hybrid 2020|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Niro Plug-in Hybrid 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Niro Plug-in Hybrid 2022|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Optima 2017|Advanced Smart Cruise Control|[Upstream](#upstream)|
|
||||
|Kia|Optima 2019-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Optima Hybrid 2017|Advanced Smart Cruise Control|[Dashcam mode](#dashcam)|
|
||||
|Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Seltos 2021|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Seltos Non-SCC 2023-24|No Smart Cruise Control (Non-SCC)|[Dashcam mode](#dashcam)|
|
||||
|Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|[Upstream](#upstream)|
|
||||
|Kia|Sorento 2019|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Sorento 2021-23|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Sorento Hybrid 2021-23|All|[Upstream](#upstream)|
|
||||
|Kia|Sorento Plug-in Hybrid 2022-23|All|[Upstream](#upstream)|
|
||||
|Kia|Sportage 2023-24|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Sportage Hybrid 2023|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|[Upstream](#upstream)|
|
||||
|Kia|Stinger 2022-23|All|[Upstream](#upstream)|
|
||||
|Kia|Telluride 2020-22|All|[Upstream](#upstream)|
|
||||
|Kia|Telluride 2023-24|Highway Driving Assist II|[Community](#community)|
|
||||
|Lexus|CT Hybrid 2017-18|Lexus Safety System+|[Upstream](#upstream)|
|
||||
|Lexus|ES 2017-18|All|[Upstream](#upstream)|
|
||||
|Lexus|ES 2019-25|All|[Upstream](#upstream)|
|
||||
|Lexus|ES Hybrid 2017-18|All|[Upstream](#upstream)|
|
||||
|Lexus|ES Hybrid 2019-25|All|[Upstream](#upstream)|
|
||||
|Lexus|GS F 2016|All|[Upstream](#upstream)|
|
||||
|Lexus|IS 2017-19|All|[Upstream](#upstream)|
|
||||
|Lexus|IS 2022-24|All|[Upstream](#upstream)|
|
||||
|Lexus|LC 2024-25|All|[Upstream](#upstream)|
|
||||
|Lexus|LS 2018|All except Lexus Safety System+ A|[Upstream](#upstream)|
|
||||
|Lexus|NS 2022-25|All|[Not compatible](#can-bus-security)|
|
||||
|Lexus|NX 2018-19|All|[Upstream](#upstream)|
|
||||
|Lexus|NX 2020-21|All|[Upstream](#upstream)|
|
||||
|Lexus|NX Hybrid 2018-19|All|[Upstream](#upstream)|
|
||||
|Lexus|NX Hybrid 2020-21|All|[Upstream](#upstream)|
|
||||
|Lexus|RC 2018-20|All|[Upstream](#upstream)|
|
||||
|Lexus|RC 2023|All|[Upstream](#upstream)|
|
||||
|Lexus|RX 2016|Lexus Safety System+|[Upstream](#upstream)|
|
||||
|Lexus|RX 2017-19|All|[Upstream](#upstream)|
|
||||
|Lexus|RX 2020-22|All|[Upstream](#upstream)|
|
||||
|Lexus|RX Hybrid 2016|Lexus Safety System+|[Upstream](#upstream)|
|
||||
|Lexus|RX Hybrid 2017-19|All|[Upstream](#upstream)|
|
||||
|Lexus|RX Hybrid 2020-22|All|[Upstream](#upstream)|
|
||||
|Lexus|UX Hybrid 2019-24|All|[Upstream](#upstream)|
|
||||
|Lincoln|Aviator 2020-24|Co-Pilot360 Plus|[Upstream](#upstream)|
|
||||
|Lincoln|Aviator Plug-in Hybrid 2020-24|Co-Pilot360 Plus|[Upstream](#upstream)|
|
||||
|MAN|eTGE 2020-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|MAN|TGE 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Mazda|3 2017-18|All|[Dashcam mode](#dashcam)|
|
||||
|Mazda|6 2017-20|All|[Dashcam mode](#dashcam)|
|
||||
|Mazda|CX-5 2017-21|All|[Dashcam mode](#dashcam)|
|
||||
|Mazda|CX-5 2022-25|All|[Upstream](#upstream)|
|
||||
|Mazda|CX-9 2016-20|All|[Dashcam mode](#dashcam)|
|
||||
|Mazda|CX-9 2021-23|All|[Upstream](#upstream)|
|
||||
|Nissan|Altima 2019-20, 2024|ProPILOT Assist|[Upstream](#upstream)|
|
||||
|Nissan|Leaf 2018-23|ProPILOT Assist|[Upstream](#upstream)|
|
||||
|Nissan|Rogue 2018-20|ProPILOT Assist|[Upstream](#upstream)|
|
||||
|Nissan|X-Trail 2017|ProPILOT Assist|[Upstream](#upstream)|
|
||||
|Peugeot|208 2019-25|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
||||
|Porsche|Macan 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
||||
|Ram|1500 2019-24|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Ram|2500 2020-24|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Ram|3500 2019-22|Adaptive Cruise Control (ACC)|[Upstream](#upstream)|
|
||||
|Rivian|R1S 2022-24|All|[Upstream](#upstream)|
|
||||
|Rivian|R1T 2022-24|All|[Upstream](#upstream)|
|
||||
|SEAT|Alhambra 2018-20|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
||||
|SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Subaru|Ascent 2019-21|All|[Upstream](#upstream)|
|
||||
|Subaru|Ascent 2023|All|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Crosstrek Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Forester 2017-18|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Forester 2019-21|All|[Upstream](#upstream)|
|
||||
|Subaru|Forester 2022-24|All|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Forester Hybrid 2020|EyeSight Driver Assistance|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Impreza 2017-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Impreza 2020-22|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Legacy 2015-18|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Legacy 2020-22|All|[Upstream](#upstream)|
|
||||
|Subaru|Outback 2015-17|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Outback 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|Outback 2020-22|All|[Upstream](#upstream)|
|
||||
|Subaru|Outback 2023|All|[Dashcam mode](#dashcam)|
|
||||
|Subaru|Solterra 2023-25|All|[Not compatible](#can-bus-security)|
|
||||
|Subaru|XV 2018-19|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Subaru|XV 2020-21|EyeSight Driver Assistance|[Upstream](#upstream)|
|
||||
|Škoda|Fabia 2022-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Škoda|Kamiq 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Škoda|Karoq 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Škoda|Kodiaq 2017-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Škoda|Octavia 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Škoda|Octavia RS 2016|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Škoda|Octavia Scout 2017-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Škoda|Scala 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Škoda|Superb 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Tesla|Model 3 (with HW3) 2019-23|All|[Upstream](#upstream)|
|
||||
|Tesla|Model 3 (with HW4) 2024-25|All|[Upstream](#upstream)|
|
||||
|Tesla|Model X (with HW4) 2024|All|[Community](community)|
|
||||
|Tesla|Model Y (with HW3) 2020-23|All|[Upstream](#upstream)|
|
||||
|Tesla|Model Y (with HW4) 2024-25|All|[Upstream](#upstream)|
|
||||
|Toyota|Alphard 2019-20|All|[Upstream](#upstream)|
|
||||
|Toyota|Alphard Hybrid 2021|All|[Upstream](#upstream)|
|
||||
|Toyota|Avalon 2016|Toyota Safety Sense P|[Upstream](#upstream)|
|
||||
|Toyota|Avalon 2017-18|All|[Upstream](#upstream)|
|
||||
|Toyota|Avalon 2019-21|All|[Upstream](#upstream)|
|
||||
|Toyota|Avalon 2022|All|[Upstream](#upstream)|
|
||||
|Toyota|Avalon Hybrid 2019-21|All|[Upstream](#upstream)|
|
||||
|Toyota|Avalon Hybrid 2022|All|[Upstream](#upstream)|
|
||||
|Toyota|bZ4x 2023-25|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|C-HR 2017-20|All|[Upstream](#upstream)|
|
||||
|Toyota|C-HR 2021|All|[Upstream](#upstream)|
|
||||
|Toyota|C-HR Hybrid 2017-20|All|[Upstream](#upstream)|
|
||||
|Toyota|C-HR Hybrid 2021-22|All|[Upstream](#upstream)|
|
||||
|Toyota|Camry 2018-20|All|[Upstream](#upstream)|
|
||||
|Toyota|Camry 2021-24|All|[Upstream](#upstream)|
|
||||
|Toyota|Camry 2025|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Camry Hybrid 2018-20|All|[Upstream](#upstream)|
|
||||
|Toyota|Camry Hybrid 2021-24|All|[Upstream](#upstream)|
|
||||
|Toyota|Corolla 2017-19|All|[Upstream](#upstream)|
|
||||
|Toyota|Corolla 2020-22|All|[Upstream](#upstream)|
|
||||
|Toyota|Corolla Cross 2022-25|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Corolla Cross (Non-US only) 2020-23|All|[Upstream](#upstream)|
|
||||
|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|[Upstream](#upstream)|
|
||||
|Toyota|Corolla Hatchback 2019-22|All|[Upstream](#upstream)|
|
||||
|Toyota|Corolla Hybrid 2020-22|All|[Upstream](#upstream)|
|
||||
|Toyota|Corolla Hybrid (South America only) 2020-23|All|[Upstream](#upstream)|
|
||||
|Toyota|Highlander 2017-19|All|[Upstream](#upstream)|
|
||||
|Toyota|Highlander 2020-23|All|[Upstream](#upstream)|
|
||||
|Toyota|Highlander 2025|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Highlander Hybrid 2017-19|All|[Upstream](#upstream)|
|
||||
|Toyota|Highlander Hybrid 2020-23|All|[Upstream](#upstream)|
|
||||
|Toyota|Mirai 2021|All|[Upstream](#upstream)|
|
||||
|Toyota|Prius 2016|Toyota Safety Sense P|[Upstream](#upstream)|
|
||||
|Toyota|Prius 2017-20|All|[Upstream](#upstream)|
|
||||
|Toyota|Prius 2021-22|All|[Upstream](#upstream)|
|
||||
|Toyota|Prius Prime 2017-20|All|[Upstream](#upstream)|
|
||||
|Toyota|Prius Prime 2021-22|All|[Upstream](#upstream)|
|
||||
|Toyota|Prius v 2017|Toyota Safety Sense P|[Upstream](#upstream)|
|
||||
|Toyota|RAV4 2016|Toyota Safety Sense P|[Upstream](#upstream)|
|
||||
|Toyota|RAV4 2017-18|All|[Upstream](#upstream)|
|
||||
|Toyota|RAV4 2019-21|All|[Upstream](#upstream)|
|
||||
|Toyota|RAV4 2022|All|[Upstream](#upstream)|
|
||||
|Toyota|RAV4 2023-25|All|[Upstream](#upstream)|
|
||||
|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|[Upstream](#upstream)|
|
||||
|Toyota|RAV4 Hybrid 2017-18|All|[Upstream](#upstream)|
|
||||
|Toyota|RAV4 Hybrid 2019-21|All|[Upstream](#upstream)|
|
||||
|Toyota|RAV4 Hybrid 2022|All|[Upstream](#upstream)|
|
||||
|Toyota|RAV4 Hybrid 2023-25|All|[Upstream](#upstream)|
|
||||
|Toyota|RAV4 Prime 2021-23|All|[Custom](#secoc-cars-with-recoverable-keys)|
|
||||
|Toyota|RAV4 Prime 2024-25|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Sequoia 2023-25|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Sienna 2018-20|All|[Upstream](#upstream)|
|
||||
|Toyota|Sienna 2021-23|All|[Custom](#secoc-cars-with-recoverable-keys)|
|
||||
|Toyota|Sienna 2024-25|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Tundra 2022-25|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Venza 2021-25|All|[Not compatible](#can-bus-security)|
|
||||
|Toyota|Yaris (Non-US only) 2020, 2023|All|[Custom](#secoc-cars-with-recoverable-keys)|
|
||||
|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Arteon Shooting Brake 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Caddy 2019|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
||||
|Volkswagen|Caddy Maxi 2019|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
||||
|Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Crafter 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|e-Crafter 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Jetta 2015-18|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
||||
|Volkswagen|Jetta 2019-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Passat 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Passat NMS 2017-22|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
||||
|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Sharan 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|[Dashcam mode](#dashcam)|
|
||||
|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|T-Roc 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Taos 2022-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Tiguan 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|[Upstream](#upstream)|
|
||||
|
||||
# Types of Support
|
||||
|
||||
**iqdbc can support many more cars than it currently does.** There are a few reasons your car may not be supported.
|
||||
If your car doesn't fit into any of the incompatibility criteria here, then there's a good chance it can be supported!
|
||||
We're adding support for new cars all the time. **We don't have a roadmap for car support**, and in fact, most car
|
||||
support comes from users like you!
|
||||
|
||||
## Upstream
|
||||
|
||||
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better
|
||||
experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
|
||||
|
||||
## Custom
|
||||
|
||||
Vehicles in this category are not considered plug-and-play. Software support is included in upstream openpilot, but
|
||||
these vehicles might not have a harness in the comma store, or the physical install might be at an unusual or cumbersome
|
||||
location, or they might need unusual configuration after install. These vehicles will not work with release builds of
|
||||
openpilot, but depending on the situation, development builds or custom forks may allow their use.
|
||||
|
||||
### SecOC cars with recoverable keys
|
||||
|
||||
For a small subset of SecOC-protected vehicles, tools may be available in the community to recover the SecOC keys. These
|
||||
tools, and the recovery process, are not part of openpilot. If supplied with a valid SecOC key, development builds or
|
||||
custom forks may work with these vehicles. Release builds of openpilot don't support SecOC.
|
||||
@@ -1,117 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import time
|
||||
import threading
|
||||
import argparse
|
||||
import numpy as np
|
||||
from pprint import pprint
|
||||
from inputs import get_gamepad
|
||||
|
||||
from kbhit import KBHit
|
||||
|
||||
from iqdbc.car.structs import CarControl
|
||||
from iqdbc.car.panda_runner import PandaRunner
|
||||
|
||||
|
||||
class Keyboard:
|
||||
def __init__(self):
|
||||
self.kb = KBHit()
|
||||
self.axis_increment = 0.05 # 5% of full actuation each key press
|
||||
self.axes_map = {'w': 'gb', 's': 'gb',
|
||||
'a': 'steer', 'd': 'steer'}
|
||||
self.axes_values = {'gb': 0., 'steer': 0.}
|
||||
self.axes_order = ['gb', 'steer']
|
||||
self.cancel = False
|
||||
|
||||
def update(self):
|
||||
key = self.kb.getch().lower()
|
||||
print(key)
|
||||
self.cancel = False
|
||||
if key == 'r':
|
||||
self.axes_values = {ax: 0. for ax in self.axes_values}
|
||||
elif key == 'c':
|
||||
self.cancel = True
|
||||
elif key in self.axes_map:
|
||||
axis = self.axes_map[key]
|
||||
incr = self.axis_increment if key in ['w', 'a'] else -self.axis_increment
|
||||
self.axes_values[axis] = float(np.clip(self.axes_values[axis] + incr, -1, 1))
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class Joystick:
|
||||
def __init__(self, gamepad=False):
|
||||
# TODO: find a way to get this from API, perhaps "inputs" doesn't support it
|
||||
if gamepad:
|
||||
self.cancel_button = 'BTN_NORTH' # (BTN_NORTH=X, ABS_RZ=Right Trigger)
|
||||
accel_axis = 'ABS_Y'
|
||||
steer_axis = 'ABS_RX'
|
||||
else:
|
||||
self.cancel_button = 'BTN_TRIGGER'
|
||||
accel_axis = 'ABS_Y'
|
||||
steer_axis = 'ABS_RX'
|
||||
self.min_axis_value = {accel_axis: 0., steer_axis: 0.}
|
||||
self.max_axis_value = {accel_axis: 255., steer_axis: 255.}
|
||||
self.axes_values = {accel_axis: 0., steer_axis: 0.}
|
||||
self.axes_order = [accel_axis, steer_axis]
|
||||
self.cancel = False
|
||||
|
||||
def update(self):
|
||||
joystick_event = get_gamepad()[0]
|
||||
event = (joystick_event.code, joystick_event.state)
|
||||
if event[0] == self.cancel_button:
|
||||
if event[1] == 1:
|
||||
self.cancel = True
|
||||
elif event[1] == 0: # state 0 is falling edge
|
||||
self.cancel = False
|
||||
elif event[0] in self.axes_values:
|
||||
self.max_axis_value[event[0]] = max(event[1], self.max_axis_value[event[0]])
|
||||
self.min_axis_value[event[0]] = min(event[1], self.min_axis_value[event[0]])
|
||||
|
||||
norm = -float(np.interp(event[1], [self.min_axis_value[event[0]], self.max_axis_value[event[0]]], [-1., 1.]))
|
||||
self.axes_values[event[0]] = norm if abs(norm) > 0.05 else 0. # center can be noisy, deadzone of 5%
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def joystick_thread(joystick):
|
||||
while True:
|
||||
joystick.update()
|
||||
|
||||
|
||||
def main(joystick):
|
||||
threading.Thread(target=joystick_thread, args=(joystick,), daemon=True).start()
|
||||
with PandaRunner() as p:
|
||||
CC = CarControl(enabled=False)
|
||||
while True:
|
||||
CC.actuators.accel = float(4.0*np.clip(joystick.axes_values['gb'], -1, 1))
|
||||
CC.actuators.torque = float(np.clip(joystick.axes_values['steer'], -1, 1))
|
||||
pprint(CC)
|
||||
|
||||
p.read()
|
||||
p.write(CC)
|
||||
|
||||
# 100Hz
|
||||
time.sleep(0.01)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='Test the car interface with a joystick. Uses keyboard by default.',
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
|
||||
parser.add_argument('--mode', choices=['keyboard', 'gamepad', 'joystick'], default='keyboard')
|
||||
args = parser.parse_args()
|
||||
|
||||
print()
|
||||
joystick: Keyboard | Joystick
|
||||
if args.mode == 'keyboard':
|
||||
print('Gas/brake control: `W` and `S` keys')
|
||||
print('Steering control: `A` and `D` keys')
|
||||
print('Buttons')
|
||||
print('- `R`: Resets axes')
|
||||
print('- `C`: Cancel cruise control')
|
||||
joystick = Keyboard()
|
||||
else:
|
||||
joystick = Joystick(gamepad=(args.mode == 'gamepad'))
|
||||
main(joystick)
|
||||
@@ -1,60 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import termios
|
||||
import atexit
|
||||
from select import select
|
||||
|
||||
STDIN_FD = sys.stdin.fileno()
|
||||
|
||||
|
||||
class KBHit:
|
||||
def __init__(self) -> None:
|
||||
self.set_kbhit_terminal()
|
||||
|
||||
def set_kbhit_terminal(self) -> None:
|
||||
# Save the terminal settings
|
||||
self.old_term = termios.tcgetattr(STDIN_FD)
|
||||
self.new_term = self.old_term.copy()
|
||||
|
||||
# New terminal setting unbuffered
|
||||
self.new_term[3] &= ~(termios.ICANON | termios.ECHO)
|
||||
termios.tcsetattr(STDIN_FD, termios.TCSAFLUSH, self.new_term)
|
||||
|
||||
# Support normal-terminal reset at exit
|
||||
atexit.register(self.set_normal_term)
|
||||
|
||||
def set_normal_term(self) -> None:
|
||||
termios.tcsetattr(STDIN_FD, termios.TCSAFLUSH, self.old_term)
|
||||
|
||||
@staticmethod
|
||||
def getch() -> str:
|
||||
return sys.stdin.read(1)
|
||||
|
||||
@staticmethod
|
||||
def getarrow() -> int:
|
||||
c = sys.stdin.read(3)[2]
|
||||
vals = [65, 67, 66, 68]
|
||||
return vals.index(ord(c))
|
||||
|
||||
@staticmethod
|
||||
def kbhit():
|
||||
''' Returns True if keyboard character was hit, False otherwise.
|
||||
'''
|
||||
return select([sys.stdin], [], [], 0)[0] != []
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
kb = KBHit()
|
||||
|
||||
print('Hit any key, or ESC to exit')
|
||||
|
||||
while True:
|
||||
|
||||
if kb.kbhit():
|
||||
c = kb.getch()
|
||||
if c == '\x1b': # ESC
|
||||
break
|
||||
print(c)
|
||||
|
||||
kb.set_normal_term()
|
||||
@@ -198,7 +198,7 @@ def get_checksum_state(dbc_name: str) -> ChecksumState | None:
|
||||
return ChecksumState(8, -1, 7, -1, False, SignalType.FCA_GIORGIO_CHECKSUM, fca_giorgio_checksum)
|
||||
elif dbc_name.startswith("comma_body"):
|
||||
return ChecksumState(8, 4, 7, 3, False, SignalType.BODY_CHECKSUM, body_checksum)
|
||||
elif dbc_name.startswith("tesla_model3_party"):
|
||||
elif dbc_name.startswith(("tesla_model3_party", "tesla_model3_vehicle")):
|
||||
return ChecksumState(8, -1, 0, -1, True, SignalType.TESLA_CHECKSUM, tesla_checksum, tesla_setup_signal)
|
||||
elif dbc_name.startswith("psa_"):
|
||||
return ChecksumState(4, 4, 7, 3, False, SignalType.PSA_CHECKSUM, psa_checksum)
|
||||
|
||||
@@ -67,6 +67,32 @@ class TestCanParserPacker:
|
||||
parser.update([t, [msg]])
|
||||
assert parser.can_valid
|
||||
|
||||
def test_lazy_add_not_ignore_alive(self):
|
||||
"""
|
||||
Accessing an undeclared message via parser.vl[...] lazily adds it via
|
||||
_add_message(key) with the default freq=None, which is NOT the same as
|
||||
declaring it with math.nan (ignore_alive=True). It's treated as "assume
|
||||
~1Hz, must be seen within ~10s" — so if that message is never fed, the
|
||||
parser is permanently invalid. Declaring an optional/rarely-sent message
|
||||
with math.nan (or gating the .vl[...] read entirely) is required to avoid
|
||||
this; see iqdbc/car/volkswagen/carstate.py's Diagnose_1/EPB_1 bugs.
|
||||
"""
|
||||
parser = CANParser(TEST_DBC, [], 0)
|
||||
assert parser.can_valid
|
||||
|
||||
# lazily add STEERING_CONTROL by reading it, without ever declaring it
|
||||
# or feeding any CAN data for it
|
||||
_ = parser.vl["STEERING_CONTROL"]
|
||||
state = parser.message_states[parser.dbc.name_to_msg["STEERING_CONTROL"].address]
|
||||
assert not state.ignore_alive
|
||||
|
||||
# never becomes valid again, no matter how many times it's checked
|
||||
# (can_valid debounces over MAX_BAD_COUNTER reads before flipping false)
|
||||
for _ in range(MAX_BAD_COUNTER):
|
||||
parser.can_valid
|
||||
for _ in range(20):
|
||||
assert not parser.can_valid
|
||||
|
||||
def test_parser_updated_list(self):
|
||||
msgs = [("CAN_FD_MESSAGE", 10), ]
|
||||
parser = CANParser(TEST_DBC, msgs, 0)
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
<!--- AUTOGENERATED FROM selfdrive/car/CARS_template.md, DO NOT EDIT. --->
|
||||
|
||||
# Support Information for {{all_car_docs | length}} Known Cars
|
||||
|
||||
|{{ExtraCarsColumn | map(attribute='value') | join('|') | replace(hardware_col_name, wide_hardware_col_name)}}|
|
||||
|---|---|---|{% for _ in range((ExtraCarsColumn | length) - 3) %}{{':---:|'}}{% endfor +%}
|
||||
{% for car_docs in all_car_docs %}
|
||||
|{% for column in ExtraCarsColumn %}{{car_docs.get_extra_cars_column(column)}}|{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
# Types of Support
|
||||
|
||||
**iqdbc can support many more cars than it currently does.** There are a few reasons your car may not be supported.
|
||||
If your car doesn't fit into any of the incompatibility criteria here, then there's a good chance it can be supported!
|
||||
We're adding support for new cars all the time. **We don't have a roadmap for car support**, and in fact, most car
|
||||
support comes from users like you!
|
||||
|
||||
## Upstream
|
||||
|
||||
A supported vehicle is one that just works when you install a comma device. All supported cars provide a better
|
||||
experience than any stock system. Supported vehicles reference the US market unless otherwise specified.
|
||||
|
||||
## Under Review
|
||||
|
||||
A vehicle under review is one for which software support has been merged into upstream openpilot, but hasn't yet been
|
||||
tested for drive quality and conformance with [comma safety guidelines](https://github.com/commaai/openpilot/blob/master/docs/SAFETY.md).
|
||||
This is a normal part of the development and quality assurance process. This vehicle will not work when upstream
|
||||
openpilot is installed, but custom forks may allow their use.
|
||||
|
||||
## Custom
|
||||
|
||||
Vehicles in this category are not considered plug-and-play. Software support is included in upstream openpilot, but
|
||||
these vehicles might not have a harness in the comma store, or the physical install might be at an unusual or cumbersome
|
||||
location, or they might need unusual configuration after install. These vehicles will not work with release builds of
|
||||
openpilot, but depending on the situation, development builds or custom forks may allow their use.
|
||||
|
||||
### SecOC cars with recoverable keys
|
||||
|
||||
For a small subset of SecOC-protected vehicles, tools may be available in the community to recover the SecOC keys. These
|
||||
tools, and the recovery process, are not part of openpilot. If supplied with a valid SecOC key, development builds or
|
||||
custom forks may work with these vehicles. Release builds of openpilot don't support SecOC.
|
||||
|
||||
## Dashcam
|
||||
|
||||
Dashcam vehicles have software support in upstream openpilot, but will go into "dashcam mode" at startup and will not
|
||||
engage. This may be due to known issues with driving safety or quality, or it may be a work in progress that isn't yet
|
||||
ready for safety and quality review.
|
||||
|
||||
## Community
|
||||
|
||||
Although they're not upstream, the community has openpilot running on other makes and models. See the 'Community
|
||||
Supported Models' section of each make [on our wiki](https://wiki.comma.ai/).
|
||||
|
||||
Some notable works-in-progress:
|
||||
* Honda
|
||||
* 2022-24 Acura RDX, commaai/iqdbc#1967
|
||||
* Camera ACC stability improvements, commaai/iqdbc#2192
|
||||
* Alpha longitudinal stability improvements, commaai/iqdbc#2347 and commaai/iqdbc#2165
|
||||
|
||||
## Incompatible
|
||||
|
||||
### CAN Bus Security
|
||||
|
||||
Vehicles with CAN security measures, such as AUTOSAR Secure Onboard Communication (SecOC) are not usable with openpilot
|
||||
unless the owner can recover the message signing key and implement CAN message signing. Examples include certain newer
|
||||
Toyota, and the GM Global B platform.
|
||||
|
||||
### FlexRay
|
||||
|
||||
All the cars that openpilot supports use a [CAN bus](https://en.wikipedia.org/wiki/CAN_bus) for communication between all the car's computers, however a
|
||||
CAN bus isn't the only way that the computers in your car can communicate. Most, if not all, vehicles from the following
|
||||
manufacturers use [FlexRay](https://en.wikipedia.org/wiki/FlexRay) instead of a CAN bus: **BMW, Mercedes, Audi, Land Rover, and some Volvo**. These cars
|
||||
may one day be supported, but we have no immediate plans to support FlexRay.
|
||||
@@ -209,6 +209,8 @@ struct CarState {
|
||||
lateralAvailable @61 :Bool; # lateral control is available even if cruise is faulted
|
||||
cruiseFaultLateralMode @62 :Bool; # cruise is faulted but lateral control is still active
|
||||
radarDisableFailed @66 :Bool;
|
||||
# Physical vehicle odometer in kilometers. Zero means unavailable on this platform.
|
||||
odometer @67 :Float64;
|
||||
|
||||
# cruise state
|
||||
cruiseState @10 :CruiseState;
|
||||
@@ -464,6 +466,7 @@ struct CarControl {
|
||||
prompt @6;
|
||||
promptRepeat @7;
|
||||
promptDistracted @8;
|
||||
preAlert @9;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,14 +535,9 @@ struct CarParams {
|
||||
steerLimitAlert @28 :Bool;
|
||||
steerLimitTimer @47 :Float32; # time before steerLimitAlert is issued
|
||||
|
||||
vEgoStopping @29 :Float32; # Speed at which the car goes into stopping state
|
||||
vEgoStarting @59 :Float32; # Speed at which the car goes into starting state
|
||||
steerControlType @34 :SteerControlType;
|
||||
radarUnavailable @35 :Bool; # True when radar objects aren't visible on CAN or aren't parsed out
|
||||
stopAccel @60 :Float32; # Required acceleration to keep vehicle stationary
|
||||
stoppingDecelRate @52 :Float32; # m/s^2/s while trying to stop
|
||||
startAccel @32 :Float32; # Required acceleration to get car moving
|
||||
startingState @70 :Bool; # Does this car make use of special starting state
|
||||
|
||||
steerActuatorDelay @36 :Float32; # Steering wheel actuator delay in seconds
|
||||
longitudinalActuatorDelay @58 :Float32; # Gas/Brake actuator delay in seconds
|
||||
@@ -772,4 +770,9 @@ struct CarParams {
|
||||
stoppingControlDEPRECATED @31 :Bool; # Does the car allow full control even at lows speeds when stopping
|
||||
radarTimeStepDEPRECATED @45: Float32 = 0.05; # time delta between radar updates, 20Hz is very standard
|
||||
enableDsuDEPRECATED @5 :Bool; # driving support unit
|
||||
vEgoStartingDEPRECATED @59 :Float32;
|
||||
startAccelDEPRECATED @32 :Float32;
|
||||
startingStateDEPRECATED @70 :Bool;
|
||||
vEgoStoppingDEPRECATED @29 :Float32;
|
||||
stoppingDecelRateDEPRECATED @52 :Float32;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_mu
|
||||
cached_params: CarParamsT | None,
|
||||
fixed_fingerprint: str | None) -> tuple[str | None, dict, str, list[CarParams.CarFw], CarParams.FingerprintSource, bool]:
|
||||
fixed_fingerprint = fixed_fingerprint or os.environ.get('FINGERPRINT', "")
|
||||
skip_fw_query = os.environ.get('SKIP_FW_QUERY', False)
|
||||
skip_fw_query = os.environ.get('SKIP_FW_QUERY', False) or bool(fixed_fingerprint)
|
||||
disable_fw_cache = os.environ.get('DISABLE_FW_CACHE', False)
|
||||
ecu_rx_addrs = set()
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ from iqdbc.car.extra_cars import CAR as EXTRA
|
||||
|
||||
|
||||
EXTRA_CARS_MD_OUT = os.path.join(BASEDIR, "../", "../", "docs", "CARS.md")
|
||||
EXTRA_CARS_MD_TEMPLATE = os.path.join(BASEDIR, "CARS_template.md")
|
||||
|
||||
# TODO: merge these platforms into normal car ports with SupportType flag
|
||||
ExtraPlatform = Platform | EXTRA
|
||||
@@ -106,7 +105,6 @@ if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Auto generates supportability info docs for all known cars",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
|
||||
parser.add_argument("--template", default=EXTRA_CARS_MD_TEMPLATE, help="Override default template filename")
|
||||
parser.add_argument("--out", default=EXTRA_CARS_MD_OUT, help="Override default generated filename")
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
@@ -125,9 +125,6 @@ class CarInterface(CarInterfaceBase, CarInterfaceExt):
|
||||
|
||||
# Tuning for experimental long
|
||||
ret.longitudinalTuning.kiV = [2.0, 1.5]
|
||||
ret.stoppingDecelRate = 2.0 # reach brake quickly after enabling
|
||||
ret.vEgoStopping = 0.25
|
||||
ret.vEgoStarting = 0.25
|
||||
|
||||
if alpha_long:
|
||||
ret.pcmCruise = False
|
||||
|
||||
@@ -23,6 +23,10 @@ MAX_ANGLE_FRAMES = 89
|
||||
MAX_ANGLE_CONSECUTIVE_FRAMES = 2
|
||||
|
||||
|
||||
def _use_stock_lkas_request_path(CP) -> bool:
|
||||
return CP.carFingerprint == CAR.HYUNDAI_PALISADE
|
||||
|
||||
|
||||
def process_hud_alert(enabled, fingerprint, hud_control):
|
||||
sys_warning = (hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw))
|
||||
|
||||
@@ -92,12 +96,12 @@ class CarController(CarControllerBase, EsccCarController, LeadDataCarController,
|
||||
else:
|
||||
self.apply_torque_last = apply_torque
|
||||
|
||||
if apply_torque == 0 and CC.latActive and CS.out.steeringPressed:
|
||||
if not _use_stock_lkas_request_path(self.CP) and apply_torque == 0 and CC.latActive and CS.out.steeringPressed:
|
||||
apply_steer_req = False
|
||||
|
||||
# Hold torque with induced temporary fault when cutting the actuation bit
|
||||
# FIXME: we don't use this with CAN FD?
|
||||
torque_fault = CC.latActive and not apply_steer_req
|
||||
torque_fault = False if _use_stock_lkas_request_path(self.CP) else (CC.latActive and not apply_steer_req)
|
||||
|
||||
# accel + longitudinal
|
||||
accel = float(np.clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX))
|
||||
|
||||
@@ -7,6 +7,10 @@ from iqdbc.iqpilot.car.hyundai.lead_data_ext import CanLeadData
|
||||
hyundai_checksum = crcmod.mkCrcFun(0x11D, initCrc=0xFD, rev=False, xorOut=0xdf)
|
||||
|
||||
|
||||
def _use_stock_scc_surrogates(CP) -> bool:
|
||||
return CP.carFingerprint == CAR.HYUNDAI_PALISADE
|
||||
|
||||
|
||||
def create_lkas11(packer, frame, CP, apply_torque, steer_req,
|
||||
torque_fault, lkas11, sys_warning, sys_state, enabled,
|
||||
left_lane, right_lane,
|
||||
@@ -137,7 +141,7 @@ def create_acc_commands(packer, enabled, accel, upper_jerk, idx, lead_data: CanL
|
||||
commands = []
|
||||
|
||||
def get_scc11_values():
|
||||
return {
|
||||
values = {
|
||||
"MainMode_ACC": 1 if main_cruise_enabled else 0,
|
||||
"TauGapSet": hud_control.leadDistanceBars,
|
||||
"VSetDis": set_speed if enabled else 0,
|
||||
@@ -148,6 +152,11 @@ def create_acc_commands(packer, enabled, accel, upper_jerk, idx, lead_data: CanL
|
||||
"ACC_ObjRelSpd": lead_data.lead_rel_speed,
|
||||
"ACC_ObjDist": int(lead_data.lead_distance), # close lead makes controls tighter
|
||||
}
|
||||
if _use_stock_scc_surrogates(CP):
|
||||
values["ObjValid"] = 1
|
||||
values["ACC_ObjStatus"] = 1
|
||||
values["ACC_ObjDist"] = 1
|
||||
return values
|
||||
|
||||
def get_scc12_values():
|
||||
scc12_values = {
|
||||
@@ -176,15 +185,17 @@ def create_acc_commands(packer, enabled, accel, upper_jerk, idx, lead_data: CanL
|
||||
return values
|
||||
|
||||
def get_scc14_values():
|
||||
return {
|
||||
values = {
|
||||
"ComfortBandUpper": tuning.comfort_band_upper, # stock usually is 0 but sometimes uses higher values
|
||||
"ComfortBandLower": tuning.comfort_band_lower, # stock usually is 0 but sometimes uses higher values
|
||||
"JerkUpperLimit": tuning.jerk_upper, # stock usually is 1.0 but sometimes uses higher values
|
||||
"JerkLowerLimit": tuning.jerk_lower, # stock usually is 0.5 but sometimes uses higher values
|
||||
"ACCMode": 2 if enabled and long_override else 1 if enabled else 4, # stock will always be 4 instead of 0 after first disengage
|
||||
"ObjGap": lead_data.object_gap, # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead
|
||||
"ObjDistStat": lead_data.object_rel_gap,
|
||||
}
|
||||
if not _use_stock_scc_surrogates(CP):
|
||||
values["ObjDistStat"] = lead_data.object_rel_gap
|
||||
return values
|
||||
|
||||
def get_fca11_values():
|
||||
return {
|
||||
|
||||
@@ -134,9 +134,6 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or Bus.radar not in DBC[ret.carFingerprint]
|
||||
ret.openpilotLongitudinalControl = alpha_long and ret.alphaLongitudinalAvailable
|
||||
ret.pcmCruise = not ret.openpilotLongitudinalControl
|
||||
ret.startingState = True
|
||||
ret.vEgoStarting = 0.1
|
||||
ret.startAccel = 1.0
|
||||
ret.longitudinalActuatorDelay = 0.5
|
||||
|
||||
if ret.openpilotLongitudinalControl:
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
from iqdbc.can import CANParser, CANPacker
|
||||
from iqdbc.car import Bus
|
||||
from iqdbc.car.hyundai import hyundaican
|
||||
from iqdbc.car.hyundai.values import CAR, DBC
|
||||
|
||||
|
||||
class DummyHudControl:
|
||||
leadDistanceBars = 3
|
||||
leadVisible = True
|
||||
|
||||
|
||||
class DummyLeadData:
|
||||
lead_visible = False
|
||||
lead_rel_speed = -7
|
||||
lead_distance = 42
|
||||
object_gap = 5
|
||||
object_rel_gap = 2
|
||||
|
||||
|
||||
class DummyTuning:
|
||||
comfort_band_upper = 0.2
|
||||
comfort_band_lower = 0.3
|
||||
jerk_upper = 1.7
|
||||
jerk_lower = 1.2
|
||||
desired_accel = 0.4
|
||||
actual_accel = 0.3
|
||||
stopping = False
|
||||
|
||||
|
||||
class DummyCP:
|
||||
carFingerprint = CAR.HYUNDAI_PALISADE
|
||||
flags = 0
|
||||
|
||||
|
||||
def _decode(msg_name: str, addr: int, dat: bytes):
|
||||
cp = CANParser(DBC[CAR.HYUNDAI_PALISADE][Bus.pt], [(msg_name, 0)], 0)
|
||||
cp.update([(0, [(addr, dat, 0)])])
|
||||
return cp.vl[msg_name]
|
||||
|
||||
|
||||
def test_palisade_uses_stock_scc_surrogates():
|
||||
packer = CANPacker(DBC[CAR.HYUNDAI_PALISADE][Bus.pt])
|
||||
cp = DummyCP()
|
||||
hud = DummyHudControl()
|
||||
tuning = DummyTuning()
|
||||
lead = DummyLeadData()
|
||||
|
||||
scc11 = hyundaican.create_acc_commands(
|
||||
packer, True, 0.5, 3.0, 1, lead, hud, 72, False, False, True, cp, False, tuning
|
||||
)[0]
|
||||
scc14 = hyundaican.create_acc_commands(
|
||||
packer, True, 0.5, 3.0, 1, lead, hud, 72, False, False, True, cp, False, tuning
|
||||
)[2]
|
||||
|
||||
scc11_vals = _decode("SCC11", scc11[0], scc11[1])
|
||||
assert scc11_vals["ObjValid"] == 1
|
||||
assert scc11_vals["ACC_ObjStatus"] == 1
|
||||
assert scc11_vals["ACC_ObjDist"] == 1
|
||||
|
||||
scc14_vals = _decode("SCC14", scc14[0], scc14[1])
|
||||
assert "ObjDistStat" not in scc14_vals or scc14_vals["ObjDistStat"] == 0
|
||||
@@ -253,9 +253,6 @@ class CarInterfaceBase(ABC, CarInterfaceBaseIQ):
|
||||
ret.steerRatioRear = 0. # no rear steering, at least on the listed cars aboveA
|
||||
ret.openpilotLongitudinalControl = False
|
||||
ret.stopAccel = -2.0
|
||||
ret.stoppingDecelRate = 0.8 # brake_travel/s while trying to stop
|
||||
ret.vEgoStopping = 0.5
|
||||
ret.vEgoStarting = 0.5
|
||||
ret.longitudinalTuning.kpBP = [0.]
|
||||
ret.longitudinalTuning.kpV = [0.]
|
||||
ret.longitudinalTuning.kiBP = [0.]
|
||||
|
||||
@@ -6,7 +6,6 @@ from iqdbc.car.vehicle_model import VehicleModel
|
||||
|
||||
FRICTION_THRESHOLD = 0.2
|
||||
|
||||
# ISO 11270
|
||||
ISO_LATERAL_ACCEL = 3.0 # m/s^2
|
||||
ISO_LATERAL_JERK = 5.0 # m/s^3
|
||||
AVERAGE_ROAD_ROLL = 0.06 # ~3.4 degrees
|
||||
|
||||
@@ -3,7 +3,7 @@ import os
|
||||
import capnp
|
||||
import urllib.parse
|
||||
import warnings
|
||||
from urllib.request import urlopen
|
||||
from urllib.request import urlopen, Request
|
||||
import zstandard as zstd
|
||||
|
||||
from iqdbc.car.common.basedir import BASEDIR
|
||||
@@ -27,7 +27,7 @@ class LogReader:
|
||||
_, ext = os.path.splitext(urllib.parse.urlparse(fn).path)
|
||||
|
||||
if fn.startswith("http"):
|
||||
with urlopen(fn) as f:
|
||||
with urlopen(Request(fn, headers={"User-Agent": "iqdbc"})) as f:
|
||||
dat = f.read()
|
||||
else:
|
||||
with open(fn, "rb") as f:
|
||||
|
||||
@@ -32,7 +32,6 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.safetyConfigs[0].safetyParam |= RivianSafetyFlags.LONG_CONTROL.value
|
||||
|
||||
ret.longitudinalActuatorDelay = 0.35
|
||||
ret.vEgoStopping = 0.25
|
||||
ret.stopAccel = 0
|
||||
|
||||
return ret
|
||||
|
||||
@@ -51,6 +51,7 @@ class IQCarParams:
|
||||
iqSafetyFlags: int = auto_field()
|
||||
pcmCruiseSpeed: bool = auto_field()
|
||||
enableGasInterceptor: bool = auto_field()
|
||||
longitudinalStoppingSpeedOverride: float = auto_field()
|
||||
|
||||
iqLateralNet: 'IQCarParams.LateralNet' = field(default_factory=lambda: IQCarParams.LateralNet())
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
# FIXME: gate by FingerPrint
|
||||
TESLA_BLINKERS = False
|
||||
|
||||
@@ -3,11 +3,13 @@ from iqdbc.can import CANPacker
|
||||
from iqdbc.car import Bus
|
||||
from iqdbc.car.lateral import apply_steer_angle_limits_vm
|
||||
from iqdbc.car.interfaces import CarControllerBase
|
||||
from iqdbc.car.tesla import TESLA_BLINKERS
|
||||
from iqdbc.car.tesla.teslacan import TeslaCAN
|
||||
from iqdbc.car.tesla.values import CarControllerParams
|
||||
from iqdbc.car.vehicle_model import VehicleModel
|
||||
from openpilot.iqpilot.selfdrive.car.enhanced_stock_longitudinal_control import get_set_speed_kph_from_params
|
||||
from iqdbc.iqpilot.car.tesla.coop_steering import CoopSteeringCarController
|
||||
from iqdbc.iqpilot.car.tesla.values import TeslaFlagsIQ
|
||||
|
||||
|
||||
def get_safety_CP():
|
||||
@@ -28,6 +30,11 @@ class CarController(CarControllerBase):
|
||||
# Vehicle model used for lateral limiting
|
||||
self.VM = VehicleModel(get_safety_CP())
|
||||
|
||||
self.has_vehicle_bus = bool(CP_IQ.flags & TeslaFlagsIQ.HAS_VEHICLE_BUS)
|
||||
self.body_controls_counter_last = -1
|
||||
self.blinker_request_prev = False
|
||||
self.blinker_cancel_frame = 0
|
||||
|
||||
def update(self, CC, CC_IQ, CS, now_nanos):
|
||||
actuators = CC.actuators
|
||||
can_sends = []
|
||||
@@ -52,6 +59,8 @@ class CarController(CarControllerBase):
|
||||
if self.frame % 4 == 0:
|
||||
state = 13 if CC.cruiseControl.cancel or CS.das_accCancel else 4 # 4=ACC_ON, 13=ACC_CANCEL_GENERIC_SILENT
|
||||
accel = float(np.clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX))
|
||||
if not CC.longActive:
|
||||
accel = 0.
|
||||
cntr = (self.frame // 4) % 8
|
||||
set_speed_kph = get_set_speed_kph_from_params(CC_IQ.params)
|
||||
can_sends.append(self.tesla_can.create_longitudinal_command(state, accel, cntr, CS.out.vEgo, CC.longActive,
|
||||
@@ -63,6 +72,30 @@ class CarController(CarControllerBase):
|
||||
cntr = (CS.das_control["DAS_controlCounter"] + 1) % 8
|
||||
can_sends.append(self.tesla_can.create_longitudinal_command(13, 0, cntr, CS.out.vEgo, False, True))
|
||||
|
||||
# Nav blinker control via DAS_bodyControls on the vehicle bus, phase-locked to the car's
|
||||
# counter. Cancel on the trailing edge since the body controller latches the signal.
|
||||
stock_dat = getattr(CS, 'das_body_controls_dat', b"")
|
||||
# FIXME: gate by FingerPrint
|
||||
if TESLA_BLINKERS and self.has_vehicle_bus and len(stock_dat) >= 8:
|
||||
left_blinker = CC.leftBlinker
|
||||
right_blinker = CC.rightBlinker
|
||||
|
||||
driver_opposes = (left_blinker and CS.out.rightBlinker) or (right_blinker and CS.out.leftBlinker)
|
||||
if driver_opposes:
|
||||
left_blinker = right_blinker = False
|
||||
|
||||
nav_requesting = left_blinker or right_blinker
|
||||
|
||||
if self.blinker_request_prev and not nav_requesting and not driver_opposes:
|
||||
self.blinker_cancel_frame = self.frame + 150 # ~1.5 s
|
||||
self.blinker_request_prev = nav_requesting
|
||||
cancel = not nav_requesting and not driver_opposes and self.frame < self.blinker_cancel_frame
|
||||
|
||||
body_counter = stock_dat[6] >> 4
|
||||
if body_counter != self.body_controls_counter_last:
|
||||
can_sends.append(self.tesla_can.create_body_controls(stock_dat, left_blinker, right_blinker, cancel))
|
||||
self.body_controls_counter_last = body_counter
|
||||
|
||||
# TODO: HUD control
|
||||
new_actuators = actuators.as_builder()
|
||||
new_actuators.steeringAngleDeg = self.apply_angle_last
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import copy
|
||||
from iqdbc.can import CANDefine, CANParser
|
||||
from iqdbc.car import Bus, create_button_events, structs
|
||||
from iqdbc.car.carlog import carlog
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car.interfaces import CarStateBase
|
||||
from iqdbc.car.tesla.teslacan import get_steer_ctrl_type
|
||||
from iqdbc.car.tesla import TESLA_BLINKERS
|
||||
from iqdbc.car.tesla.values import DBC, CANBUS, GEAR_MAP, STEER_THRESHOLD, TeslaFlags
|
||||
|
||||
from iqdbc.iqpilot.car.tesla.carstate_ext import CarStateExt
|
||||
from iqdbc.iqpilot.car.tesla.values import TeslaFlagsIQ
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.system.proprietary_runtime._verified_import import import_verified_module
|
||||
|
||||
vehicle_state = import_verified_module("iqpilot_alc_private", "iqpilot_private.konn3kt.iqlvbs.vehicle_state")
|
||||
|
||||
ButtonType = structs.CarState.ButtonEvent.Type
|
||||
|
||||
@@ -22,13 +26,12 @@ class CarState(CarStateBase, CarStateExt):
|
||||
self.summon = False
|
||||
self.summon_prev = False
|
||||
self.cruise_enabled_prev = False
|
||||
self.fsd14_error_logged = False
|
||||
self.suspected_fsd14 = False
|
||||
self.suspected_fsd14_clear_frames = 0
|
||||
|
||||
self.hands_on_level = 0
|
||||
self.acc_state_last = 0
|
||||
self.das_control = None
|
||||
self.das_body_controls_dat = b""
|
||||
self._odometer_store = vehicle_state.VehicleOdometerStore(CP, Params())
|
||||
self.cruise_override = False
|
||||
|
||||
def update_summon_state(self, summon_state: str, cruise_enabled: bool):
|
||||
@@ -136,54 +139,40 @@ class CarState(CarStateBase, CarStateExt):
|
||||
ret.stockAeb = cp_ap_party.vl["DAS_control"]["DAS_aebEvent"] == 1
|
||||
|
||||
# LKAS
|
||||
# On FSD 14+, ANGLE_CONTROL behavior changed to allow user winddown while actuating.
|
||||
# FSD switched from using ANGLE_CONTROL to LANE_KEEP_ASSIST to likely keep the old steering override disengage logic.
|
||||
# LKAS switched from LANE_KEEP_ASSIST to ANGLE_CONTROL to likely allow overriding LKAS events smoothly
|
||||
lkas_ctrl_type = get_steer_ctrl_type(self.CP.flags, 2)
|
||||
ret.stockLkas = cp_ap_party.vl["DAS_steeringControl"]["DAS_steeringControlType"] == lkas_ctrl_type # LANE_KEEP_ASSIST
|
||||
steer_control_type = int(cp_ap_party.vl["DAS_steeringControl"]["DAS_steeringControlType"])
|
||||
if self.CP.flags & TeslaFlags.LEGACY_DAS_STEERING:
|
||||
steer_control_type >>= 1 # legacy firmware uses a 2-bit field, one bit up from the 3-bit signal
|
||||
ret.stockLkas = steer_control_type == 2 # LANE_KEEP_ASSIST
|
||||
|
||||
# Stock Autosteer should be disengaged (includes FSD)
|
||||
# TODO: find for TESLA_MODEL_X and HW2.5 vehicles
|
||||
if not (self.CP.flags & TeslaFlags.MISSING_DAS_SETTINGS):
|
||||
ret.invalidLkasSetting = cp_ap_party.vl["DAS_status"]["DAS_autopilotState"] not in (0, 1, 2) # DISABLED, UNAVAILABLE, AVAILABLE
|
||||
|
||||
# Because we don't have FSD 14 detection outside of a set of FW, we should check if this FW is accidentally missing from FSD_14_FW
|
||||
# 1. If in Autosteer or FSD, already caught by invalidLkasSetting
|
||||
# 2. If in TACC and DAS ever sends ANGLE_CONTROL (1), we can infer it's trying to do LKAS on FSD 14+
|
||||
# NOTE: Tesla's latest firmware changed ELDA (Emergency Lane Departure Assist) to use ANGLE_CONTROL (1)
|
||||
# instead of EMERGENCY_LANE_KEEP (3). Exclude ELDA by checking eac_status so it doesn't latch suspected_fsd14.
|
||||
eac_is_emergency = eac_status == "EMERGENCY_LANE_KEEP"
|
||||
angle_control = cp_ap_party.vl["DAS_steeringControl"]["DAS_steeringControlType"] == 1 and not eac_is_emergency # ANGLE_CONTROL, excluding ELDA
|
||||
if not ret.invalidLkasSetting and angle_control and not self.CP.flags & TeslaFlags.FSD_14:
|
||||
self.suspected_fsd14 = True
|
||||
self.suspected_fsd14_clear_frames = 0
|
||||
|
||||
if self.suspected_fsd14:
|
||||
ret.invalidLkasSetting = True
|
||||
if not self.fsd14_error_logged:
|
||||
carlog.error("FSD 14 detected, but FW not in FSD_14_FW set")
|
||||
self.fsd14_error_logged = True
|
||||
# Un-latch if ANGLE_CONTROL has been absent for ~3 s (100 frames @ ~33 Hz).
|
||||
# This allows re-engagement after transient triggers (e.g. if ELDA slips through on new FW variants).
|
||||
if not angle_control:
|
||||
self.suspected_fsd14_clear_frames += 1
|
||||
if self.suspected_fsd14_clear_frames >= 100:
|
||||
self.suspected_fsd14 = False
|
||||
self.suspected_fsd14_clear_frames = 0
|
||||
else:
|
||||
self.suspected_fsd14_clear_frames = 0
|
||||
|
||||
# Buttons # ToDo: add Gap adjust button
|
||||
|
||||
# Messages needed by carcontroller
|
||||
self.das_control = copy.copy(cp_ap_party.vl["DAS_control"])
|
||||
|
||||
# Raw stock DAS_bodyControls bytes (bus 2), used to ride the blinker on the vehicle bus.
|
||||
# FIXME: gate by FingerPrint
|
||||
if TESLA_BLINKERS and Bus.cam in can_parsers:
|
||||
self.das_body_controls_dat = bytes(can_parsers[Bus.cam].dat.get(0x3E9, b""))
|
||||
|
||||
CarStateExt.update(self, ret, ret_iq, can_parsers)
|
||||
if ret.odometer > 0.0:
|
||||
ret.odometer = self._odometer_store.record(ret.odometer) or 0.0
|
||||
|
||||
return ret, ret_iq
|
||||
|
||||
@staticmethod
|
||||
def get_can_parsers(CP, CP_IQ):
|
||||
return {
|
||||
parsers = {
|
||||
Bus.party: CANParser(DBC[CP.carFingerprint][Bus.party], [], CANBUS.party),
|
||||
Bus.ap_party: CANParser(DBC[CP.carFingerprint][Bus.party], [], CANBUS.autopilot_party),
|
||||
**CarStateExt.get_parser(CP, CP_IQ),
|
||||
}
|
||||
# Stock DAS_bodyControls from the AP bus (bus 2) for the nav blinker.
|
||||
if TESLA_BLINKERS and CP_IQ.flags & TeslaFlagsIQ.HAS_VEHICLE_BUS and Bus.adas in DBC[CP.carFingerprint]:
|
||||
parsers[Bus.cam] = CANParser(DBC[CP.carFingerprint][Bus.adas], [("DAS_bodyControls", 2)], CANBUS.autopilot_party)
|
||||
return parsers
|
||||
|
||||
@@ -2,7 +2,7 @@ from iqdbc.car import Bus, get_safety_config, structs
|
||||
from iqdbc.car.interfaces import CarInterfaceBase
|
||||
from iqdbc.car.tesla.carcontroller import CarController
|
||||
from iqdbc.car.tesla.carstate import CarState
|
||||
from iqdbc.car.tesla.values import TeslaSafetyFlags, TeslaFlags, CANBUS, CAR, DBC, FSD_14_FW, Ecu
|
||||
from iqdbc.car.tesla.values import TeslaSafetyFlags, TeslaFlags, CANBUS, CAR, DBC, LEGACY_DAS_STEERING_FW, Ecu
|
||||
from iqdbc.car.tesla.radar_interface import RadarInterface, RADAR_START_ADDR
|
||||
|
||||
from iqdbc.iqpilot.car.tesla.values import TeslaFlagsIQ, TeslaSafetyFlagsIQ
|
||||
@@ -41,14 +41,10 @@ class CarInterface(CarInterfaceBase):
|
||||
ret.openpilotLongitudinalControl = True
|
||||
ret.safetyConfigs[0].safetyParam |= TeslaSafetyFlags.LONG_CONTROL.value
|
||||
|
||||
ret.vEgoStopping = 0.1
|
||||
ret.vEgoStarting = 0.1
|
||||
ret.stoppingDecelRate = 0.3
|
||||
|
||||
fsd_14 = any(fw.ecu == Ecu.eps and fw.fwVersion in FSD_14_FW.get(candidate, []) for fw in car_fw)
|
||||
if fsd_14:
|
||||
ret.flags |= TeslaFlags.FSD_14.value
|
||||
ret.safetyConfigs[0].safetyParam |= TeslaSafetyFlags.FSD_14.value
|
||||
legacy_das = any(fw.ecu == Ecu.eps and fw.fwVersion in LEGACY_DAS_STEERING_FW.get(candidate, []) for fw in car_fw)
|
||||
if legacy_das:
|
||||
ret.flags |= TeslaFlags.LEGACY_DAS_STEERING.value
|
||||
ret.safetyConfigs[0].safetyParam |= TeslaSafetyFlags.LEGACY_DAS_STEERING.value
|
||||
|
||||
ret.dashcamOnly = candidate in (CAR.TESLA_MODEL_X,) # dashcam only, pending find invalidLkasSetting signal
|
||||
|
||||
@@ -63,7 +59,10 @@ class CarInterface(CarInterfaceBase):
|
||||
if candidate == CAR.TESLA_MODEL_X:
|
||||
stock_cp.dashcamOnly = False
|
||||
|
||||
if 0x3DF in fingerprint[1]:
|
||||
# Vehicle-bus messages can be slow enough to miss the initial capture window.
|
||||
# Accept either the established 0x3DF marker or the absolute odometer frame.
|
||||
vehicle_bus_seen = any(0x3DF in bus or 0x3B6 in bus for bus in fingerprint.values())
|
||||
if vehicle_bus_seen:
|
||||
ret.flags |= TeslaFlagsIQ.HAS_VEHICLE_BUS.value
|
||||
ret.iqSafetyFlags |= TeslaSafetyFlagsIQ.HAS_VEHICLE_BUS
|
||||
|
||||
|
||||
@@ -3,14 +3,6 @@ from iqdbc.car.tesla.values import CANBUS, CarControllerParams, TeslaFlags
|
||||
from iqdbc.car import DT_CTRL
|
||||
|
||||
|
||||
def get_steer_ctrl_type(flags: int, ctrl_type: int) -> int:
|
||||
# Returns the flipped signal value for DAS_steeringControlType on FSD 14
|
||||
if flags & TeslaFlags.FSD_14:
|
||||
return {1: 2, 2: 1}.get(ctrl_type, ctrl_type)
|
||||
else:
|
||||
return ctrl_type
|
||||
|
||||
|
||||
class TeslaCAN:
|
||||
def __init__(self, CP, packer):
|
||||
self.CP = CP
|
||||
@@ -18,14 +10,15 @@ class TeslaCAN:
|
||||
self.l_jerk = 0.0
|
||||
|
||||
def create_steering_control(self, angle, enabled, control_type):
|
||||
# On FSD 14+, ANGLE_CONTROL behavior changed to allow user winddown while actuating.
|
||||
# with openpilot, after overriding w/ ANGLE_CONTROL the wheel snaps back to the original angle abruptly
|
||||
# so we now use LANE_KEEP_ASSIST to match stock FSD.
|
||||
# see carstate.py for more details
|
||||
# control_type comes from coop_steering: ANGLE_CONTROL (1) normally, LANE_KEEP_ASSIST (2) when cooperative steering is enabled
|
||||
control_type = control_type if enabled else 0
|
||||
if self.CP.flags & TeslaFlags.LEGACY_DAS_STEERING:
|
||||
control_type <<= 1 # legacy firmware uses a 2-bit field, one bit up from the 3-bit signal
|
||||
|
||||
values = {
|
||||
"DAS_steeringAngleRequest": -angle,
|
||||
"DAS_steeringHapticRequest": 0,
|
||||
"DAS_steeringControlType": get_steer_ctrl_type(self.CP.flags, control_type if enabled else 0),
|
||||
"DAS_steeringControlType": control_type,
|
||||
}
|
||||
|
||||
return self.packer.make_can_msg("DAS_steeringControl", CANBUS.party, values)
|
||||
@@ -60,6 +53,32 @@ class TeslaCAN:
|
||||
|
||||
return self.packer.make_can_msg("APS_eacMonitor", CANBUS.party, values)
|
||||
|
||||
def create_body_controls(self, stock_dat, left_blinker, right_blinker, cancel=False):
|
||||
# Ride alongside the car's native DAS_bodyControls: copy the raw frame, override only the
|
||||
# turn-indicator bits, and stamp counter + 1 so our frame supersedes the stock one.
|
||||
dat = bytearray(stock_dat)
|
||||
if len(dat) < 8:
|
||||
dat.extend(b"\x00" * (8 - len(dat)))
|
||||
|
||||
if left_blinker or right_blinker:
|
||||
turn_req = 1 if left_blinker else 2 # DAS_TURN_INDICATOR_LEFT / _RIGHT
|
||||
dat[1] = (dat[1] & ~0x07) | (turn_req & 0x07)
|
||||
dat[2] = (dat[2] & ~0x3C) | (1 << 2) # DAS_ACTIVE_NAV_LANE_CHANGE
|
||||
elif cancel:
|
||||
dat[1] = (dat[1] & ~0x07) | 0x03 # DAS_TURN_INDICATOR_CANCEL
|
||||
dat[2] = (dat[2] & ~0x3C) | (4 << 2) # DAS_CANCEL_LANE_CHANGE
|
||||
|
||||
counter = (((dat[6] >> 4) + 1) & 0x0F)
|
||||
dat[6] = (dat[6] & ~0xF0) | (counter << 4)
|
||||
|
||||
addr = 0x3E9
|
||||
checksum = (addr & 0xFF) + ((addr >> 8) & 0xFF)
|
||||
for i in range(7):
|
||||
checksum += dat[i]
|
||||
dat[7] = checksum & 0xFF
|
||||
|
||||
return addr, bytes(dat), CANBUS.vehicle
|
||||
|
||||
|
||||
def tesla_checksum(address: int, sig, d: bytearray) -> int:
|
||||
checksum = (address & 0xFF) + ((address >> 8) & 0xFF)
|
||||
|
||||
@@ -4,6 +4,7 @@ from iqdbc.car.tesla.teslacan import TeslaCAN
|
||||
from iqdbc.car.tesla.radar_interface import RADAR_START_ADDR
|
||||
from iqdbc.car.tesla.carcontroller import CarController
|
||||
from iqdbc.car.tesla.values import CAR
|
||||
from iqdbc.can import CANPacker, CANParser
|
||||
|
||||
|
||||
class TestTeslaFingerprint:
|
||||
@@ -31,6 +32,19 @@ class TestTeslaCan:
|
||||
def make_can_msg(self, name, bus, values):
|
||||
return name, bus, values
|
||||
|
||||
def test_vehicle_bus_odometer_decodes_kilometers(self):
|
||||
packer = CANPacker("tesla_model3_vehicle")
|
||||
parser = CANParser("tesla_model3_vehicle", [("ID3B6UI_odometer", 1)], 1)
|
||||
|
||||
message = packer.make_can_msg("ID3B6UI_odometer", 1, {
|
||||
"UI_odometer": 29150.377,
|
||||
"UI_odometerCounter": 1,
|
||||
"UI_odometerChecksum": 0,
|
||||
})
|
||||
parser.update([1_000_000_000, [message]])
|
||||
|
||||
assert parser.vl["ID3B6UI_odometer"]["UI_odometer"] == 29150.377
|
||||
|
||||
def test_longitudinal_command_does_not_reference_missing_jerk_attr(self):
|
||||
CP = CarInterface.get_non_essential_params(CAR.TESLA_MODEL_3)
|
||||
tesla_can = TeslaCAN(CP, self.DummyPacker())
|
||||
|
||||
@@ -79,16 +79,41 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
||||
]
|
||||
)
|
||||
|
||||
# Cars with this EPS FW have FSD 14 and use TeslaFlags.FSD_14
|
||||
FSD_14_FW = {
|
||||
# Cars with this EPS FW have a 2-bit DAS_steeringControlType and use TeslaFlags.LEGACY_DAS_STEERING
|
||||
LEGACY_DAS_STEERING_FW = {
|
||||
CAR.TESLA_MODEL_3: [
|
||||
b'TeMYG4_Main_0.0.0 (77),E4HP015.04.5',
|
||||
b'TeMYG4_Main_0.0.0 (78),E4HP015.05.0',
|
||||
b'TeM3_E014p10_0.0.0 (16),E014.17.00',
|
||||
b'TeM3_E014p10_0.0.0 (16),EL014.17.00',
|
||||
b'TeM3_ES014p11_0.0.0 (25),ES014.19.0',
|
||||
b'TeMYG4_DCS_Update_0.0.0 (13),E4014.28.1',
|
||||
b'TeMYG4_DCS_Update_0.0.0 (9),E4014.26.0',
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (2),E4015.02.0',
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (5),E4015.03.2',
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (5),E4L015.03.2',
|
||||
b'TeMYG4_Main_0.0.0 (59),E4H014.29.0',
|
||||
b'TeMYG4_Main_0.0.0 (65),E4H015.01.0',
|
||||
b'TeMYG4_Main_0.0.0 (67),E4H015.02.1',
|
||||
b'TeMYG4_SingleECU_0.0.0 (33),E4S014.27',
|
||||
],
|
||||
CAR.TESLA_MODEL_Y: [
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (6),Y4003.04.0',
|
||||
b'TeMYG4_Main_0.0.0 (77),Y4003.05.4',
|
||||
]
|
||||
b'TeM3_E014p10_0.0.0 (16),Y002.18.00',
|
||||
b'TeM3_E014p10_0.0.0 (16),YP002.18.00',
|
||||
b'TeM3_ES014p11_0.0.0 (16),YS002.17',
|
||||
b'TeM3_ES014p11_0.0.0 (25),YS002.19.0',
|
||||
b'TeMYG4_DCS_Update_0.0.0 (13),Y4002.27.1',
|
||||
b'TeMYG4_DCS_Update_0.0.0 (13),Y4P002.27.1',
|
||||
b'TeMYG4_DCS_Update_0.0.0 (9),Y4P002.25.0',
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (2),Y4003.02.0',
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (2),Y4P003.02.0',
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (5),Y4003.03.2',
|
||||
b'TeMYG4_Legacy3Y_0.0.0 (5),Y4P003.03.2',
|
||||
b'TeMYG4_SingleECU_0.0.0 (28),Y4S002.23.0',
|
||||
b'TeMYG4_SingleECU_0.0.0 (33),Y4S002.26',
|
||||
],
|
||||
CAR.TESLA_MODEL_X: [
|
||||
b'TeM3_SP_XP002p2_0.0.0 (23),XPR003.6.0',
|
||||
b'TeM3_SP_XP002p2_0.0.0 (36),XPR003.10.0',
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
@@ -139,12 +164,12 @@ class CarControllerParams:
|
||||
|
||||
class TeslaSafetyFlags(IntFlag):
|
||||
LONG_CONTROL = 1
|
||||
FSD_14 = 2
|
||||
LEGACY_DAS_STEERING = 2
|
||||
|
||||
|
||||
class TeslaFlags(IntFlag):
|
||||
LONG_CONTROL = 1
|
||||
FSD_14 = 2
|
||||
LEGACY_DAS_STEERING = 2
|
||||
MISSING_DAS_SETTINGS = 4
|
||||
|
||||
|
||||
|
||||
@@ -301,7 +301,8 @@ routes = [
|
||||
CarTestRoute("578742b26807f756|00000010--41ee3e5bec", VOLKSWAGEN.VOLKSWAGEN_JETTA_MK6),
|
||||
CarTestRoute("58a7d3b707987d65/2021-03-25--17-26-37", VOLKSWAGEN.VOLKSWAGEN_JETTA_MK7),
|
||||
CarTestRoute("4d134e099430fba2/2021-03-26--00-26-06", VOLKSWAGEN.VOLKSWAGEN_PASSAT_MK8),
|
||||
CarTestRoute("3cfdec54aa035f3f/2022-07-19--23-45-10", VOLKSWAGEN.VOLKSWAGEN_PASSAT_NMS),
|
||||
CarTestRoute("b29ee8c5a0a735d1|000000dc--a384e9083e", VOLKSWAGEN.VOLKSWAGEN_PASSAT_NMS, segment=0),
|
||||
CarTestRoute("0f53129ed44f6920|00000287--3efbddeb96", VOLKSWAGEN.VOLKSWAGEN_PASSAT_NMS, segment=0),
|
||||
CarTestRoute("0cd0b7f7e31a3853/2021-11-03--19-30-22", VOLKSWAGEN.VOLKSWAGEN_POLO_MK6),
|
||||
CarTestRoute("064d1816e448f8eb/2022-09-29--15-32-34", VOLKSWAGEN.VOLKSWAGEN_SHARAN_MK2),
|
||||
CarTestRoute("7d82b2f3a9115f1f/2021-10-21--15-39-42", VOLKSWAGEN.VOLKSWAGEN_TAOS_MK1),
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Real-CAN replay invariant tests for VW torque platforms (PQ / MQB / MLB).
|
||||
|
||||
Replays real konn3kt routes through the car interface with openpilot lateral
|
||||
INACTIVE (latActive=False) and asserts openpilot never transmits an active-steering
|
||||
HCA command (active status or non-zero torque). Re-transmitting the stock camera's
|
||||
active HCA while not in control (stock-LKAS forwarding) leaves the EPS faulted for
|
||||
the whole drive (LH2_Sta_HCA=FAULT) - the regression that bricked steering on a PQ
|
||||
Passat NMS with a factory LKAS camera. Panda accepts these frames, so only a replay
|
||||
invariant like this catches it.
|
||||
|
||||
Self-contained within iqdbc: routes are resolved through konn3kt's public
|
||||
/v1/route/<id>/files endpoint (URLs are signed server-side, no auth/token needed).
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
from collections import Counter
|
||||
|
||||
import pytest
|
||||
|
||||
from iqdbc.can.parser import CANParser
|
||||
from iqdbc.car import Bus, structs
|
||||
from iqdbc.car.can_definitions import CanData
|
||||
from iqdbc.car.car_helpers import can_fingerprint, interfaces
|
||||
from iqdbc.car.logreader import LogReader
|
||||
from iqdbc.car.volkswagen.values import CAR, DBC, VolkswagenFlags
|
||||
|
||||
API_HOST = os.environ.get("API_HOST", "https://api-iqlabs.konn3kt.com")
|
||||
|
||||
# konn3kt-hosted VW routes. (route_id, segment, platform, label)
|
||||
# Add MQB routes here as konn3kt-hosted MQB logs become available.
|
||||
VW_ROUTES = [
|
||||
("b29ee8c5a0a735d1|000000dc--a384e9083e", 0, CAR.VOLKSWAGEN_PASSAT_NMS, "PQ with stock LKAS camera"),
|
||||
("0f53129ed44f6920|00000287--3efbddeb96", 0, CAR.VOLKSWAGEN_PASSAT_NMS, "PQ without stock LKAS camera"),
|
||||
]
|
||||
|
||||
# Per-platform HCA message: (address, msg, status signal, torque signal, active-status values)
|
||||
HCA_INFO = {
|
||||
"pq": (0xD2, "HCA_1", "HCA_Status", "LM_Offset", (5, 7)),
|
||||
"mqb": (0x126, "HCA_01", "HCA_01_Status_HCA", "HCA_01_LM_Offset", (5, 6, 7)),
|
||||
}
|
||||
|
||||
|
||||
def _request_headers() -> dict[str, str]:
|
||||
# konn3kt's edge rejects the default urllib User-Agent with 403. The routes are public
|
||||
# (access returns early for public routes), but IQ.Pilot/Cabana tooling conventionally
|
||||
# sends a Konn3kt user JWT, so include one when available (env or ~/.comma/auth.json).
|
||||
headers = {"User-Agent": "iqdbc"}
|
||||
token = os.environ.get("KONN3KT_ACCESS_TOKEN")
|
||||
if not token:
|
||||
try:
|
||||
with open(os.path.expanduser("~/.comma/auth.json")) as f:
|
||||
token = json.load(f).get("access_token")
|
||||
except (OSError, ValueError):
|
||||
token = None
|
||||
if token:
|
||||
headers["Authorization"] = f"JWT {token}"
|
||||
return headers
|
||||
|
||||
|
||||
def _rlog_url(route_id: str, segment: int) -> str:
|
||||
req = urllib.request.Request(f"{API_HOST}/v1/route/{urllib.parse.quote(route_id, safe='|')}/files",
|
||||
headers=_request_headers())
|
||||
with urllib.request.urlopen(req, timeout=30) as f:
|
||||
files = json.load(f)
|
||||
for url in files.get("logs", []):
|
||||
# path looks like /connectdata/<dongle>/<log>/<seg>/rlog.zst
|
||||
parts = urllib.parse.urlparse(url).path.rstrip("/").split("/")
|
||||
if len(parts) >= 2 and parts[-2] == str(segment):
|
||||
return url
|
||||
raise RuntimeError(f"no rlog for {route_id} segment {segment} (uploaded & public?)")
|
||||
|
||||
|
||||
def _load_can(route_id: str, segment: int):
|
||||
lr = LogReader(_rlog_url(route_id, segment), only_union_types=True, sort_by_time=True)
|
||||
return [(m.logMonoTime, [CanData(c.address, c.dat, c.src) for c in m.can]) for m in lr if m.which() == "can"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("route_id,segment,platform,label", VW_ROUTES)
|
||||
def test_vw_inactive_steering_invariant(route_id, segment, platform, label):
|
||||
can_msgs = _load_can(route_id, segment)
|
||||
assert len(can_msgs) > 1000, f"insufficient CAN data for {label}: {len(can_msgs)} frames"
|
||||
|
||||
# fingerprint from a fresh iterator over the (unmutated) frame list
|
||||
frame_iter = (frames for _, frames in can_msgs)
|
||||
def can_recv(wait_for_one: bool = False):
|
||||
return [next(frame_iter, [])]
|
||||
_, fingerprint = can_fingerprint(can_recv)
|
||||
|
||||
CarInterface = interfaces[platform]
|
||||
CP = CarInterface.get_params(platform, fingerprint, [], False, False, False)
|
||||
CP_IQ = CarInterface.get_params_iq(CP, platform, fingerprint, [], False, False, False)
|
||||
|
||||
if CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
pytest.skip("invariant covers torque-based VW platforms (PQ/MQB/MLB)")
|
||||
|
||||
key = "pq" if CP.flags & VolkswagenFlags.PQ else "mqb"
|
||||
hca_addr, hca_msg, status_sig, torque_sig, active_status = HCA_INFO[key]
|
||||
cp = CANParser(DBC[platform][Bus.pt], [(hca_msg, 0)], 0)
|
||||
|
||||
CI = CarInterface(CP, CP_IQ)
|
||||
CC = structs.CarControl().as_reader() # latActive defaults to False
|
||||
CC_IQ = structs.IQCarControl()
|
||||
|
||||
hca_seen = 0
|
||||
violations = Counter()
|
||||
for i, (mono, frames) in enumerate(can_msgs):
|
||||
CI.update([(mono, frames)])
|
||||
_, sendcan = CI.apply(CC, CC_IQ, mono)
|
||||
|
||||
if i < 300: # CarController / CANParser warmup
|
||||
continue
|
||||
|
||||
for addr, dat, bus in sendcan:
|
||||
if addr != hca_addr or bus != 0:
|
||||
continue
|
||||
hca_seen += 1
|
||||
cp.update([(mono, [(addr, bytes(dat), 0)])])
|
||||
if int(cp.vl[hca_msg][status_sig]) in active_status:
|
||||
violations["active_status"] += 1
|
||||
if abs(cp.vl[hca_msg][torque_sig]) > 0:
|
||||
violations["nonzero_torque"] += 1
|
||||
|
||||
assert hca_seen > 50, f"{label}: no HCA steering messages transmitted to inspect"
|
||||
assert not len(violations), \
|
||||
f"{label}: openpilot TX'd active HCA while latActive=False: {dict(violations)}"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
sys.exit(pytest.main([__file__, "-v"]))
|
||||
@@ -67,6 +67,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"VOLKSWAGEN_CADDY_MK3" = [1.2, 1.2, 0.1]
|
||||
"VOLKSWAGEN_PASSAT_NMS" = [2.5, 2.5, 0.1]
|
||||
"VOLKSWAGEN_SHARAN_MK2" = [2.5, 2.5, 0.1]
|
||||
"SEAT_ALHAMBRA_MK1" = [2.5, 2.5, 0.1]
|
||||
"HYUNDAI_SANTA_CRUZ_1ST_GEN" = [2.7, 2.7, 0.1]
|
||||
"KIA_SPORTAGE_5TH_GEN" = [2.6, 2.6, 0.1]
|
||||
"GENESIS_GV70_1ST_GEN" = [2.42, 2.42, 0.1]
|
||||
|
||||
@@ -76,6 +76,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
|
||||
"VOLKSWAGEN_JETTA_MK6" = "VOLKSWAGEN_PASSAT_NMS"
|
||||
"VOLKSWAGEN_PASSAT_MK7" = "VOLKSWAGEN_PASSAT_NMS"
|
||||
"VOLKSWAGEN_PASSAT_NMS_PLUS" = "VOLKSWAGEN_PASSAT_NMS"
|
||||
"VOLKSWAGEN_PASSAT_B7" = "VOLKSWAGEN_PASSAT_NMS"
|
||||
|
||||
"SUBARU_CROSSTREK_HYBRID" = "SUBARU_IMPREZA_2020"
|
||||
"SUBARU_FORESTER_HYBRID" = "SUBARU_IMPREZA_2020"
|
||||
|
||||
@@ -260,6 +260,7 @@ class CarController(CarControllerBase, GasInterceptorCarController):
|
||||
freeze_integrator=actuators.longControlState != LongCtrlState.pid)
|
||||
else:
|
||||
self.long_pid.reset()
|
||||
pcm_accel_cmd = 0.
|
||||
|
||||
# Along with rate limiting positive jerk above, this greatly improves gas response time
|
||||
# Consider the net acceleration request that the PCM should be applying (pitch included)
|
||||
@@ -269,7 +270,9 @@ class CarController(CarControllerBase, GasInterceptorCarController):
|
||||
elif net_acceleration_request_min > 0.3:
|
||||
self.permit_braking = False
|
||||
|
||||
pcm_accel_cmd = pcm_accel_cmd if self.CP.carFingerprint in TSS2_CAR else actuators.accel
|
||||
sdsu_tssp_long_active = bool(self.CP_IQ.flags & ToyotaFlagsIQ.SMART_DSU) and \
|
||||
(self.CP.carFingerprint not in TSS2_CAR) and CC.longActive
|
||||
pcm_accel_cmd = actuators.accel if sdsu_tssp_long_active else pcm_accel_cmd
|
||||
pcm_accel_cmd = float(np.clip(pcm_accel_cmd, self.params.ACCEL_MIN, self.params.ACCEL_MAX))
|
||||
|
||||
main_accel_cmd = 0. if self.CP.flags & ToyotaFlags.SECOC.value else pcm_accel_cmd
|
||||
|
||||
@@ -36,7 +36,6 @@ class CarInterface(CarInterfaceBase):
|
||||
if ret.flags & ToyotaFlags.SECOC.value:
|
||||
ret.secOcRequired = True
|
||||
ret.safetyConfigs[0].safetyParam |= ToyotaSafetyFlags.SECOC.value
|
||||
ret.dashcamOnly = is_release
|
||||
|
||||
if candidate in ANGLE_CONTROL_CAR:
|
||||
ret.steerControlType = SteerControlType.angle
|
||||
@@ -119,10 +118,6 @@ class CarInterface(CarInterfaceBase):
|
||||
if candidate in TSS2_CAR:
|
||||
ret.flags |= ToyotaFlags.RAISED_ACCEL_LIMIT.value
|
||||
|
||||
ret.vEgoStopping = 0.25
|
||||
ret.vEgoStarting = 0.25
|
||||
ret.stoppingDecelRate = 0.3 # reach stopping target smoothly
|
||||
|
||||
# Hybrids have much quicker longitudinal actuator response
|
||||
if ret.flags & ToyotaFlags.HYBRID.value:
|
||||
ret.longitudinalActuatorDelay = 0.05
|
||||
@@ -132,9 +127,6 @@ 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:
|
||||
if stock_cp.flags & ToyotaFlags.SECOC.value and stock_cp.fingerprintSource == structs.CarParams.FingerprintSource.fixed:
|
||||
stock_cp.dashcamOnly = False
|
||||
|
||||
if candidate in UNSUPPORTED_DSU_CAR:
|
||||
ret.iqSafetyFlags |= ToyotaSafetyFlagsIQ.UNSUPPORTED_DSU
|
||||
|
||||
|
||||
@@ -4,26 +4,20 @@ from iqdbc.car.toyota.values import CAR, ToyotaFlags
|
||||
from iqdbc.iqpilot.car.toyota.values import ToyotaFlagsIQ
|
||||
|
||||
|
||||
def test_forced_secoc_toyota_clears_dashcam_mode():
|
||||
def test_secoc_toyota_not_dashcam_on_release():
|
||||
# SecOC Toyotas are controllable regardless of branch or fingerprint source.
|
||||
candidate = CAR.TOYOTA_SIENNA_4TH_GEN
|
||||
|
||||
# is_release=True (release branch) must not force dashcam mode
|
||||
cp = CarInterface.get_params(candidate, gen_empty_fingerprint(), [], False, True, False)
|
||||
assert cp.dashcamOnly
|
||||
|
||||
cp.fingerprintSource = structs.CarParams.FingerprintSource.fixed
|
||||
CarInterface.get_params_iq(cp, candidate, gen_empty_fingerprint(), [], False, True, False)
|
||||
|
||||
assert cp.flags & ToyotaFlags.SECOC.value
|
||||
assert cp.secOcRequired
|
||||
assert not cp.dashcamOnly
|
||||
|
||||
|
||||
def test_automatic_secoc_toyota_release_stays_dashcam():
|
||||
candidate = CAR.TOYOTA_SIENNA_4TH_GEN
|
||||
cp = CarInterface.get_params(candidate, gen_empty_fingerprint(), [], False, True, False)
|
||||
assert cp.dashcamOnly
|
||||
|
||||
# fw/can-sourced fingerprint (not forced) must also stay controllable
|
||||
cp.fingerprintSource = structs.CarParams.FingerprintSource.can
|
||||
CarInterface.get_params_iq(cp, candidate, gen_empty_fingerprint(), [], False, True, False)
|
||||
|
||||
assert cp.dashcamOnly
|
||||
assert not cp.dashcamOnly
|
||||
|
||||
|
||||
def test_smart_dsu_clears_disable_radar_on_radar_acc_toyota():
|
||||
|
||||
@@ -14,10 +14,16 @@ from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car.common.numpy_fast import clip, interp
|
||||
from iqdbc.car.interfaces import CarControllerBase
|
||||
from iqdbc.car.volkswagen import mlbcan, mqbcan, pqcan, mebcan
|
||||
from iqdbc.car.volkswagen.values import CanBus, CarControllerParams, VolkswagenFlags, VolkswagenFlagsIQ
|
||||
from iqdbc.car.volkswagen.pq_radar_handler import PQRadarHandler
|
||||
from iqdbc.car.volkswagen.values import (
|
||||
CanBus, CarControllerParams, MQB_A0_CARS, VolkswagenFlags, VolkswagenFlagsIQ, apply_pq_stopping_accel,
|
||||
)
|
||||
from iqdbc.car.volkswagen.mebutils import LongControlJerk, LongControlLimit, LatControlCurvature
|
||||
from iqdbc.car.vehicle_model import VehicleModel
|
||||
from openpilot.iqpilot.konn3kt.iqlvbs import alc as iq_lvbs_alc
|
||||
from openpilot.system.proprietary_runtime._verified_import import import_verified_module
|
||||
|
||||
iq_lvbs_alc = import_verified_module("iqpilot_alc_private", "iqpilot_private.konn3kt.iqlvbs.alc")
|
||||
iq_lvbs_commander = import_verified_module("iqpilot_commander_private", "iqpilot_private.konn3kt.iqlvbs.iqlvbs_commander")
|
||||
|
||||
iqpilot_path = os.path.join(os.path.dirname(__file__), '..', '..', '..')
|
||||
sys.path.insert(0, iqpilot_path)
|
||||
@@ -27,9 +33,19 @@ except ImportError:
|
||||
pass
|
||||
|
||||
VisualAlert = structs.CarControl.HUDControl.VisualAlert
|
||||
AudibleAlert = structs.CarControl.HUDControl.AudibleAlert
|
||||
LongCtrlState = structs.CarControl.Actuators.LongControlState
|
||||
|
||||
|
||||
def dVisual(CCS, CS):
|
||||
if CCS == mqbcan:
|
||||
decelV = CS.tsk_verzoeg_anf
|
||||
elif CCS == pqcan:
|
||||
decelV = CS.br8_acc_anf
|
||||
else:
|
||||
decelV = False
|
||||
return decelV
|
||||
|
||||
class MQBStandstillManager:
|
||||
BRAKE_TORQUE_RAMP_RATE = 2000.0 # Nm/s
|
||||
ASSUMED_WHEEL_RADIUS = 0.328 # m, typical tire rolling radius
|
||||
@@ -176,7 +192,6 @@ class MQBStandstillManager:
|
||||
self.prev_accel = accel
|
||||
return long_active, accel, stopping, starting, esp_starting_override, esp_stopping_override
|
||||
|
||||
|
||||
class CarController(CarControllerBase):
|
||||
def __init__(self, dbc_names, CP, CP_IQ):
|
||||
super().__init__(dbc_names, CP, CP_IQ)
|
||||
@@ -185,8 +200,11 @@ class CarController(CarControllerBase):
|
||||
self.CAN = CanBus(CP)
|
||||
self.packer_pt = CANPacker(dbc_names[Bus.pt])
|
||||
|
||||
self._pt_tx_bus = self.CAN.pt
|
||||
if CP.flags & VolkswagenFlags.PQ:
|
||||
self.CCS = pqcan
|
||||
if CP.flags & VolkswagenFlagsIQ.IQ_PQ_LOWLINE:
|
||||
self._pt_tx_bus = self.CAN.aux
|
||||
elif CP.flags & VolkswagenFlags.MLB:
|
||||
self.CCS = mlbcan
|
||||
elif CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
@@ -211,13 +229,16 @@ class CarController(CarControllerBase):
|
||||
self.long_jerk_control = LongControlJerk(dt=(DT_CTRL * self.CCP.ACC_CONTROL_STEP)) if self.CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO) else None
|
||||
self.long_limit_control = LongControlLimit(dt=(DT_CTRL * self.CCP.ACC_CONTROL_STEP)) if self.CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO) else None
|
||||
self.gra_acc_counter_last = None
|
||||
self.motor3_frame_last = None
|
||||
self.motor3_was_stopping = False
|
||||
self.motor3_resuming = False
|
||||
self.sng_handoff_active = False
|
||||
self.acc_counter_seeded = False
|
||||
self.klr_counter_last = None
|
||||
self.eps_timer_soft_disable_alert = False
|
||||
self.hca_frame_timer_running = 0
|
||||
self.hca_frame_same_torque = 0
|
||||
self.accel_last = 0
|
||||
self.accel_diff = 0
|
||||
self.long_deviation = 0
|
||||
self.long_jerklimit = 0
|
||||
self.HCA_Status = 3
|
||||
@@ -231,19 +252,43 @@ class CarController(CarControllerBase):
|
||||
self.radar_disabled_warning_timer = 0
|
||||
# Check once at init whether the DBC includes MEB_AWV_01 (AEB HUD for radar-disabled camera harness cars)
|
||||
self._has_aeb_hud_msg = "MEB_AWV_01" in self.packer_pt.dbc.name_to_msg
|
||||
self.eps_timer_workaround = bool(CP.flags & VolkswagenFlags.MLB)
|
||||
self.eps_timer_workaround = bool(CP.flags & (VolkswagenFlags.MLB | VolkswagenFlagsIQ.IQ_PQ_TIMEBOMB))
|
||||
self._pq_patch_checked = not bool(CP.flags & VolkswagenFlags.PQ) or self.eps_timer_workaround
|
||||
self.hca_frame_timer_resetting = 0
|
||||
self.hca_frame_low_torque = 0
|
||||
self.long_override_counter = 0
|
||||
self.long_disabled_counter = 0
|
||||
self.standstill_manager = MQBStandstillManager(CP.mass, self.CCP.ACCEL_MIN) if self.CCS == mqbcan else None
|
||||
self.radar_handler = PQRadarHandler(self.CAN) if self.CCS is pqcan else None
|
||||
self.blend_stock_radar = False
|
||||
self.unavailable = False
|
||||
self.unavailable_hold = 0
|
||||
self.VM = VehicleModel(CP)
|
||||
self.is_mqb_a0 = self._is_mqb_a0_car(CP.carFingerprint)
|
||||
self.LateralController = (
|
||||
LatControlCurvature(self.CCP.CURVATURE_PID, self.CCP.CURVATURE_LIMITS.CURVATURE_MAX, 1 / (DT_CTRL * self.CCP.STEER_STEP))
|
||||
if (CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO))
|
||||
else None
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _is_mqb_a0_car(candidate) -> bool:
|
||||
return candidate in MQB_A0_CARS
|
||||
|
||||
def _get_mqb_steering_torque_scale(self, v_ego: float, enabled: bool) -> float:
|
||||
if enabled and self.CCS == mqbcan:
|
||||
return float(np.interp(v_ego, [0.4, 3.5, 4.0], [0.8, 0.95, 1.0]))
|
||||
return 1.0
|
||||
|
||||
def _should_spam_mqb_a0_resume(self, CS, enabled: bool) -> bool:
|
||||
return bool(
|
||||
enabled and
|
||||
self.is_mqb_a0 and
|
||||
self.CCS == mqbcan and
|
||||
CS.out.standstill and
|
||||
self.frame % 50 < 15
|
||||
)
|
||||
|
||||
def update(self, CC, CC_IQ, CS, now_nanos):
|
||||
actuators = CC.actuators
|
||||
hud_control = CC.hudControl
|
||||
@@ -252,10 +297,23 @@ class CarController(CarControllerBase):
|
||||
apply_torque = 0
|
||||
pqhca5or7Toggle = self._params.get_bool("pqhca5or7Toggle")
|
||||
eBrakeActive = self._params.get_bool("eBrakeActive")
|
||||
iq_mqb_steering_lockout = self._params.get_bool("iqMqbSteeringLockout")
|
||||
iq_mqb_acc_resume = self._params.get_bool("iqMqbAccResume")
|
||||
self.blend_stock_radar = self._params.get_bool("IQDynamicBlendStockRadar")
|
||||
if not self._pq_patch_checked:
|
||||
self._pq_patch_checked = True
|
||||
self.eps_timer_workaround = not self._params.get_bool("VwPqEpsPatched")
|
||||
blend_active = bool(self.blend_stock_radar and self.radar_handler is not None and self.CP.openpilotLongitudinalControl)
|
||||
AngleLateralControl = iq_lvbs_alc.angle_lateral_control_enabled(self, CS)
|
||||
self.entering = CS.vw_iq_lvbs_alc_entering
|
||||
self.active = CS.vw_iq_lvbs_alc_active
|
||||
|
||||
if hud_control.audibleAlert == AudibleAlert.refuse:
|
||||
self.unavailable_hold = self.CCP.IQ_PQ_UNAVAILABLE_HUD_FRAMES
|
||||
else:
|
||||
self.unavailable_hold = max(0, self.unavailable_hold - 1)
|
||||
self.unavailable = self.unavailable_hold > 0
|
||||
|
||||
CS.force_rhd_for_bsm = getattr(CC, "forceRHDForBSM", False)
|
||||
CS.enable_predicative_speed_limit = getattr(CC.cruiseControl, "speedLimitPredicative", False)
|
||||
CS.enable_pred_react_to_speed_limits = getattr(CC.cruiseControl, "speedLimitPredReactToSL", False)
|
||||
@@ -296,7 +354,8 @@ class CarController(CarControllerBase):
|
||||
self.steering_power_last = steering_power
|
||||
else:
|
||||
if CC.latActive and not AngleLateralControl:
|
||||
new_torque = int(round(actuators.torque * self.CCP.STEER_MAX))
|
||||
torque_scale = self._get_mqb_steering_torque_scale(CS.out.vEgo, iq_mqb_steering_lockout)
|
||||
new_torque = int(round(actuators.torque * self.CCP.STEER_MAX * torque_scale))
|
||||
apply_torque = apply_driver_steer_torque_limits(new_torque, self.apply_torque_last, CS.out.steeringTorque, self.CCP)
|
||||
self.hca_frame_timer_running += self.CCP.STEER_STEP
|
||||
if self.apply_torque_last == apply_torque:
|
||||
@@ -341,10 +400,10 @@ class CarController(CarControllerBase):
|
||||
|
||||
self.eps_timer_soft_disable_alert = self.hca_frame_timer_running > self.CCP.STEER_TIME_ALERT / DT_CTRL
|
||||
self.apply_torque_last = apply_torque
|
||||
if not (AngleLateralControl and self.CCS in (mqbcan, pqcan)):
|
||||
can_sends.append(self.CCS.create_hca_steering_control(self.packer_pt, self.CAN.pt, output_torque, self.HCA_Status))
|
||||
if not (AngleLateralControl and self.CCS in (mqbcan, pqcan, mlbcan)):
|
||||
can_sends.append(self.CCS.create_hca_steering_control(self.packer_pt, self._pt_tx_bus, output_torque, self.HCA_Status))
|
||||
|
||||
if self.CP.flags & VolkswagenFlags.STOCK_HCA_PRESENT:
|
||||
if self.CP.flags & VolkswagenFlags.STOCK_HCA_PRESENT and self.CCS == mqbcan:
|
||||
ea_simulated_torque = float(np.clip(apply_torque * 2, -self.CCP.STEER_MAX, self.CCP.STEER_MAX))
|
||||
if abs(CS.out.steeringTorque) > abs(ea_simulated_torque):
|
||||
ea_simulated_torque = CS.out.steeringTorque
|
||||
@@ -379,7 +438,7 @@ class CarController(CarControllerBase):
|
||||
if self.frame % self.CCP.ACC_CONTROL_STEP == 0 and self.CP.openpilotLongitudinalControl and not CS.out.radarDisableFailed:
|
||||
stopping = actuators.longControlState == LongCtrlState.stopping
|
||||
if self.CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
starting = actuators.longControlState == LongCtrlState.starting and CS.out.vEgo <= self.CP.vEgoStarting
|
||||
starting = actuators.longControlState == LongCtrlState.pid and (CS.esp_hold_confirmation or CS.out.vEgo < 0.25)
|
||||
accel = float(np.clip(actuators.accel, self.CCP.ACCEL_MIN, self.CCP.ACCEL_MAX) if CC.enabled else 0)
|
||||
|
||||
long_override = CC.cruiseControl.override or CS.out.gasPressed
|
||||
@@ -409,7 +468,7 @@ class CarController(CarControllerBase):
|
||||
self.accel_last = accel
|
||||
else:
|
||||
stopping = actuators.longControlState == LongCtrlState.stopping
|
||||
starting = actuators.longControlState == LongCtrlState.pid and (CS.esp_hold_confirmation or CS.out.vEgo < self.CP.vEgoStopping)
|
||||
starting = actuators.longControlState == LongCtrlState.pid and (CS.esp_hold_confirmation or CS.out.vEgo < 0.25)
|
||||
long_active = CC.longActive
|
||||
accel = actuators.accel
|
||||
esp_starting_override = None
|
||||
@@ -424,10 +483,16 @@ class CarController(CarControllerBase):
|
||||
|
||||
acc_control = self.CCS.acc_control_value(CS.out.cruiseState.available, long_active, CC.cruiseControl.override, CS.out.accFaulted)
|
||||
accel = float(np.clip(accel, self.CCP.ACCEL_MIN, self.CCP.ACCEL_MAX) if (long_active or CC.cruiseControl.override) else 0)
|
||||
self.accel_diff = (0.0019 * (accel - self.accel_last)) + (1 - 0.0019) * self.accel_diff
|
||||
self.long_jerklimit = 3.0 # AendGrad (0.01 * (np.clip(abs(accel), 0.7, 2))) + (1 - 0.01) * self.long_jerklimit
|
||||
self.long_deviation = 0.2 # RegelAbw np.interp(abs(accel - self.accel_diff), [0, 0.3, 1.0], [0.02, 0.04, 0.08])
|
||||
self.long_jerklimit = float(interp(accel, [-1.5, -0.3, 0.05], [2.0, 0.52, 0.30]))
|
||||
self.long_deviation = float(interp(accel, [-0.3, 0.1], [0.0, 0.20]))
|
||||
self.accel_last = accel
|
||||
|
||||
if blend_active and getattr(CC_IQ, "useRadarAccel", False) and CS.acc_radar_sta_adr == 1 and not self.radar_handler.failed:
|
||||
accel = float(np.clip(CS.acc_radar_sollbeschl, self.CCP.ACCEL_MIN, self.CCP.ACCEL_MAX))
|
||||
self.long_jerklimit = CS.acc_radar_aendgrad
|
||||
self.long_deviation = CS.acc_radar_regelabw
|
||||
self.accel_last = accel
|
||||
|
||||
if self.CCS == mqbcan:
|
||||
can_sends.extend(self.CCS.create_acc_accel_control(
|
||||
self.packer_pt, self.CAN.pt, CS.acc_type, accel, acc_control, stopping, starting, CS.esp_hold_confirmation,
|
||||
@@ -435,10 +500,19 @@ class CarController(CarControllerBase):
|
||||
esp_starting_override=esp_starting_override, esp_stopping_override=esp_stopping_override,
|
||||
))
|
||||
else:
|
||||
can_sends.extend(self.CCS.create_acc_accel_control(
|
||||
self.packer_pt, self.CAN.pt, CS.acc_type, accel, acc_control, stopping, starting, CS.esp_hold_confirmation,
|
||||
self.long_deviation, self.long_jerklimit, eBrakeActive,
|
||||
))
|
||||
accel = apply_pq_stopping_accel(self.CP.carFingerprint, accel, stopping)
|
||||
|
||||
sng_ecd_enabled = bool(self.CP.flags & VolkswagenFlagsIQ.IQ_PQ_SNG_ECD)
|
||||
low_speed = CS.out.vEgo <= self.CCP.SNG_HANDOFF_SPEED
|
||||
if sng_ecd_enabled and long_active and low_speed and accel <= 0.05 and not starting:
|
||||
self.sng_handoff_active = True
|
||||
else:
|
||||
self.sng_handoff_active = False
|
||||
sng_decel_req = float(np.clip(accel, self.CCP.ACCEL_MIN, self.CCP.SNG_HOLD_DECEL_MAX)) if self.sng_handoff_active else 0.0
|
||||
|
||||
can_sends.extend(self.CCS.create_acc_accel_control(self.packer_pt, self.CAN.pt, CS.acc_type, accel, acc_control, stopping and not self.motor3_resuming, starting, CS.esp_hold_confirmation, self.long_deviation, self.long_jerklimit, eBrakeActive, sng_active=self.sng_handoff_active))
|
||||
if sng_ecd_enabled:
|
||||
can_sends.append(self.CCS.create_sng_handoff_control(self.packer_pt, self.CAN.aux, self.sng_handoff_active, sng_decel_req))
|
||||
|
||||
if (self.CP.flags & VolkswagenFlags.DISABLE_RADAR) and self.CP.openpilotLongitudinalControl and not CS.out.radarDisableFailed:
|
||||
if self.CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
@@ -468,15 +542,16 @@ class CarController(CarControllerBase):
|
||||
can_sends.append(self.CCS.create_lka_hud_control(self.packer_pt, self.CAN.pt, CS.ldw_stock_values, CC.latActive, CS.out.steeringPressed,
|
||||
hud_alert, hud_control, sound_alert))
|
||||
else:
|
||||
can_sends.append(self.CCS.create_lka_hud_control(self.packer_pt, self.CAN.pt, CS.ldw_stock_values, CC.latActive, steering_pressed_hud,
|
||||
can_sends.append(self.CCS.create_lka_hud_control(self.packer_pt, self._pt_tx_bus, CS.ldw_stock_values, CC.latActive, steering_pressed_hud,
|
||||
hud_alert, hud_control, self.entering, self.CCS is pqcan and AngleLateralControl, self.active))
|
||||
|
||||
if hud_control.leadDistanceBars != self.lead_distance_bars_last:
|
||||
self.distance_bar_frame = self.frame
|
||||
|
||||
if self.frame % self.CCP.ACC_HUD_STEP == 0 and self.CP.openpilotLongitudinalControl:
|
||||
fcw_alert = hud_control.visualAlert == VisualAlert.fcw
|
||||
d_unresponsive = hud_control.driverUnresponsive
|
||||
if self.CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
fcw_alert = hud_control.visualAlert == VisualAlert.fcw
|
||||
show_distance_bars = self.frame - self.distance_bar_frame < 400
|
||||
gap = max(8, CS.out.vEgo * hud_control.leadFollowTime)
|
||||
distance = max(8, hud_control.leadDistance) if hud_control.leadDistance != 0 else 0
|
||||
@@ -498,23 +573,29 @@ class CarController(CarControllerBase):
|
||||
CS.esp_hold_confirmation, distance, gap, fcw_alert, acc_hud_event, speed_limit))
|
||||
else:
|
||||
leadDistance = min(8, hud_control.leadDistance) if hud_control.leadDistance != 0 else 0
|
||||
fcw_alert = hud_control.visualAlert == VisualAlert.fcw
|
||||
self.leadDistanceBars = min(3, hud_control.leadDistanceBars)
|
||||
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
|
||||
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))
|
||||
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))
|
||||
|
||||
if self.CP.flags & VolkswagenFlags.PQ:
|
||||
if self.frame % 2 == 0:
|
||||
self.blinkerActive = CS.leftBlinkerUpdate or CS.rightBlinkerUpdate
|
||||
leftBlinker = CC.leftBlinker if not self.blinkerActive else False
|
||||
rightBlinker = CC.rightBlinker if not self.blinkerActive else False
|
||||
can_sends.append(self.CCS.create_blinker_control(self.packer_pt, self.CAN.pt, leftBlinker, rightBlinker))
|
||||
iq_lvbs_commander.update_turn_signals(self, CC, CS, can_sends)
|
||||
|
||||
if self.CP.openpilotLongitudinalControl and (self.CP.flags & VolkswagenFlags.PQ):
|
||||
if self.frame % 2 == 0:
|
||||
if blend_active:
|
||||
can_sends.extend(self.radar_handler.update(
|
||||
self.packer_pt, self.frame, CS,
|
||||
blend_active=True,
|
||||
engage_req=getattr(CC_IQ, "radarEngageReq", False),
|
||||
cancel_req=getattr(CC_IQ, "radarCancelReq", False),
|
||||
set_speed_kph=getattr(CC_IQ, "radarSetSpeedKph", 0.0),
|
||||
gap_bars=getattr(CC_IQ, "radarGapBars", 0),
|
||||
v_ego=CS.out.vEgo,
|
||||
))
|
||||
elif self.frame % 2 == 0:
|
||||
can_sends.append(self.CCS.filter_motor2(self.packer_pt, self.CAN.ext, CS.motor2_stock))
|
||||
can_sends.append(self.CCS.filter_motor5(self.packer_pt, self.CAN.ext, CS.motor5_stock))
|
||||
|
||||
gra_send_ready = self.CP.pcmCruise and CS.gra_stock_values["COUNTER"] != self.gra_acc_counter_last
|
||||
if self.CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
@@ -526,15 +607,25 @@ class CarController(CarControllerBase):
|
||||
stock_cancel_pressed = bool(CS.gra_stock_values["GRA_Abbrechen"])
|
||||
|
||||
cancel_cmd = stock_cancel_pressed or CC.cruiseControl.cancel
|
||||
if gra_send_ready and (cancel_cmd or CC.cruiseControl.resume):
|
||||
resume_cmd = CC.cruiseControl.resume or self._should_spam_mqb_a0_resume(CS, iq_mqb_acc_resume)
|
||||
if gra_send_ready and (cancel_cmd or resume_cmd):
|
||||
bus_send = self.CAN.aux if self.CP.flags & VolkswagenFlags.PQ else self.CAN.ext
|
||||
can_sends.append(self.CCS.create_acc_buttons_control(self.packer_pt, bus_send, CS.gra_stock_values,
|
||||
cancel=cancel_cmd, resume=CC.cruiseControl.resume))
|
||||
cancel=cancel_cmd, resume=resume_cmd))
|
||||
|
||||
if self.CP.openpilotLongitudinalControl and self.CCS == pqcan:
|
||||
if self.CP.openpilotLongitudinalControl and self.CCS == pqcan and not blend_active:
|
||||
if self.frame % 3:
|
||||
can_sends.append(self.CCS.create_gra_neu(self.packer_pt, self.CAN.ext, CS.gra_stock_values, CC.longActive))
|
||||
|
||||
if self.CP.flags & VolkswagenFlagsIQ.IQ_PQ_ACC_FTS_EPB:
|
||||
is_stopping = actuators.longControlState == LongCtrlState.stopping
|
||||
if CS.out.vEgo > 0.5 or not CC.longActive:
|
||||
self.motor3_resuming = False
|
||||
elif (self.motor3_was_stopping and not is_stopping and self.CP.openpilotLongitudinalControl and CC.longActive):
|
||||
self.motor3_resuming = True
|
||||
if self.motor3_resuming and CS.motor3_stock:
|
||||
can_sends.append(self.CCS.create_motor3_resume(self.packer_pt, self.CAN.aux, CS.motor1_stock, CS.motor3_stock, resume=True))
|
||||
self.motor3_was_stopping = is_stopping
|
||||
|
||||
new_actuators = actuators.as_builder()
|
||||
new_actuators.torque = self.apply_torque_last / self.CCP.STEER_MAX
|
||||
@@ -547,5 +638,6 @@ class CarController(CarControllerBase):
|
||||
|
||||
self.lead_distance_bars_last = hud_control.leadDistanceBars
|
||||
self.gra_acc_counter_last = CS.gra_stock_values["COUNTER"]
|
||||
self.motor3_frame_last = CS.motor3_frame
|
||||
self.frame += 1
|
||||
return new_actuators, can_sends
|
||||
|
||||
@@ -12,7 +12,10 @@ from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car.volkswagen.values import CAR, DBC, CanBus, NetworkLocation, RADAR_DISABLE_STATE, TransmissionType, GearShifter, \
|
||||
CarControllerParams, VolkswagenFlags, VolkswagenFlagsIQ
|
||||
from iqdbc.car.volkswagen.speed_limit_manager import SpeedLimitManager
|
||||
from openpilot.iqpilot.konn3kt.iqlvbs import alc as iq_lvbs_alc
|
||||
from openpilot.system.proprietary_runtime._verified_import import import_verified_module
|
||||
|
||||
iq_lvbs_alc = import_verified_module("iqpilot_alc_private", "iqpilot_private.konn3kt.iqlvbs.alc")
|
||||
vehicle_state = import_verified_module("iqpilot_alc_private", "iqpilot_private.konn3kt.iqlvbs.vehicle_state")
|
||||
|
||||
iqpilot_path = os.path.join(os.path.dirname(__file__), '..', '..', '..')
|
||||
sys.path.insert(0, iqpilot_path)
|
||||
@@ -45,6 +48,14 @@ class CarState(CarStateBase):
|
||||
self.ea_hud_stock_values = {}
|
||||
self.ea_control_stock_values = {}
|
||||
self.acc_type = 0
|
||||
self.acc_radar_sollbeschl = 0.0
|
||||
self.acc_radar_regelabw = 0.0
|
||||
self.acc_radar_aendgrad = 0.0
|
||||
self.acc_radar_sta_adr = 0
|
||||
self.acc_radar_fehler = False
|
||||
self.acc_radar_v_wunsch = 0.0
|
||||
self.acc_radar_sta_acc = 0
|
||||
self.epb_freigabe_ver = False
|
||||
self.acc_stock_counters: dict[str, int] = {}
|
||||
self.esp_stopping = False
|
||||
self.tsk_brake_torque = 0.0
|
||||
@@ -85,7 +96,20 @@ class CarState(CarStateBase):
|
||||
self.PQ_ALC_Status_raw = 0
|
||||
self.alcOverrideAlert = False
|
||||
self.bremse8_stock = None
|
||||
self.br8_acc_anf = False
|
||||
self.tsk_verzoeg_anf = False
|
||||
self.cruise_main_switch = False
|
||||
self.motor3_stock = {}
|
||||
self.motor1_stock = {}
|
||||
self.motor3_frame = 0
|
||||
self.motor1_frame = 0
|
||||
self._odometer_store = vehicle_state.VehicleOdometerStore(CP, self._params)
|
||||
|
||||
def _update_odometer(self, ret: structs.CarState, raw_km: float) -> None:
|
||||
"""Publish the cluster value while proprietary Konn3kt code owns persistence."""
|
||||
odometer_km = self._odometer_store.record(raw_km)
|
||||
if odometer_km is not None:
|
||||
ret.odometer = odometer_km
|
||||
|
||||
def _apply_iq_private_flags(self, ret_iq: structs.IQCarState) -> None:
|
||||
ret_iq.alcOverrideAlert = bool(self.alcOverrideAlert)
|
||||
@@ -117,6 +141,9 @@ class CarState(CarStateBase):
|
||||
def _update_mqb_iq_alc_state(self, pt_cp):
|
||||
iq_lvbs_alc.update_mqb_carstate_alc_state(self, pt_cp)
|
||||
|
||||
def _update_mlb_iq_alc_state(self, pt_cp):
|
||||
iq_lvbs_alc.update_mlb_carstate_alc_state(self, pt_cp)
|
||||
|
||||
def _update_pq_iq_alc_state(self, pt_cp):
|
||||
iq_lvbs_alc.update_pq_carstate_alc_state(self, pt_cp)
|
||||
|
||||
@@ -126,7 +153,8 @@ class CarState(CarStateBase):
|
||||
ext_cp = pt_cp if self.CP.networkLocation == NetworkLocation.fwdCamera else cam_cp
|
||||
|
||||
if self.CP.flags & VolkswagenFlags.PQ:
|
||||
return self.update_pq(pt_cp, cam_cp, ext_cp)
|
||||
aux_cp = can_parsers.get(Bus.aux)
|
||||
return self.update_pq(pt_cp, cam_cp, ext_cp, aux_cp)
|
||||
elif self.CP.flags & VolkswagenFlags.MLB:
|
||||
br_cp = can_parsers[Bus.aux]
|
||||
return self.update_mlb(pt_cp, br_cp, cam_cp, ext_cp)
|
||||
@@ -218,6 +246,7 @@ class CarState(CarStateBase):
|
||||
self.grade = pt_cp.vl["Motor_16"]["TSK_Steigung"]
|
||||
acc_limiter_mode = False if cc_only else ext_cp.vl["ACC_02"]["ACC_Gesetzte_Zeitluecke"] == 0
|
||||
speed_limiter_mode = bool(pt_cp.vl["TSK_06"]["TSK_Limiter_ausgewaehlt"])
|
||||
self.tsk_verzoeg_anf = bool(pt_cp.vl["TSK_06"]["TSK_Freig_Verzoeg_Anf"])
|
||||
|
||||
self._update_mqb_iq_alc_state(pt_cp)
|
||||
|
||||
@@ -256,12 +285,15 @@ class CarState(CarStateBase):
|
||||
ret.buttonEvents = self.create_button_events(pt_cp, self.CCP.BUTTONS)
|
||||
|
||||
ret.lowSpeedAlert = self.update_low_speed_alert(ret.vEgo)
|
||||
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")
|
||||
cruise_main_switch = bool(self.gra_stock_values["GRA_Hauptschalter"])
|
||||
ret.cruiseFaultLateralMode = allow_lat_only and ret.accFaulted and cruise_main_switch
|
||||
ret.lateralAvailable = ret.cruiseState.available or ret.cruiseFaultLateralMode
|
||||
ret.blockPcmEnable = ret.cruiseFaultLateralMode
|
||||
|
||||
ret.fuelGauge = pt_cp.vl["Kombi_02"]["KBI_Inhalt_Tank"] / 55.0
|
||||
ret.fuelTankLevelL = pt_cp.vl["Kombi_02"]["KBI_Inhalt_Tank"] # raw liters for konn3kt
|
||||
self._update_odometer(ret, aux_cp.vl["Kombi_02"]["KBI_Kilometerstand"])
|
||||
|
||||
self.cruise_faulted = ret.accFaulted
|
||||
self._apply_iq_private_flags(ret_iq)
|
||||
@@ -377,6 +409,7 @@ class CarState(CarStateBase):
|
||||
psd_06_values = main_cp.vl["PSD_06"] if self.CP.flags & VolkswagenFlags.STOCK_PSD_PRESENT else {}
|
||||
psd_06_values = pt_cp.vl["PSD_06"] if not psd_06_values and self.CP.flags & VolkswagenFlags.STOCK_PSD_06_PRESENT else psd_06_values
|
||||
diagnose_01_values = pt_cp.vl["Diagnose_01"] if self.CP.flags & VolkswagenFlags.STOCK_DIAGNOSE_01_PRESENT else {}
|
||||
self._update_odometer(ret, pt_cp.vl["Diagnose_01"]["KBI_Kilometerstand"])
|
||||
|
||||
if self.enable_speed_limit_predicative and not self.enable_predicative_speed_limit:
|
||||
self.enable_predicative_speed_limit = True
|
||||
@@ -401,10 +434,8 @@ class CarState(CarStateBase):
|
||||
ret.espDisabled = bool(pt_cp.vl["ESP_21"]["ESP_Tastung_passiv"])
|
||||
ret.espActive = bool(pt_cp.vl["ESP_21"]["ESP_Eingriff"])
|
||||
|
||||
allow_lat_only = self._params.get_bool("AllowLateralWhenLongUnavailable")
|
||||
cruise_main_switch = bool(pt_cp.vl["GRA_ACC_01"]["GRA_Hauptschalter"])
|
||||
cruise_fault_candidate = allow_lat_only and ret.accFaulted and cruise_main_switch
|
||||
|
||||
allow_lat_only = self._params.get_bool("AllowLateralWhenLongUnavailable") and self._params.get_bool("AolEnabled")
|
||||
cruise_fault_candidate = allow_lat_only and ret.accFaulted and bool(pt_cp.vl["GRA_ACC_01"]["GRA_Hauptschalter"])
|
||||
if cruise_fault_candidate:
|
||||
self.cruise_faulted_frames += 1
|
||||
self.cruise_fault_clear_frames = 0
|
||||
@@ -418,12 +449,10 @@ class CarState(CarStateBase):
|
||||
self.cruise_fault_lateral_active = False
|
||||
else:
|
||||
self.cruise_fault_clear_frames = 0
|
||||
|
||||
if not allow_lat_only:
|
||||
self.cruise_fault_lateral_active = False
|
||||
self.cruise_faulted_frames = 0
|
||||
self.cruise_fault_clear_frames = 0
|
||||
|
||||
ret.cruiseFaultLateralMode = self.cruise_fault_lateral_active
|
||||
ret.lateralAvailable = ret.cruiseState.available or ret.cruiseFaultLateralMode
|
||||
ret.blockPcmEnable = ret.cruiseFaultLateralMode
|
||||
@@ -453,9 +482,10 @@ class CarState(CarStateBase):
|
||||
self._apply_iq_private_flags(ret_iq)
|
||||
return ret, ret_iq
|
||||
|
||||
def update_pq(self, pt_cp, cam_cp, ext_cp) -> tuple[structs.CarState, structs.IQCarState]:
|
||||
def update_pq(self, pt_cp, cam_cp, ext_cp, aux_cp=None) -> tuple[structs.CarState, structs.IQCarState]:
|
||||
ret = structs.CarState()
|
||||
ret_iq = structs.IQCarState()
|
||||
sng_ecd_enabled = bool(self.CP.flags & VolkswagenFlagsIQ.IQ_PQ_SNG_ECD)
|
||||
|
||||
# vEgo obtained from Bremse_1 vehicle speed rather than Bremse_3 wheel speeds because Bremse_3 isn't present on NSF
|
||||
ret.vEgoRaw = pt_cp.vl["Bremse_1"]["BR1_Rad_kmh"] * CV.KPH_TO_MS
|
||||
@@ -468,13 +498,13 @@ class CarState(CarStateBase):
|
||||
ret.steeringTorque = pt_cp.vl["Lenkhilfe_3"]["LH3_LM"] * (1, -1)[int(pt_cp.vl["Lenkhilfe_3"]["LH3_LMSign"])]
|
||||
ret.steeringPressed = abs(ret.steeringTorque) > self.CCP.STEER_DRIVER_ALLOWANCE
|
||||
hca_status = self.CCP.hca_status_values.get(pt_cp.vl["Lenkhilfe_2"]["LH2_Sta_HCA"])
|
||||
ret.steerFaultTemporary, ret.steerFaultPermanent = self.update_hca_state(hca_status)
|
||||
ret.steerFaultTemporary, ret.steerFaultPermanent = self.update_hca_state(hca_status, ready_confirms_init=False)
|
||||
|
||||
# Update gas, brakes, and gearshift.
|
||||
ret.gasPressed = pt_cp.vl["Motor_3"]["MO3_Pedalwert"] > 0
|
||||
ret.brake = pt_cp.vl["Bremse_5"]["BR5_Bremsdruck"] / 250.0 # FIXME: this is pressure in Bar, not sure what OP expects
|
||||
ret.brakePressed = bool(pt_cp.vl["Motor_2"]["MO2_BLS"])
|
||||
ret.parkingBrake = bool(pt_cp.vl["Kombi_1"]["Bremsinfo"])
|
||||
ret.parkingBrake = False # bool(pt_cp.vl["Kombi_1"]["Bremsinfo"])
|
||||
|
||||
# Update gear and/or clutch position data.
|
||||
if self.CP.transmissionType == TransmissionType.automatic:
|
||||
@@ -503,8 +533,11 @@ class CarState(CarStateBase):
|
||||
# Consume blind-spot monitoring info/warning LED states, if available.
|
||||
# Infostufe: BSM LED on, Warnung: BSM LED flashing
|
||||
if self.CP.enableBsm:
|
||||
ret.leftBlindspot = bool(ext_cp.vl["SWA_1"]["SWA_Infostufe_SWA_li"]) or bool(ext_cp.vl["SWA_1"]["SWA_Warnung_SWA_li"])
|
||||
ret.rightBlindspot = bool(ext_cp.vl["SWA_1"]["SWA_Infostufe_SWA_re"]) or bool(ext_cp.vl["SWA_1"]["SWA_Warnung_SWA_re"])
|
||||
blindspot_li = bool(ext_cp.vl["SWA_1"]["SWA_Infostufe_SWA_li"]) or bool(ext_cp.vl["SWA_1"]["SWA_Warnung_SWA_li"])
|
||||
blindspot_re = bool(ext_cp.vl["SWA_1"]["SWA_Infostufe_SWA_re"]) or bool(ext_cp.vl["SWA_1"]["SWA_Warnung_SWA_re"])
|
||||
force_rhd = self.force_rhd_for_bsm or self._params.get_bool("ForceRHDForBSM")
|
||||
ret.leftBlindspot = blindspot_re if force_rhd else blindspot_li
|
||||
ret.rightBlindspot = blindspot_li if force_rhd else blindspot_re
|
||||
|
||||
# Consume factory LDW data relevant for factory SWA (Lane Change Assist)
|
||||
# and capture it for forwarding to the blind spot radar controller
|
||||
@@ -524,16 +557,18 @@ class CarState(CarStateBase):
|
||||
# Update ACC radar status.
|
||||
self.acc_type = 0 if cc_only else ext_cp.vl["ACC_System"]["ACS_Typ_ACC"]
|
||||
cruise_main_switch = bool(pt_cp.vl["Motor_5"]["MO5_GRA_Hauptsch"])
|
||||
cruise_tsk_status = bool(pt_cp.vl["Motor_2"]["MO2_Status_TSK"])
|
||||
self.cruise_main_switch = cruise_main_switch or cruise_tsk_status
|
||||
self.cruise_main_switch = cruise_main_switch
|
||||
MO2_StaGRA = pt_cp.vl["Motor_2"]["MO2_Sta_GRA"] in (1, 2)
|
||||
ACS_StaADR = False if cc_only else ext_cp.vl["ACC_System"]["ACS_Sta_ADR"] == 1
|
||||
cruiseActive = MO2_StaGRA or ACS_StaADR
|
||||
if cruiseActive:
|
||||
self.epb_freigabe_ver = bool(aux_cp.vl["EPB_1"]["EP1_Freigabe_Ver"]) if sng_ecd_enabled and not cc_only else False
|
||||
sng_holding = sng_ecd_enabled and self.epb_freigabe_ver
|
||||
if cruiseActive or sng_holding:
|
||||
self.last_cruiseActive = True
|
||||
elif not MO2_StaGRA and not ACS_StaADR:
|
||||
elif not MO2_StaGRA and not ACS_StaADR and not sng_holding:
|
||||
self.last_cruiseActive = False
|
||||
ret.cruiseState.enabled = self.last_cruiseActive
|
||||
self.br8_acc_anf = bool(pt_cp.vl["Bremse_8"]["BR8_Sta_ACC_Anf"]) if not cc_only else False
|
||||
|
||||
if self.CP.pcmCruise:
|
||||
if cc_only:
|
||||
@@ -544,9 +579,9 @@ class CarState(CarStateBase):
|
||||
cruise_faulted = pt_cp.vl["Motor_2"]["MO2_Sta_GRA"] == 3
|
||||
|
||||
ret.accFaulted = cruise_faulted
|
||||
ret.cruiseState.available = (cruise_main_switch or cruise_tsk_status) and not cruise_faulted
|
||||
ret.cruiseState.available = cruise_main_switch and not cruise_faulted
|
||||
allow_lat_only = self._params.get_bool("AllowLateralWhenLongUnavailable") and self._params.get_bool("AolEnabled")
|
||||
cruise_main_available = cruise_main_switch or cruise_tsk_status
|
||||
cruise_main_available = cruise_main_switch
|
||||
ret.cruiseFaultLateralMode = allow_lat_only and cruise_faulted and cruise_main_available
|
||||
ret.lateralAvailable = ret.cruiseState.available or ret.cruiseFaultLateralMode
|
||||
ret.blockPcmEnable = ret.cruiseFaultLateralMode
|
||||
@@ -563,6 +598,33 @@ class CarState(CarStateBase):
|
||||
ret.cruiseState.speed = 0
|
||||
|
||||
self.motor2_stock = pt_cp.vl["Motor_2"]
|
||||
self.motor5_stock = pt_cp.vl["Motor_5"]
|
||||
|
||||
if self.CP.flags & VolkswagenFlagsIQ.IQ_PQ_ACC_FTS_EPB:
|
||||
self.motor3_stock = aux_cp.vl["Motor_3"]
|
||||
self.motor1_stock = aux_cp.vl["Motor_1"]
|
||||
self.motor3_frame += 1
|
||||
self.motor1_frame += 1
|
||||
|
||||
if cc_only:
|
||||
self.acc_radar_sollbeschl = 0.0
|
||||
self.acc_radar_regelabw = 0.0
|
||||
self.acc_radar_aendgrad = 0.0
|
||||
self.acc_radar_sta_adr = 0
|
||||
self.acc_radar_fehler = False
|
||||
self.acc_radar_v_wunsch = 0.0
|
||||
self.acc_radar_sta_acc = 0
|
||||
else:
|
||||
self.acc_radar_sollbeschl = ext_cp.vl["ACC_System"]["ACS_Sollbeschl"]
|
||||
self.acc_radar_regelabw = ext_cp.vl["ACC_System"]["ACS_zul_Regelabw"]
|
||||
self.acc_radar_aendgrad = ext_cp.vl["ACC_System"]["ACS_max_AendGrad"]
|
||||
self.acc_radar_sta_adr = int(ext_cp.vl["ACC_System"]["ACS_Sta_ADR"])
|
||||
self.acc_radar_fehler = bool(ext_cp.vl["ACC_System"]["ACS_Fehler"])
|
||||
self.acc_radar_v_wunsch = ext_cp.vl["ACC_GRA_Anzeige"]["ACA_V_Wunsch"]
|
||||
self.acc_radar_sta_acc = int(ext_cp.vl["ACC_GRA_Anzeige"]["ACA_StaACC"])
|
||||
|
||||
ret_iq.accRadarStaAdr = self.acc_radar_sta_adr
|
||||
ret_iq.accRadarFehler = self.acc_radar_fehler
|
||||
|
||||
# Update button states for turn signals and ACC controls, capture all ACC button state/config for passthrough
|
||||
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_stalk(300, pt_cp.vl["Gate_Komf_1"]["GK1_Blinker_li"],
|
||||
@@ -577,8 +639,15 @@ class CarState(CarStateBase):
|
||||
|
||||
ret.lowSpeedAlert = self.update_low_speed_alert(ret.vEgo)
|
||||
|
||||
ret.fuelGauge = pt_cp.vl["Kombi_1"]["Tankinhalt"] / 55.0
|
||||
ret.fuelTankLevelL = pt_cp.vl["Kombi_1"]["Tankinhalt"] # raw liters for konn3kt
|
||||
ret.fuelGauge = 0 # pt_cp.vl["Kombi_1"]["Tankinhalt"] / 55.0
|
||||
ret.fuelTankLevelL = 0 # pt_cp.vl["Kombi_1"]["Tankinhalt"] # raw liters for konn3kt
|
||||
if aux_cp is not None:
|
||||
self._update_odometer(ret, aux_cp.vl["Kombi_3"]["Kilometerstand"])
|
||||
|
||||
if self.CP.flags & VolkswagenFlagsIQ.IQ_PQ_ACC_FTS_EPB:
|
||||
ret.cruiseState.standstill = self.CP.pcmCruise and bool(pt_cp.vl["Bremse_5"]["BR5_Stillstand"]) and ret.cruiseState.enabled
|
||||
elif sng_ecd_enabled:
|
||||
ret.cruiseState.standstill = sng_holding and ret.standstill
|
||||
|
||||
self.cruise_faulted = ret.accFaulted
|
||||
self.frame += 1
|
||||
@@ -615,6 +684,7 @@ class CarState(CarStateBase):
|
||||
ret.accFaulted = pt_cp.vl["TSK_02"]["TSK_Status"] in (3,)
|
||||
|
||||
self.parse_mlb_mqb_steering_state(ret, pt_cp)
|
||||
self._update_mlb_iq_alc_state(pt_cp)
|
||||
|
||||
ret.brake = pt_cp.vl["ESP_05"]["ESP_Bremsdruck"] / 250.0
|
||||
brake_pedal_pressed = bool(pt_cp.vl["Motor_03"]["MO_Fahrer_bremst"])
|
||||
@@ -648,6 +718,7 @@ class CarState(CarStateBase):
|
||||
|
||||
ret.fuelGauge = br_cp.vl["Kombi_02"]["KBI_Inhalt_Tank"] / 55.0
|
||||
ret.fuelTankLevelL = br_cp.vl["Kombi_02"]["KBI_Inhalt_Tank"] # raw liters for konn3kt
|
||||
self._update_odometer(ret, br_cp.vl["Kombi_02"]["KBI_Kilometerstand"])
|
||||
|
||||
ret.buttonEvents = self.create_button_events(pt_cp, self.CCP.BUTTONS)
|
||||
|
||||
@@ -680,10 +751,11 @@ class CarState(CarStateBase):
|
||||
ret.steerFaultTemporary, ret.steerFaultPermanent = self.update_hca_state(hca_status, drive_mode)
|
||||
return
|
||||
|
||||
def update_hca_state(self, hca_status, drive_mode=True):
|
||||
def update_hca_state(self, hca_status, drive_mode=True, ready_confirms_init=True):
|
||||
# Treat FAULT as temporary for worst likely EPS recovery time, for cars without factory Lane Assist
|
||||
# DISABLED means the EPS hasn't been configured to support Lane Assist
|
||||
self.eps_init_complete = self.eps_init_complete or (hca_status in ("DISABLED", "READY", "ACTIVE") or self.frame > 600)
|
||||
init_statuses = ("DISABLED", "READY", "ACTIVE") if ready_confirms_init else ("DISABLED", "ACTIVE")
|
||||
self.eps_init_complete = self.eps_init_complete or hca_status in init_statuses or self.frame > 1000
|
||||
perm_fault = drive_mode and hca_status == "DISABLED" or (self.eps_init_complete and hca_status == "FAULT")
|
||||
temp_fault = drive_mode and hca_status in ("REJECTED", "PREEMPTED") or not self.eps_init_complete
|
||||
return temp_fault, perm_fault
|
||||
@@ -735,8 +807,11 @@ class CarState(CarStateBase):
|
||||
]
|
||||
if CP.flags & VolkswagenFlags.MLB:
|
||||
pt_messages += [
|
||||
("Blinkmodi_01", math.nan) # From J519 BCM (is inactive when no lights active, 50Hz when active)
|
||||
("Blinkmodi_01", math.nan), # From J519 BCM (is inactive when no lights active, 50Hz when active)
|
||||
("Kombi_02", math.nan), # Auxiliary-bus cluster odometer
|
||||
]
|
||||
else:
|
||||
pt_messages += [("Kombi_02", math.nan)] # Auxiliary-bus cluster odometer
|
||||
if CP.flags & VolkswagenFlags.STOCK_HCA_PRESENT:
|
||||
cam_messages += [
|
||||
("HCA_01", 1), # From R242 Driver assistance camera, 50Hz if steering/1Hz if not
|
||||
@@ -750,8 +825,12 @@ class CarState(CarStateBase):
|
||||
|
||||
@staticmethod
|
||||
def get_can_parsers_pq(CP):
|
||||
aux_messages = [("Kombi_3", math.nan)] # Bus 1 cluster odometer
|
||||
if CP.flags & VolkswagenFlagsIQ.IQ_PQ_ACC_FTS_EPB:
|
||||
aux_messages.append(("Motor_3", 0))
|
||||
return {
|
||||
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).pt),
|
||||
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).powertrain),
|
||||
Bus.aux: CANParser(DBC[CP.carFingerprint][Bus.pt], aux_messages, CanBus(CP).aux),
|
||||
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).cam),
|
||||
}
|
||||
|
||||
@@ -763,6 +842,7 @@ class CarState(CarStateBase):
|
||||
# TA_01 lives on bus 0 (car ECU / OP-generated when long is active).
|
||||
# math.nan → ignore_alive=True so it never contributes to can_valid.
|
||||
("TA_01", math.nan),
|
||||
("Diagnose_01", math.nan), # Bus 0 cluster odometer
|
||||
]
|
||||
if CP.networkLocation == NetworkLocation.fwdCamera:
|
||||
pt_messages.append(("AWV_03", 1))
|
||||
|
||||
@@ -681,6 +681,14 @@ FW_VERSIONS = {
|
||||
b'\xf1\x873QF907572A \xf1\x890132',
|
||||
],
|
||||
},
|
||||
CAR.VOLKSWAGEN_PASSAT_B7: {
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\xf1\x8703L906018RE\xf1\x899979',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x74f, None): [
|
||||
b'\xf1\x873AA980654D \xf1\x890300\xf1\x82\x0143',
|
||||
],
|
||||
},
|
||||
CAR.VOLKSWAGEN_POLO_MK6: {
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\xf1\x8704C906025H \xf1\x895177',
|
||||
@@ -716,6 +724,17 @@ FW_VERSIONS = {
|
||||
b'\xf1\x877N0907572C \xf1\x890211\xf1\x82\x0153',
|
||||
],
|
||||
},
|
||||
CAR.SEAT_ALHAMBRA_MK1: {
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\xf1\x8704L906016HE\xf1\x894635',
|
||||
],
|
||||
(Ecu.srs, 0x715, None): [
|
||||
b'\xf1\x877N0959655D \xf1\x890016\xf1\x82\x0801100705----10--',
|
||||
],
|
||||
(Ecu.fwdRadar, 0x757, None): [
|
||||
b'\xf1\x877N0907572C \xf1\x890211\xf1\x82\x0153',
|
||||
],
|
||||
},
|
||||
CAR.VOLKSWAGEN_TAOS_MK1: {
|
||||
(Ecu.engine, 0x7e0, None): [
|
||||
b'\xf1\x8704E906025CK\xf1\x892228',
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import time
|
||||
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car import get_safety_config, structs, uds
|
||||
from iqdbc.car.carlog import carlog
|
||||
from iqdbc.car.interfaces import CarInterfaceBase
|
||||
from iqdbc.car.isotp_parallel_query import IsoTpParallelQuery
|
||||
from iqdbc.car.volkswagen.carcontroller import CarController
|
||||
from iqdbc.car.volkswagen.carstate import CarState
|
||||
from iqdbc.car.volkswagen.values import CanBus, CAR, DashcamOnlyReason, NetworkLocation, RADAR_DISABLE_STATE, TransmissionType, VolkswagenFlags, VolkswagenSafetyFlags, VolkswagenFlagsIQ
|
||||
from iqdbc.car.volkswagen.values import (
|
||||
CAR, CanBus, DashcamOnlyReason, NetworkLocation, RADAR_DISABLE_STATE, TransmissionType,
|
||||
VolkswagenFlags, VolkswagenSafetyFlags, VolkswagenFlagsIQ, get_longitudinal_stopping_speed_override,
|
||||
)
|
||||
from iqdbc.car.volkswagen.radar_interface import RadarInterface
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
import sys
|
||||
import os
|
||||
iqpilot_path = os.path.join(os.path.dirname(__file__), '..', '..', '..')
|
||||
@@ -19,6 +20,11 @@ try:
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
try:
|
||||
from openpilot.system.proprietary_runtime._verified_import import import_verified_module
|
||||
except Exception:
|
||||
import_verified_module = None
|
||||
|
||||
|
||||
class CarInterface(CarInterfaceBase):
|
||||
CarState = CarState
|
||||
@@ -39,9 +45,16 @@ class CarInterface(CarInterfaceBase):
|
||||
if ret.flags & VolkswagenFlags.PQ:
|
||||
# Set global PQ35/PQ46/NMS parameters
|
||||
safety_configs = [get_safety_config(structs.CarParams.SafetyModel.volkswagenPq)]
|
||||
if candidate == CAR.SEAT_ALHAMBRA_MK1:
|
||||
ret.flags |= VolkswagenFlagsIQ.IQ_PQ_TIMEBOMB.value
|
||||
if not (ret.flags & VolkswagenFlagsIQ.IQ_PQ_TIMEBOMB) and _params.get_bool("VwPqEpsPatched"):
|
||||
ret.minSteerSpeed = 0
|
||||
if angle_lat_enabled:
|
||||
ret.flags |= VolkswagenFlagsIQ.IQ_LVBS_ALC_MODULE.value
|
||||
safety_configs[0].safetyParam |= VolkswagenSafetyFlags.PQ_ALC_MODULE.value
|
||||
if alpha_long:
|
||||
ret.flags |= VolkswagenFlagsIQ.IQ_PQ_SNG_ECD.value
|
||||
safety_configs[0].safetyParam |= VolkswagenSafetyFlags.PQ_SNG_ECD.value
|
||||
ret.enableBsm = 0x3BA in fingerprint[0] # SWA_1
|
||||
|
||||
if 0x440 in fingerprint[0] or docs: # Getriebe_1
|
||||
@@ -59,6 +72,13 @@ class CarInterface(CarInterfaceBase):
|
||||
else:
|
||||
ret.flags |= VolkswagenFlagsIQ.IQ_CC_ONLY_NO_RADAR.value
|
||||
|
||||
cc_only_flags = VolkswagenFlagsIQ.IQ_CC_ONLY | VolkswagenFlagsIQ.IQ_CC_ONLY_NO_RADAR
|
||||
if ret.flags & cc_only_flags:
|
||||
safety_configs[0].safetyParam |= VolkswagenSafetyFlags.PQ_NO_CAM_BUS.value
|
||||
if (ret.flags & cc_only_flags) and not fingerprint[0]:
|
||||
ret.flags |= VolkswagenFlagsIQ.IQ_PQ_LOWLINE.value
|
||||
safety_configs[0].safetyParam |= VolkswagenSafetyFlags.PQ_LOWLINE.value
|
||||
|
||||
if any(msg in fingerprint[1] for msg in (0x1A0, 0xC2)): # Bremse_1, Lenkwinkel_1
|
||||
ret.networkLocation = NetworkLocation.gateway
|
||||
else:
|
||||
@@ -164,19 +184,20 @@ class CarInterface(CarInterfaceBase):
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
elif ret.flags & VolkswagenFlags.MLB:
|
||||
ret.steerActuatorDelay = 0.2
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
if angle_lat_enabled:
|
||||
ret.steerControlType = structs.CarParams.SteerControlType.angle
|
||||
ret.steerAtStandstill = bool(joystick_mode)
|
||||
else:
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
elif ret.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
ret.steerActuatorDelay = 0.3
|
||||
else:
|
||||
ret.steerActuatorDelay = 0.1
|
||||
ret.lateralTuning.pid.kpBP = [0.]
|
||||
ret.lateralTuning.pid.kiBP = [0.]
|
||||
ret.lateralTuning.pid.kf = 0.00006
|
||||
ret.lateralTuning.pid.kpV = [0.6]
|
||||
ret.lateralTuning.pid.kiV = [0.2]
|
||||
if angle_lat_enabled:
|
||||
ret.steerControlType = structs.CarParams.SteerControlType.angle
|
||||
ret.steerAtStandstill = bool(joystick_mode)
|
||||
else:
|
||||
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
|
||||
|
||||
# Global longitudinal tuning defaults, can be overridden per-vehicle
|
||||
|
||||
@@ -200,17 +221,12 @@ class CarInterface(CarInterfaceBase):
|
||||
if candidate == CAR.PORSCHE_MACAN_MK1:
|
||||
ret.steerActuatorDelay = 0.07
|
||||
|
||||
if candidate == CAR.VOLKSWAGEN_PASSAT_B7 or CAR.SEAT_ALHAMBRA_MK1:
|
||||
ret.flags |= VolkswagenFlagsIQ.IQ_PQ_ACC_FTS_EPB.value
|
||||
safety_configs[0].safetyParam |= VolkswagenSafetyFlags.PQ_ACC_FTS_EPB.value
|
||||
|
||||
ret.pcmCruise = not ret.openpilotLongitudinalControl
|
||||
if ret.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
|
||||
ret.startingState = True
|
||||
ret.startAccel = 0.8
|
||||
ret.vEgoStarting = 0.5
|
||||
ret.vEgoStopping = 0.1
|
||||
ret.stopAccel = -0.55
|
||||
else:
|
||||
ret.stopAccel = -0.55
|
||||
ret.vEgoStarting = 0.1
|
||||
ret.vEgoStopping = 1.5 * CV.KPH_TO_MS if ret.flags & VolkswagenFlags.PQ else 0.1
|
||||
ret.stopAccel = -0.55
|
||||
ret.autoResumeSng = ret.minEnableSpeed == -1
|
||||
CAN = CanBus(fingerprint=fingerprint)
|
||||
if CAN.pt >= 4:
|
||||
@@ -221,10 +237,18 @@ class CarInterface(CarInterfaceBase):
|
||||
|
||||
@staticmethod
|
||||
def pre_init(CP: structs.CarParams, CP_IQ: structs.IQCarParams, can_recv, can_send):
|
||||
# Engine-on check moved to init(): if radar can't be disabled, radarDisableFailed=True
|
||||
# gates only long control (carcontroller line ~308) while lateral still works.
|
||||
# Full dashcam mode here was too aggressive — lateral doesn't need radar disabled.
|
||||
pass
|
||||
if not (CP.flags & VolkswagenFlags.PQ) or (CP.flags & VolkswagenFlagsIQ.IQ_PQ_TIMEBOMB) or import_verified_module is None:
|
||||
return
|
||||
try:
|
||||
params = Params()
|
||||
if params.get_bool("VwPqEpsPatched"):
|
||||
return
|
||||
flasher = import_verified_module("iqpilot_hephaestusd_private", "iqpilot_private.konn3kt.hephaestus.vw_pq_flasher")
|
||||
status = flasher.check_eps_patch_status(1, can_recv, can_send)
|
||||
except Exception:
|
||||
return
|
||||
if status == "patched":
|
||||
params.put_bool("VwPqEpsPatched", True)
|
||||
|
||||
@staticmethod
|
||||
def init(CP: structs.CarParams, CP_IQ: structs.IQCarParams, can_recv, can_send):
|
||||
@@ -321,4 +345,5 @@ 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:
|
||||
ret.longitudinalStoppingSpeedOverride = get_longitudinal_stopping_speed_override(candidate, stock_cp.flags)
|
||||
return ret
|
||||
|
||||
@@ -28,7 +28,7 @@ def create_steering_control(packer, bus, apply_curvature, lkas_enabled, power):
|
||||
values = {
|
||||
"Curvature": abs(apply_curvature), # in rad/m
|
||||
"Curvature_VZ": 1 if apply_curvature > 0 and lkas_enabled else 0,
|
||||
"Power": 100 if lkas_enabled else 0, # TEST: hard 100%, no ramp
|
||||
"Power": power if lkas_enabled else 0,
|
||||
"RequestStatus": 4 if lkas_enabled else 2,
|
||||
"HighSendRate": lkas_enabled,
|
||||
}
|
||||
|
||||
@@ -270,5 +270,5 @@ class LatControlCurvature():
|
||||
error = desired_curvature - actual_curvature
|
||||
freeze_integrator = CC.steerLimited or CS.vEgo < 5
|
||||
output_curvature = self.pid.update(error, feedforward=desired_curvature_corr, speed=CS.vEgo,
|
||||
freeze_integrator=freeze_integrator, override=False)
|
||||
freeze_integrator=freeze_integrator, override=CS.steeringPressed)
|
||||
return output_curvature
|
||||
|
||||
@@ -45,7 +45,7 @@ def create_acc_accel_control(packer, bus, acc_type, accel, acc_control, stopping
|
||||
return [packer.make_can_msg("ACC_05", bus, values)]
|
||||
|
||||
|
||||
def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, leadDistance, distanceBars, fcw_alert, leadVisible):
|
||||
def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, leadDistance, distanceBars, fcw_alert, leadVisible, unavailable, decel, d_unresponsive):
|
||||
values = {}
|
||||
return packer.make_can_msg("ACC_02", bus, values)
|
||||
|
||||
|
||||
@@ -114,10 +114,10 @@ def create_acc_accel_control(packer, bus, acc_type, accel, acc_control, stopping
|
||||
"ACC_Status_ACC": acc_control,
|
||||
"ACC_StartStopp_Info": acc_enabled,
|
||||
"ACC_Sollbeschleunigung_02": accel if acc_enabled else 3.01,
|
||||
"ACC_zul_Regelabw_unten": comfortBand if acc_enabled else 0.2,
|
||||
"ACC_zul_Regelabw_oben": comfortBand if acc_enabled else 0.2,
|
||||
"ACC_neg_Sollbeschl_Grad_02": jerkLimit if acc_enabled else 0,
|
||||
"ACC_pos_Sollbeschl_Grad_02": jerkLimit if acc_enabled else 0,
|
||||
"ACC_zul_Regelabw_unten": 0.2,
|
||||
"ACC_zul_Regelabw_oben": 0.2,
|
||||
"ACC_neg_Sollbeschl_Grad_02": 3.0 if acc_enabled else 0,
|
||||
"ACC_pos_Sollbeschl_Grad_02": 3.0 if acc_enabled else 0,
|
||||
"ACC_Anfahren": starting if acc_enabled else False,
|
||||
"ACC_Anhalten": stopping if acc_enabled else False,
|
||||
}
|
||||
@@ -149,12 +149,16 @@ def create_acc_accel_control(packer, bus, acc_type, accel, acc_control, stopping
|
||||
return commands
|
||||
|
||||
|
||||
def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, leadDistance, distanceBars, fcw_alert, leadVisible):
|
||||
def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, leadDistance, distanceBars, fcw_alert, leadVisible, unavailable, decel, d_unresponsive):
|
||||
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": distanceBars,
|
||||
"ACC_Display_Prio": 3,
|
||||
"ACC_Gesetzte_Zeitluecke": leadDistanceBars,
|
||||
"ACC_Optischer_Fahrerhinweis": 1 if fcw_alert else 0,
|
||||
"ACC_Display_Prio": priodisp,
|
||||
"ACC_Relevantes_Objekt": leadDistanceBars,
|
||||
"ACC_Abstandsindex": leadDistance if leadVisible else 0,
|
||||
"ACC_Akustik_02": fcw_alert,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos/
|
||||
"""
|
||||
from iqdbc.car.common.conversions import Conversions as CV
|
||||
from iqdbc.car.volkswagen import pqcan
|
||||
|
||||
|
||||
class PQRadarHandler:
|
||||
GRA_STEP = 3 # GRA_Neu cadence (~33 Hz), matches stock stalk module
|
||||
SPOOF_STEP = 2 # Motor_2 / Motor_5 spoof cadence (50 Hz)
|
||||
|
||||
ENGAGE_FLOOR = 1.0 * CV.KPH_TO_MS # never SET at/below 1 kph
|
||||
REENGAGE_FLOOR = 2.0 * CV.KPH_TO_MS # hysteresis: only (re)engage above 2 kph
|
||||
|
||||
SETSPEED_TOL_KPH = 1.0 # don't chase set-speed within this band
|
||||
SHORT_STEP_KPH = 1.0 * CV.MPH_TO_KPH # GRA_*_kurz ~= 1 mph
|
||||
LONG_STEP_KPH = 5.0 * CV.MPH_TO_KPH # GRA_*_lang ~= 5 mph
|
||||
TAP_RELEASE_CYCLES = 2 # GRA cycles to release between set-speed taps
|
||||
|
||||
def __init__(self, CAN):
|
||||
self.bus = CAN.ext # radar lives on bus 2 (ext/cam)
|
||||
self.counter = 0
|
||||
self.failed = False # ACS_Fehler / irrev_Fehler -> radar dead for the drive
|
||||
self.want_engaged = False # our belief the radar cruise should be on
|
||||
self._press_phase = 0 # alternate press/release for SET/cancel discrete edges
|
||||
self._tap_cooldown = 0 # set-speed tap rate limiter
|
||||
|
||||
def reset(self):
|
||||
self.want_engaged = False
|
||||
self._press_phase = 0
|
||||
self._tap_cooldown = 0
|
||||
|
||||
@staticmethod
|
||||
def _map_gap_bars(gap_bars):
|
||||
if not gap_bars:
|
||||
return None
|
||||
return int(min(3, max(1, gap_bars)))
|
||||
|
||||
def update(self, packer, frame, CS, *, blend_active, engage_req, cancel_req,
|
||||
set_speed_kph, gap_bars, v_ego):
|
||||
can_sends = []
|
||||
|
||||
if not blend_active:
|
||||
self.reset()
|
||||
return can_sends
|
||||
|
||||
if CS.acc_radar_fehler or CS.acc_radar_sta_adr == 3:
|
||||
self.failed = True
|
||||
|
||||
radar_active = (CS.acc_radar_sta_adr == 1) and not self.failed
|
||||
|
||||
if self.failed:
|
||||
self.want_engaged = False
|
||||
elif cancel_req:
|
||||
self.want_engaged = False
|
||||
elif engage_req and v_ego > self.REENGAGE_FLOOR:
|
||||
self.want_engaged = True
|
||||
|
||||
if (frame % self.SPOOF_STEP) == 0:
|
||||
# Mirror the stock engage handshake ORDER: the radar leads (SET -> ADR active) and only THEN
|
||||
# does the engine report GRA regulating. Asserting MO2_Sta_GRA=1 before the radar's ADR is
|
||||
# active presents an impossible state ("engine regulating but ADR didn't initiate it") and the
|
||||
# radar latches an irreversible fault. So only assert cruise-active once ADR is actually active;
|
||||
# relay Motor_5 (main switch) as verbatim OEM passthrough throughout.
|
||||
hold_engaged = self.want_engaged and radar_active
|
||||
can_sends.append(pqcan.filter_motor2(packer, self.bus, CS.motor2_stock, gra_active=hold_engaged))
|
||||
can_sends.append(pqcan.filter_motor5(packer, self.bus, CS.motor5_stock, gra_active=False))
|
||||
|
||||
if (frame % self.GRA_STEP) == 0:
|
||||
set_btn = resume_btn = cancel = up_s = down_s = up_l = down_l = False
|
||||
self._press_phase ^= 1
|
||||
pressing = self._press_phase == 0
|
||||
|
||||
if self.failed:
|
||||
pass
|
||||
elif cancel_req:
|
||||
# Only actually press cancel when the radar is engaged (or overdriven) -- otherwise it's a
|
||||
# no-op against a passive/off radar and just spams GRA_Abbrechen at ~16 Hz. Fires while
|
||||
# active and stops once the radar leaves the active state.
|
||||
cancel = pressing and radar_active
|
||||
elif self.want_engaged and not radar_active and v_ego > self.ENGAGE_FLOOR:
|
||||
# Engage with RESUME (GRA_Recall), not SET. Ground-truth from an OEM ACC engage (radar leads:
|
||||
# RESUME -> ACS_Sta_ADR 2->1 in ~90ms -> engine MO2_Sta_GRA 0->1 ~80ms later) shows this radar
|
||||
# engages from passive on GRA_Recall; it ignores GRA_Neu_Setzen from that state.
|
||||
resume_btn = pressing
|
||||
elif self.want_engaged and radar_active:
|
||||
if self._tap_cooldown > 0:
|
||||
self._tap_cooldown -= 1
|
||||
elif set_speed_kph > 0:
|
||||
delta = set_speed_kph - CS.acc_radar_v_wunsch
|
||||
if abs(delta) >= self.SETSPEED_TOL_KPH:
|
||||
big = abs(delta) >= self.LONG_STEP_KPH
|
||||
if delta > 0:
|
||||
up_l, up_s = big, not big
|
||||
else:
|
||||
down_l, down_s = big, not big
|
||||
self._tap_cooldown = self.TAP_RELEASE_CYCLES
|
||||
|
||||
self.counter = (self.counter + 1) % 16
|
||||
can_sends.append(pqcan.create_radar_gra(
|
||||
packer, self.bus, CS.gra_stock_values, self.counter,
|
||||
set_btn=set_btn, resume=resume_btn, cancel=cancel, up_short=up_s, down_short=down_s,
|
||||
up_long=up_l, down_long=down_l, zeitluecke=self._map_gap_bars(gap_bars),
|
||||
))
|
||||
|
||||
return can_sends
|
||||
@@ -1,3 +1,7 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos/
|
||||
"""
|
||||
|
||||
def create_hca_steering_control(packer, bus, apply_torque, HCA_Status):
|
||||
values = {
|
||||
"LM_Offset": abs(apply_torque),
|
||||
@@ -95,20 +99,20 @@ def acc_hud_status_value(main_switch_on, acc_faulted, longActive, longOverride):
|
||||
return hud_status
|
||||
|
||||
|
||||
def create_acc_accel_control(packer, bus, acc_type, accel, acc_control, stopping, starting, esp_hold, comfortBand, jerkLimit, eBrakeActive):
|
||||
def create_acc_accel_control(packer, bus, acc_type, accel, acc_control, stopping, starting, esp_hold, comfortBand, jerkLimit, eBrakeActive, sng_active=False):
|
||||
commands = []
|
||||
acc_enabled = acc_control == 1
|
||||
acc_enabled = acc_control == 1 and not sng_active
|
||||
|
||||
values = {
|
||||
"ACS_Sta_ADR": acc_control,
|
||||
"ACS_Sta_ADR": 0 if sng_active else acc_control,
|
||||
"ACS_StSt_Info": acc_enabled,
|
||||
"ACS_Typ_ACC": acc_type,
|
||||
"ACS_Anhaltewunsch": acc_type == 1 and stopping or eBrakeActive,
|
||||
"ACS_Anhaltewunsch": (acc_type == 1 and stopping or eBrakeActive) or sng_active,
|
||||
"ACS_FreigSollB": acc_enabled,
|
||||
"ACS_Sollbeschl": accel if acc_enabled else 3.01,
|
||||
"ACS_zul_Regelabw": comfortBand if acc_enabled else 1.27,
|
||||
"ACS_max_AendGrad": jerkLimit if acc_enabled else 5.08,
|
||||
"ACS_Schubabsch": 1 if acc_enabled and (accel > 0.05) else 0,
|
||||
"ACS_Schubabsch": 0,
|
||||
"ACS_MomEingriff": 0,
|
||||
"ACS_ADR_Schub": 0,
|
||||
}
|
||||
@@ -118,6 +122,14 @@ def create_acc_accel_control(packer, bus, acc_type, accel, acc_control, stopping
|
||||
return commands
|
||||
|
||||
|
||||
def create_sng_handoff_control(packer, bus, handoff_active, decel_req):
|
||||
values = {
|
||||
"SNG_HandoffActive": handoff_active,
|
||||
"SNG_DecelReq": decel_req if handoff_active else 0.0,
|
||||
}
|
||||
return packer.make_can_msg("SNG_1", bus, values)
|
||||
|
||||
|
||||
def create_blinker_control(packer, bus, leftBlinker, rightBlinker):
|
||||
values = {
|
||||
"BM_rechts": rightBlinker,
|
||||
@@ -126,29 +138,71 @@ def create_blinker_control(packer, bus, leftBlinker, rightBlinker):
|
||||
return packer.make_can_msg("Blinkmodi_02", bus, values)
|
||||
|
||||
|
||||
def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, leadDistance, distanceBars, fcw_alert, leadVisible):
|
||||
if distanceBars == 1:
|
||||
leadDistanceBars = 2
|
||||
elif distanceBars == 2:
|
||||
leadDistanceBars = 3
|
||||
elif distanceBars == 3:
|
||||
leadDistanceBars = 4
|
||||
else:
|
||||
leadDistanceBars = 2
|
||||
def create_acc_hud_control(packer, bus, acc_hud_status, set_speed, leadDistance, distanceBars, fcw_alert, leadVisible, unavailable, decel, d_unresponsive):
|
||||
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 = {
|
||||
"ACA_StaACC": acc_hud_status,
|
||||
"ACA_AnzDisplay": 1 if acc_hud_status in (3, 4) else 0,
|
||||
"ACA_Zeitluecke": leadDistanceBars,
|
||||
"ACA_V_Wunsch": set_speed,
|
||||
"ACA_gemZeitl": min(15, max(1, int(round(leadDistance)))) if leadVisible else 0,
|
||||
"ACA_PrioDisp": 3,
|
||||
"ACA_PrioDisp": priodisp,
|
||||
"ACA_Akustik1": d_unresponsive,
|
||||
# "ACA_Fahrerhinw": unavailable,
|
||||
"ACA_Akustik2": fcw_alert,
|
||||
"ACA_ACC_Verz": decel,
|
||||
}
|
||||
|
||||
return packer.make_can_msg("ACC_GRA_Anzeige", bus, values)
|
||||
|
||||
def filter_motor2(packer, bus, motor2_stock):
|
||||
values = motor2_stock
|
||||
values.update({
|
||||
"MO2_Sta_GRA": 0,
|
||||
})
|
||||
def filter_motor2(packer, bus, motor2_stock, gra_active=False):
|
||||
values = dict(motor2_stock)
|
||||
if gra_active:
|
||||
values.update({
|
||||
"MO2_Sta_GRA": 1,
|
||||
"MO2_Status_TSK": 1,
|
||||
})
|
||||
else:
|
||||
values.update({
|
||||
"MO2_Sta_GRA": 0,
|
||||
})
|
||||
return packer.make_can_msg("Motor_2", bus, values)
|
||||
|
||||
|
||||
def filter_motor5(packer, bus, motor5_stock, gra_active=False):
|
||||
values = dict(motor5_stock)
|
||||
if gra_active:
|
||||
values["MO5_GRA_Hauptsch"] = 1
|
||||
return packer.make_can_msg("Motor_5", bus, values)
|
||||
|
||||
|
||||
def create_motor3_resume(packer, bus, motor1_stock, motor3_stock, resume=False):
|
||||
values = dict(motor3_stock)
|
||||
values_motor1 = dict(motor1_stock)
|
||||
if resume:
|
||||
values["MO3_Pedalwert"] = values_motor1["MO1_Pedalwert"]
|
||||
return packer.make_can_msg("Motor_3", bus, values)
|
||||
|
||||
|
||||
def create_radar_gra(packer, bus, gra_stock, counter, set_btn=False, cancel=False, resume=False,
|
||||
up_short=False, down_short=False, up_long=False, down_long=False, zeitluecke=None):
|
||||
values = {s: gra_stock[s] for s in [
|
||||
"GRA_Hauptschalt", # ACC main switch passthrough
|
||||
"GRA_Typ_Hauptschalt", # momentary vs latching
|
||||
"GRA_Kodierinfo", # configuration
|
||||
"GRA_Sender", # CAN originator
|
||||
]}
|
||||
values.update({
|
||||
"COUNTER": counter % 16,
|
||||
"GRA_Neu_Setzen": 1 if set_btn else 0,
|
||||
"GRA_Abbrechen": 1 if cancel else 0,
|
||||
"GRA_Recall": 1 if resume else 0,
|
||||
"GRA_Up_kurz": 1 if up_short else 0,
|
||||
"GRA_Down_kurz": 1 if down_short else 0,
|
||||
"GRA_Up_lang": 1 if up_long else 0,
|
||||
"GRA_Down_lang": 1 if down_long else 0,
|
||||
})
|
||||
if zeitluecke is not None:
|
||||
values["GRA_Zeitluecke"] = zeitluecke
|
||||
return packer.make_can_msg("GRA_Neu", bus, values)
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
from types import SimpleNamespace
|
||||
|
||||
from iqdbc.car.volkswagen import mqbcan, pqcan
|
||||
from iqdbc.car.volkswagen.carcontroller import CarController
|
||||
from iqdbc.car.volkswagen.values import CAR, MQB_A0_CARS
|
||||
|
||||
|
||||
def test_is_mqb_a0_car_matches_expected_platforms():
|
||||
assert CAR.VOLKSWAGEN_POLO_MK6 in MQB_A0_CARS
|
||||
assert CAR.VOLKSWAGEN_TCROSS_MK1 in MQB_A0_CARS
|
||||
assert CAR.SKODA_FABIA_MK4 in MQB_A0_CARS
|
||||
assert CAR.SKODA_KAMIQ_MK1 in MQB_A0_CARS
|
||||
assert CarController._is_mqb_a0_car(CAR.VOLKSWAGEN_POLO_MK6)
|
||||
assert CarController._is_mqb_a0_car(CAR.VOLKSWAGEN_TCROSS_MK1)
|
||||
assert CarController._is_mqb_a0_car(CAR.SKODA_FABIA_MK4)
|
||||
assert CarController._is_mqb_a0_car(CAR.SKODA_KAMIQ_MK1)
|
||||
assert not CarController._is_mqb_a0_car(CAR.VOLKSWAGEN_GOLF_MK7)
|
||||
|
||||
|
||||
def test_mqb_steering_torque_scale_only_changes_when_toggle_enabled():
|
||||
controller = object.__new__(CarController)
|
||||
controller.CCS = mqbcan
|
||||
assert controller._get_mqb_steering_torque_scale(0.4, False) == 1.0
|
||||
|
||||
assert controller._get_mqb_steering_torque_scale(0.4, True) == 0.8
|
||||
assert controller._get_mqb_steering_torque_scale(4.0, True) == 1.0
|
||||
|
||||
controller.CCS = pqcan
|
||||
assert controller._get_mqb_steering_torque_scale(0.4, True) == 1.0
|
||||
|
||||
|
||||
def test_mqb_a0_resume_spam_requires_toggle_platform_and_window():
|
||||
controller = object.__new__(CarController)
|
||||
controller.CCS = mqbcan
|
||||
controller.is_mqb_a0 = True
|
||||
controller.frame = 10
|
||||
cs = SimpleNamespace(out=SimpleNamespace(standstill=True))
|
||||
|
||||
assert controller._should_spam_mqb_a0_resume(cs, True)
|
||||
|
||||
controller.frame = 20
|
||||
assert not controller._should_spam_mqb_a0_resume(cs, True)
|
||||
|
||||
controller.frame = 10
|
||||
controller.is_mqb_a0 = False
|
||||
assert not controller._should_spam_mqb_a0_resume(cs, True)
|
||||
|
||||
controller.is_mqb_a0 = True
|
||||
assert not controller._should_spam_mqb_a0_resume(cs, False)
|
||||
@@ -0,0 +1,186 @@
|
||||
"""
|
||||
Regression guard for the class of bug fixed in carstate.py's Diagnose_1 (cluster clock,
|
||||
removed) and EPB_1 (stop-and-go hold, now gated on PQ_SNG_ECD): reading a CAN message via
|
||||
`some_cp.vl["MsgName"]["Signal"]` without declaring it in get_can_parsers_pq() lazily adds
|
||||
it via VLDict.__getitem__ -> CANParser._add_message(key, freq=None), which is NOT the same
|
||||
as ignore-alive (that's what math.nan is for -- see
|
||||
iqdbc/can/tests/test_packer_parser.py::test_lazy_add_not_ignore_alive). An undeclared
|
||||
message defaults to "assume ~1Hz, must be seen within ~10s", so if the real car never sends
|
||||
it, CarState.canValid gets stuck False forever.
|
||||
|
||||
Rather than fuzzing every VolkswagenFlagsIQ combination (most are unreachable through
|
||||
interface.py's real detection logic), each fixture below is the CarParams captured from a
|
||||
real konn3kt route for a real car of that variant. We run CarState.update() once (no CAN
|
||||
data needs to be fed -- .vl[...] lazily adds and returns default-zero values regardless of
|
||||
whether the parser has ever seen a real frame) while recording every message name accessed,
|
||||
then assert that set is a subset of what that real car actually transmits (per its captured
|
||||
CAN fingerprint). A message accessed but not in the real fingerprint is exactly the bug
|
||||
class this guards against.
|
||||
"""
|
||||
from iqdbc.can.parser import VLDict
|
||||
from iqdbc.car import structs
|
||||
from iqdbc.car.volkswagen.carstate import CarState
|
||||
from iqdbc.car.volkswagen.values import CAR, Bus
|
||||
|
||||
|
||||
class _RecordingVLDict(VLDict):
|
||||
"""Records every message name read via .vl[...], including ones lazily added for
|
||||
messages never declared in get_can_parsers_pq's message list. Applied by reclassing
|
||||
a live CANParser.vl instance in place (rather than replacing it with a fresh object)
|
||||
so any messages already registered at CANParser construction time, and the parser
|
||||
back-reference _add_message needs, are preserved."""
|
||||
accessed: set[str]
|
||||
|
||||
def __getitem__(self, key):
|
||||
if isinstance(key, str):
|
||||
self.accessed.add(key)
|
||||
return super().__getitem__(key)
|
||||
|
||||
|
||||
def _make_car_params(car_fingerprint, flags, network_location, transmission_type, enable_bsm, pcm_cruise):
|
||||
CP = structs.CarParams.new_message()
|
||||
CP.carFingerprint = car_fingerprint
|
||||
CP.flags = flags
|
||||
CP.radarUnavailable = True
|
||||
CP.networkLocation = network_location
|
||||
CP.transmissionType = transmission_type
|
||||
CP.enableBsm = enable_bsm
|
||||
CP.pcmCruise = pcm_cruise
|
||||
CP.minSteerSpeed = 0.0
|
||||
CP_IQ = structs.IQCarParams()
|
||||
return CP, CP_IQ
|
||||
|
||||
|
||||
# Real per-variant CarParams captured from konn3kt routes (not hand-derived), so each
|
||||
# fixture reflects an actual car rather than a guess at which flag combos are reachable.
|
||||
# known_bus1/known_bus2 are the exact message names present in that car's real CAN
|
||||
# fingerprint. Bus.pt and Bus.aux both listen on physical bus 1 for PQ (CanBus.powertrain
|
||||
# == CanBus.aux == 1); Bus.cam listens on physical bus 2 (CanBus.cam == 2) -- see CanBus in
|
||||
# iqdbc/car/volkswagen/values.py. UNK_* (unrecognized DBC addresses) are dropped.
|
||||
FIXTURES = [
|
||||
dict(
|
||||
name="jetta_mk6_base",
|
||||
route="a0d99b85ff06857b|0000003a--135c88414f",
|
||||
car_fingerprint=CAR.VOLKSWAGEN_JETTA_MK6,
|
||||
flags=2,
|
||||
network_location="gateway",
|
||||
transmission_type="automatic",
|
||||
enable_bsm=False,
|
||||
pcm_cruise=True,
|
||||
known_bus1={
|
||||
'ACC_GRA_Anzeige', 'ACC_System', 'AWV', 'Airbag_1', 'Airbag_2', 'BSG_Last', 'Bremse_1',
|
||||
'Bremse_10', 'Bremse_11', 'Bremse_2', 'Bremse_3', 'Bremse_4', 'Bremse_5', 'Bremse_8',
|
||||
'Bremse_9', 'Diagnose_1', 'Einheiten_1', 'GRA_Neu', 'Gate_Komf_1', 'Gate_Komf_2',
|
||||
'Getriebe_1', 'Getriebe_2', 'Getriebe_4', 'Ident', 'Klima_1', 'Kombi_1', 'Kombi_2',
|
||||
'Kombi_3', 'Lenkhilfe_1', 'Lenkhilfe_2', 'Lenkhilfe_3', 'Lenkwinkel_1', 'Motor_1',
|
||||
'Motor_10', 'Motor_12', 'Motor_2', 'Motor_3', 'Motor_5', 'Motor_6', 'Motor_7', 'Motor_8',
|
||||
'Motor_Bremse', 'Motor_Flexia', 'Soll_Verbauliste_neu', 'Systeminfo_1', 'Waehlhebel_1',
|
||||
},
|
||||
known_bus2={
|
||||
'ACC_GRA_Anzeige', 'ACC_System', 'AWV', 'Airbag_1', 'BSG_Last', 'Bremse_1', 'Bremse_10',
|
||||
'Bremse_11', 'Bremse_2', 'Bremse_3', 'Bremse_5', 'Bremse_8', 'Diagnose_1', 'Einheiten_1',
|
||||
'GRA_Neu', 'Gate_Komf_1', 'Gate_Komf_2', 'Getriebe_1', 'Ident', 'Kombi_1', 'Kombi_2',
|
||||
'Kombi_3', 'Lenkhilfe_2', 'Lenkhilfe_3', 'Lenkwinkel_1', 'Motor_1', 'Motor_10', 'Motor_2',
|
||||
'Motor_3', 'Motor_5', 'Motor_Flexia', 'Soll_Verbauliste_neu', 'Systeminfo_1',
|
||||
},
|
||||
),
|
||||
dict(
|
||||
name="passat_nms_sng_ecd",
|
||||
route="0f53129ed44f6920|00000031--0c1aea511e",
|
||||
car_fingerprint=CAR.VOLKSWAGEN_PASSAT_NMS,
|
||||
flags=524418, # PQ | IQ_LVBS_ALC_MODULE | IQ_PQ_SNG_ECD
|
||||
network_location="gateway",
|
||||
transmission_type="automatic",
|
||||
enable_bsm=False,
|
||||
pcm_cruise=False,
|
||||
known_bus1={
|
||||
'ACC_GRA_Anzeige', 'ACC_System', 'AWV', 'Airbag_1', 'Airbag_2', 'BSG_Last', 'Bremse_1',
|
||||
'Bremse_10', 'Bremse_11', 'Bremse_2', 'Bremse_3', 'Bremse_4', 'Bremse_5', 'Bremse_8',
|
||||
'Bremse_9', 'Diagnose_1', 'EPB_1', 'EPB_2', 'Einheiten_1', 'GRA_Neu', 'Gate_Komf_1',
|
||||
'Gate_Komf_2', 'Getriebe_1', 'Getriebe_2', 'Ident', 'Klima_1', 'Kombi_1', 'Kombi_2',
|
||||
'Kombi_3', 'Lenkhilfe_1', 'Lenkhilfe_2', 'Lenkhilfe_3', 'Lenkwinkel_1', 'Motor_1',
|
||||
'Motor_10', 'Motor_12', 'Motor_13', 'Motor_2', 'Motor_3', 'Motor_5', 'Motor_6', 'Motor_7',
|
||||
'Motor_8', 'Motor_Bremse', 'Motor_Flexia', 'Soll_Verbauliste_neu', 'Systeminfo_1',
|
||||
},
|
||||
known_bus2={
|
||||
'ACC_GRA_Anzeige', 'ACC_System', 'AWV', 'Airbag_1', 'BSG_Last', 'Bremse_1', 'Bremse_10',
|
||||
'Bremse_11', 'Bremse_2', 'Bremse_3', 'Bremse_5', 'Bremse_8', 'Diagnose_1', 'EPB_1',
|
||||
'Einheiten_1', 'GRA_Neu', 'Gate_Komf_1', 'Gate_Komf_2', 'Getriebe_1', 'Ident', 'Kombi_1',
|
||||
'Kombi_2', 'Kombi_3', 'Lenkhilfe_2', 'Lenkhilfe_3', 'Lenkwinkel_1', 'Motor_1', 'Motor_10',
|
||||
'Motor_2', 'Motor_3', 'Motor_5', 'Motor_Flexia', 'Soll_Verbauliste_neu', 'Systeminfo_1',
|
||||
},
|
||||
),
|
||||
dict(
|
||||
name="passat_b7_acc_fts_epb",
|
||||
route="20e3cd4f0d5f39d1|0000008e--274d762bac",
|
||||
car_fingerprint=CAR.VOLKSWAGEN_PASSAT_B7,
|
||||
flags=262146, # PQ | IQ_PQ_ACC_FTS_EPB
|
||||
network_location="gateway",
|
||||
transmission_type="automatic",
|
||||
enable_bsm=True,
|
||||
pcm_cruise=False,
|
||||
known_bus1={
|
||||
'ACC_GRA_Anzeige', 'ACC_System', 'AWV', 'Airbag_1', 'Airbag_2', 'BSG_Last', 'Bremse_1',
|
||||
'Bremse_10', 'Bremse_11', 'Bremse_2', 'Bremse_3', 'Bremse_4', 'Bremse_5', 'Bremse_8',
|
||||
'Bremse_9', 'Daempfer_1', 'Diagnose_1', 'EPB_1', 'Einheiten_1', 'GRA_Neu', 'Gate_Komf_1',
|
||||
'Gate_Komf_2', 'Getriebe_1', 'Getriebe_2', 'Getriebe_4', 'HCA_1', 'Ident', 'Klima_1',
|
||||
'Kombi_1', 'Kombi_2', 'Kombi_3', 'Lenkhilfe_1', 'Lenkhilfe_2', 'Lenkhilfe_3',
|
||||
'Lenkwinkel_1', 'Motor_1', 'Motor_10', 'Motor_12', 'Motor_2', 'Motor_3', 'Motor_5',
|
||||
'Motor_6', 'Motor_7', 'Motor_8', 'Motor_Bremse', 'Motor_Flexia', 'Parkhilfe_01',
|
||||
'Soll_Verbauliste_neu', 'Systeminfo_1', 'Waehlhebel_1',
|
||||
},
|
||||
known_bus2={
|
||||
'ACC_GRA_Anzeige', 'ACC_System', 'AWV', 'Airbag_1', 'BSG_Last', 'Bremse_1', 'Bremse_10',
|
||||
'Bremse_11', 'Bremse_2', 'Bremse_3', 'Bremse_5', 'Bremse_8', 'Diagnose_1', 'EPB_1',
|
||||
'Einheiten_1', 'GRA_Neu', 'Gate_Komf_1', 'Gate_Komf_2', 'Getriebe_1', 'HCA_1', 'Ident',
|
||||
'Kombi_1', 'Kombi_2', 'Kombi_3', 'LDW_Status', 'Lenkhilfe_2', 'Lenkhilfe_3',
|
||||
'Lenkwinkel_1', 'Motor_1', 'Motor_10', 'Motor_2', 'Motor_3', 'Motor_5', 'Motor_Flexia',
|
||||
'Parkhilfe_01', 'RDK_Status', 'SWA_1', 'Soll_Verbauliste_neu', 'Systeminfo_1',
|
||||
},
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class TestVolkswagenPqCanValid:
|
||||
def test_only_reads_messages_the_real_car_sends(self, subtests):
|
||||
for fixture in FIXTURES:
|
||||
with subtests.test(car=fixture["name"]):
|
||||
CP, CP_IQ = _make_car_params(
|
||||
fixture["car_fingerprint"], fixture["flags"], fixture["network_location"],
|
||||
fixture["transmission_type"], fixture["enable_bsm"], fixture["pcm_cruise"],
|
||||
)
|
||||
|
||||
CS = CarState(CP, CP_IQ)
|
||||
can_parsers = CS.get_can_parsers(CP, CP_IQ)
|
||||
|
||||
recorders = {}
|
||||
for bus, parser in can_parsers.items():
|
||||
if parser is None:
|
||||
continue
|
||||
parser.vl.__class__ = _RecordingVLDict
|
||||
parser.vl.accessed = set()
|
||||
recorders[bus] = parser.vl
|
||||
|
||||
# no CAN data is fed: .vl[...] lazily adds and returns default-zero values
|
||||
# regardless of whether the parser has ever seen a real frame, so this alone
|
||||
# is enough to harvest every message name update_pq() touches for this variant
|
||||
CS.update(can_parsers)
|
||||
|
||||
accessed_bus1 = recorders[Bus.pt].accessed | recorders[Bus.aux].accessed
|
||||
accessed_bus2 = recorders[Bus.cam].accessed
|
||||
|
||||
extra_bus1 = accessed_bus1 - fixture["known_bus1"]
|
||||
extra_bus2 = accessed_bus2 - fixture["known_bus2"]
|
||||
|
||||
assert not extra_bus1, (
|
||||
f"{fixture['name']}: code reads {sorted(extra_bus1)} on bus 1 (pt/aux) but the "
|
||||
f"real car (route {fixture['route']}) never transmits it -- this needs to be "
|
||||
f"gated behind whatever flag makes it optional, or declared with math.nan if it's "
|
||||
f"genuinely on-demand/rare, not read unconditionally"
|
||||
)
|
||||
assert not extra_bus2, (
|
||||
f"{fixture['name']}: code reads {sorted(extra_bus2)} on bus 2 (cam) but the "
|
||||
f"real car (route {fixture['route']}) never transmits it -- this needs to be "
|
||||
f"gated behind whatever flag makes it optional, or declared with math.nan if it's "
|
||||
f"genuinely on-demand/rare, not read unconditionally"
|
||||
)
|
||||
@@ -0,0 +1,22 @@
|
||||
import pytest
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("candidate, flags, expected", [
|
||||
(CAR.VOLKSWAGEN_PASSAT_B7, VolkswagenFlags.PQ, PASSAT_B7_STOPPING_SPEED),
|
||||
(CAR.VOLKSWAGEN_JETTA_MK6, VolkswagenFlags.PQ, PQ_STOPPING_SPEED),
|
||||
(CAR.VOLKSWAGEN_GOLF_MK7, 0, 0.0),
|
||||
(CAR.VOLKSWAGEN_ID4_MK1, VolkswagenFlags.MEB, 0.0),
|
||||
])
|
||||
def test_stopping_speed_override(candidate, flags, expected):
|
||||
assert get_longitudinal_stopping_speed_override(candidate, flags) == expected
|
||||
|
||||
|
||||
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
|
||||
@@ -43,6 +43,10 @@ class TestVolkswagenPlatformConfigs:
|
||||
if len(shared_chassis_codes) == 0:
|
||||
continue
|
||||
|
||||
# A shared chassis code is unambiguous when the VIN WMI separates the candidates.
|
||||
if platform.config.wmis.isdisjoint(comp.config.wmis):
|
||||
continue
|
||||
|
||||
platform_model_years = getattr(platform.config, "model_years", set())
|
||||
comp_model_years = getattr(comp.config, "model_years", set())
|
||||
if platform_model_years and comp_model_years and platform_model_years.isdisjoint(comp_model_years):
|
||||
@@ -51,10 +55,13 @@ class TestVolkswagenPlatformConfigs:
|
||||
assert set() == shared_chassis_codes, f"Shared chassis codes: {comp}"
|
||||
|
||||
def test_custom_fuzzy_fingerprinting(self, subtests):
|
||||
all_radar_fw = list({fw for ecus in FW_VERSIONS.values() for fw in ecus[Ecu.fwdRadar, 0x757, None]})
|
||||
all_radar_fw = list({fw for ecus in FW_VERSIONS.values() for fw in ecus.get((Ecu.fwdRadar, 0x757, None), [])})
|
||||
|
||||
for platform in CAR:
|
||||
with subtests.test(platform=platform.name):
|
||||
# Fuzzy matching keys off the radar ECU (CHECK_FUZZY_ECUS), so a platform that
|
||||
# declares no radar ECU can never be VIN-matched and should never be expected to match.
|
||||
platform_has_radar = (Ecu.fwdRadar, 0x757, None) in FW_VERSIONS.get(platform, {})
|
||||
for wmi in WMI:
|
||||
for chassis_code in platform.config.chassis_codes | {"00"}:
|
||||
platform_model_years = getattr(platform.config, "model_years", set())
|
||||
@@ -70,7 +77,7 @@ class TestVolkswagenPlatformConfigs:
|
||||
for radar_fw in random.sample(all_radar_fw, 5) + [b'\xf1\x875Q0907572G \xf1\x890571', b'\xf1\x877H9907572AA\xf1\x890396']:
|
||||
model_year_match = len(platform_model_years) == 0 or model_year in platform_model_years
|
||||
should_match = ((wmi in platform.config.wmis and chassis_code in platform.config.chassis_codes and model_year_match) and
|
||||
radar_fw in all_radar_fw)
|
||||
radar_fw in all_radar_fw and platform_has_radar)
|
||||
|
||||
live_fws = {(0x757, None): [radar_fw]}
|
||||
matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(live_fws, vin, FW_VERSIONS)
|
||||
@@ -106,3 +113,17 @@ def test_button_enable_recovers_once_cruise_fault_clears():
|
||||
)]
|
||||
|
||||
assert state.update_button_enable(button_events)
|
||||
|
||||
|
||||
def test_pq_hca_ready_does_not_complete_eps_initialization():
|
||||
state = object.__new__(CarState)
|
||||
state.eps_init_complete = False
|
||||
|
||||
state.frame = 0
|
||||
assert state.update_hca_state("READY", ready_confirms_init=False) == (True, False)
|
||||
|
||||
state.frame = 317
|
||||
assert state.update_hca_state("FAULT", ready_confirms_init=False) == (True, False)
|
||||
|
||||
state.frame = 1001
|
||||
assert state.update_hca_state("FAULT", ready_confirms_init=False) == (False, True)
|
||||
|
||||
@@ -35,6 +35,10 @@ class CanBus(CanBusBase):
|
||||
# NetworkLocation.gateway: powertrain CAN
|
||||
return 1
|
||||
|
||||
@property
|
||||
def powertrain(self) -> int:
|
||||
return 1
|
||||
|
||||
@property
|
||||
def main(self) -> int:
|
||||
return 1
|
||||
@@ -49,17 +53,11 @@ class CanBus(CanBusBase):
|
||||
# ADAS / Extended CAN, side of the relay with the ACC radar
|
||||
return 2
|
||||
|
||||
@property
|
||||
def eps(self) -> int:
|
||||
return 4
|
||||
|
||||
@property
|
||||
def car(self) -> int:
|
||||
return 6
|
||||
|
||||
|
||||
# Extra Tolerances For Road Variance
|
||||
AVERAGE_ROAD_ROLL = 0.06
|
||||
PQ_STOPPING_SPEED = 1.5 * CV.KPH_TO_MS
|
||||
PASSAT_B7_STOPPING_SPEED = 0.55 * CV.KPH_TO_MS
|
||||
PASSAT_B7_STOP_ACCEL = -0.55
|
||||
|
||||
|
||||
class CarControllerParams:
|
||||
@@ -84,6 +82,8 @@ class CarControllerParams:
|
||||
AEB_CONTROL_STEP = 2 # ACC_10 frequency 50Hz
|
||||
AEB_HUD_STEP = 20 # ACC_15 frequency 5Hz
|
||||
VW_LOW_SPEED_STATE_SPEED = 0.5 # m/s; below this, always force starting or stopping in MQB legacy long
|
||||
SNG_HANDOFF_SPEED = 5.0 * CV.KPH_TO_MS
|
||||
SNG_HOLD_DECEL_MAX = -0.1
|
||||
|
||||
# Documented lateral limits: 3.00 Nm max, rate of change 5.00 Nm/sec.
|
||||
# MQB vs PQ maximums are shared, but rate-of-change limited differently
|
||||
@@ -99,7 +99,8 @@ class CarControllerParams:
|
||||
STEER_LOW_TORQUE = int(STEER_MAX * 0.20) # Steer timer mitigation performed when torque output under 20%
|
||||
STEER_TIME_LOW_TORQUE = 0.5 # Wait for this duration of STEER_LOW_TORQUE to begin mitigation
|
||||
STEER_TIME_STUCK_TORQUE = 1.9 # EPS limits same torque to 6 seconds, reset timer 3x within that period
|
||||
STEER_TIME_RESET = 1.1 # Duration of HCA disable needed for effective EPS timer reset
|
||||
STEER_TIME_RESET = 1.1 # Duration of HCA disable needed for effective EPS timer reset'
|
||||
IQ_PQ_UNAVAILABLE_HUD_FRAMES = 25
|
||||
|
||||
DEFAULT_MIN_STEER_SPEED = 0.4 # m/s, newer EPS racks fault below this speed, don't show a low speed alert
|
||||
|
||||
@@ -115,8 +116,8 @@ class CarControllerParams:
|
||||
self.LDW_STEP = 5 # LDW_1 message frequency 20Hz
|
||||
self.ACC_HUD_STEP = 4 # ACC_GRA_Anzeige frequency 25Hz
|
||||
self.STEER_DRIVER_ALLOWANCE = 80 # Driver intervention threshold 0.8 Nm
|
||||
self.STEER_DELTA_UP = 10 # Max HCA reached in 0.60s (STEER_MAX / (50Hz * 0.60))
|
||||
self.STEER_DELTA_DOWN = 10 # Min HCA reached in 0.60s (STEER_MAX / (50Hz * 0.60))
|
||||
self.STEER_DELTA_UP = 150 # Max HCA reached in 0.60s (STEER_MAX / (50Hz * 0.60))
|
||||
self.STEER_DELTA_DOWN = 300 # Min HCA reached in 0.60s (STEER_MAX / (50Hz * 0.60))
|
||||
|
||||
if CP.transmissionType == TransmissionType.automatic:
|
||||
self.shifter_values = can_define.dv["Getriebe_1"]["GE1_Wahl_Pos"]
|
||||
@@ -284,6 +285,10 @@ class VolkswagenSafetyFlags(IntFlag):
|
||||
ALLOW_LONG_ACCEL_WITH_GAS_PRESSED = 8
|
||||
DISABLE_RADAR = 16
|
||||
PQ_ALC_MODULE = 32
|
||||
PQ_LOWLINE = 64
|
||||
PQ_NO_CAM_BUS = 128
|
||||
PQ_ACC_FTS_EPB = 256
|
||||
PQ_SNG_ECD = 512
|
||||
|
||||
|
||||
class VolkswagenFlags(IntFlag):
|
||||
@@ -311,6 +316,10 @@ class VolkswagenFlagsIQ(IntFlag):
|
||||
IQ_CC_ONLY = 1 << 5 # CC only mode with radar (has AEB)
|
||||
IQ_CC_ONLY_NO_RADAR = 1 << 6 # CC only mode without radar
|
||||
IQ_LVBS_ALC_MODULE = 1 << 7 # IQ.Lvbs VW ALC hardware module present / intended active path
|
||||
IQ_PQ_LOWLINE = 1 << 17 # Non-ECAN lateral-only PQ: bus 0 dead, TX on bus 1 (ptCAN)
|
||||
IQ_PQ_ACC_FTS_EPB = 1 << 18 # B7 TRW450: ACC FtS + EPB hold, Motor_1 resume spoof on bus 1
|
||||
IQ_PQ_SNG_ECD = 1 << 19
|
||||
IQ_PQ_TIMEBOMB = 1 << 20
|
||||
|
||||
|
||||
RADAR_DISABLE_STATE = {"error": False}
|
||||
@@ -333,6 +342,7 @@ class VolkswagenMQBPlatformConfig(PlatformConfig):
|
||||
# on camera-integrated cars, as we lose too many ECUs to reliably identify the vehicle
|
||||
chassis_codes: set[str] = field(default_factory=set)
|
||||
wmis: set[WMI] = field(default_factory=set)
|
||||
model_years: set[str] = field(default_factory=set)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -542,24 +552,35 @@ class CAR(Platforms):
|
||||
VolkswagenCarSpecs(mass=1551, wheelbase=2.79),
|
||||
chassis_codes={"3C", "3G"},
|
||||
wmis={WMI.VOLKSWAGEN_EUROPE_CAR},
|
||||
model_years={"F", "G", "H", "J", "K", "L", "M", "N"}, # 2015-2022
|
||||
)
|
||||
VOLKSWAGEN_PASSAT_MK7 = VolkswagenPQPlatformConfig(
|
||||
[VWCarDocs("Volkswagen Passat 2.0 TDI 2014")],
|
||||
VolkswagenCarSpecs(mass=1836, wheelbase=2.70, steerRatio=13.0, minSteerSpeed=31 * CV.KPH_TO_MS),
|
||||
chassis_codes={"3C"},
|
||||
wmis={WMI.VOLKSWAGEN_EUROPE_CAR},
|
||||
model_years={"E"}, # 2014
|
||||
)
|
||||
VOLKSWAGEN_PASSAT_NMS = VolkswagenPQPlatformConfig(
|
||||
[VWCarDocs("Volkswagen Passat NMS 2015-17")],
|
||||
VolkswagenCarSpecs(mass=1503, wheelbase=2.80),
|
||||
chassis_codes={"A3"},
|
||||
wmis={WMI.VOLKSWAGEN_USA_CAR},
|
||||
# NMS and NMS+ share chassis code A3; disambiguate by model year
|
||||
model_years={"F", "G", "H"}, # 2015-2017
|
||||
)
|
||||
VOLKSWAGEN_PASSAT_NMS_PLUS = VolkswagenPQPlatformConfig(
|
||||
[VWCarDocs("Volkswagen Passat NMS 2018-22")],
|
||||
VolkswagenCarSpecs(mass=1503, wheelbase=2.80, minEnableSpeed=20 * CV.KPH_TO_MS),
|
||||
chassis_codes={"A3"},
|
||||
wmis={WMI.VOLKSWAGEN_USA_CAR},
|
||||
model_years={"J", "K", "L", "M", "N"}, # 2018-2022
|
||||
)
|
||||
VOLKSWAGEN_PASSAT_B7 = VolkswagenPQPlatformConfig(
|
||||
[VWCarDocs("Volkswagen Passat B7 2008-2011")],
|
||||
VolkswagenCarSpecs(mass=1503, wheelbase=2.712, steerRatio=16.4, minSteerSpeed=0),
|
||||
chassis_codes={"A3"},
|
||||
wmis={WMI.VOLKSWAGEN_USA_CAR},
|
||||
)
|
||||
VOLKSWAGEN_POLO_MK6 = VolkswagenMQBPlatformConfig(
|
||||
[
|
||||
@@ -573,12 +594,19 @@ class CAR(Platforms):
|
||||
VOLKSWAGEN_SHARAN_MK2 = VolkswagenPQPlatformConfig(
|
||||
[
|
||||
VWCarDocs("Volkswagen Sharan 2018-22"),
|
||||
VWCarDocs("SEAT Alhambra 2018-20"),
|
||||
],
|
||||
VolkswagenCarSpecs(mass=1639, wheelbase=2.92),
|
||||
chassis_codes={"7N"},
|
||||
wmis={WMI.VOLKSWAGEN_EUROPE_CAR},
|
||||
)
|
||||
SEAT_ALHAMBRA_MK1 = VolkswagenPQPlatformConfig(
|
||||
[
|
||||
VWCarDocs("SEAT Alhambra 2018-20"),
|
||||
],
|
||||
VolkswagenCarSpecs(mass=1639, wheelbase=2.92, minSteerSpeed=50 * CV.KPH_TO_MS),
|
||||
chassis_codes={"7N"},
|
||||
wmis={WMI.SEAT},
|
||||
)
|
||||
VOLKSWAGEN_TAOS_MK1 = VolkswagenMQBPlatformConfig(
|
||||
[VWCarDocs("Volkswagen Taos 2022-24")],
|
||||
VolkswagenCarSpecs(mass=1498, wheelbase=2.69),
|
||||
@@ -880,4 +908,24 @@ FW_QUERY_CONFIG = FwQueryConfig(
|
||||
match_fw_to_car_fuzzy=match_fw_to_car_fuzzy,
|
||||
)
|
||||
|
||||
MQB_A0_CARS = {
|
||||
CAR.VOLKSWAGEN_POLO_MK6,
|
||||
CAR.VOLKSWAGEN_TCROSS_MK1,
|
||||
CAR.SKODA_FABIA_MK4,
|
||||
CAR.SKODA_KAMIQ_MK1,
|
||||
}
|
||||
|
||||
|
||||
def get_longitudinal_stopping_speed_override(candidate: CAR, flags: int) -> float:
|
||||
if candidate == CAR.VOLKSWAGEN_PASSAT_B7:
|
||||
return PASSAT_B7_STOPPING_SPEED
|
||||
if flags & VolkswagenFlags.PQ:
|
||||
return PQ_STOPPING_SPEED
|
||||
return 0.0
|
||||
|
||||
|
||||
def apply_pq_stopping_accel(candidate: CAR, accel: float, stopping: bool) -> float:
|
||||
return PASSAT_B7_STOP_ACCEL if candidate == CAR.VOLKSWAGEN_PASSAT_B7 and stopping else accel
|
||||
|
||||
|
||||
DBC = CAR.create_dbc_map()
|
||||
|
||||
@@ -3,6 +3,13 @@ from pathlib import Path
|
||||
|
||||
env = Environment(ENV=os.environ)
|
||||
|
||||
# short colored build output, if the top-level pretty tool is present (main-repo build)
|
||||
_pretty = Dir('#site_scons/site_tools').File('pretty.py')
|
||||
if _pretty.exists():
|
||||
env.Tool('pretty', toolpath=[_pretty.dir.abspath])
|
||||
if not hasattr(env, 'PrettyAction'):
|
||||
env.AddMethod(lambda e, cmd, label, **kw: Action(cmd), 'PrettyAction')
|
||||
|
||||
generator = File("generator/generator.py")
|
||||
|
||||
source_files = [
|
||||
@@ -27,5 +34,5 @@ output_files += [
|
||||
generated = env.Command(
|
||||
target=list(set(output_files)),
|
||||
source=[generator] + source_files,
|
||||
action="python3 ${SOURCES[0]}",
|
||||
action=env.PrettyAction("python3 ${SOURCES[0]}", 'GEN'),
|
||||
)
|
||||
|
||||
@@ -204,7 +204,7 @@ BO_ 605 DAS_road: 6 XXX
|
||||
BO_ 1160 DAS_steeringControl: 4 PARTY
|
||||
SG_ DAS_steeringControlChecksum : 24|8@1+ (1,0) [0|255] "" aps
|
||||
SG_ DAS_steeringControlCounter : 16|4@1+ (1,0) [0|15] "" aps
|
||||
SG_ DAS_steeringControlType : 23|2@0+ (1,0) [0|3] "" aps
|
||||
SG_ DAS_steeringControlType : 23|3@0+ (1,0) [0|7] "" aps
|
||||
SG_ DAS_steeringAngleRequest : 6|15@0+ (0.1,-1638.35) [-1638.35|1638.35] "deg" aps
|
||||
SG_ DAS_steeringHapticRequest : 7|1@0+ (1,0) [0|1] "" aps
|
||||
|
||||
@@ -426,7 +426,7 @@ VAL_ 599 DI_uiSpeedUnits 0 "DI_SPEED_MPH" 1 "DI_SPEED_KPH" ;
|
||||
VAL_ 599 DI_uiSpeed 255 "DI_UI_SPEED_SNA" ;
|
||||
VAL_ 599 DI_vehicleSpeed 4095 "SNA" ;
|
||||
VAL_ 637 APS_eacAllow 0 "INHIBIT" 1 "ALLOW" 2 "RESERVED" 3 "SNA";
|
||||
VAL_ 1160 DAS_steeringControlType 2 "LANE_KEEP_ASSIST" 0 "NONE" 1 "ANGLE_CONTROL" 3 "EMERGENCY_LANE_KEEP" ;
|
||||
VAL_ 1160 DAS_steeringControlType 2 "LANE_KEEP_ASSIST" 0 "NONE" 1 "ANGLE_CONTROL" 3 "EMERGENCY_LANE_KEEP" 4 "FSD" ;
|
||||
VAL_ 1160 DAS_steeringAngleRequest 16384 "ZERO_ANGLE" ;
|
||||
VAL_ 297 SCCM_steeringAngleValidity 3 "SNA" 2 "INIT" 0 "INVALID" 1 "VALID" ;
|
||||
VAL_ 297 SCCM_steeringAngleSensorStatus 0 "OK" 1 "INIT" 2 "ERROR" 3 "ERROR_INIT" ;
|
||||
|
||||
@@ -197,15 +197,24 @@ BO_ 1001 DAS_bodyControls: 8 VEH
|
||||
SG_ DAS_headlightRequest : 0|2@1+ (1,0) [0|3] "" aps
|
||||
SG_ DAS_hazardLightRequest : 2|2@1+ (1,0) [0|3] "" aps
|
||||
SG_ DAS_wiperSpeed : 4|4@1+ (1,0) [0|15] "" aps
|
||||
SG_ DAS_turnIndicatorRequest : 8|2@1+ (1,0) [0|3] "" aps
|
||||
SG_ DAS_highLowBeamDecision : 10|2@1+ (1,0) [0|3] "" aps
|
||||
SG_ DAS_heaterRequest : 12|2@1+ (1,0) [0|2] "" aps
|
||||
SG_ DAS_turnIndicatorRequestReason : 17|4@1+ (1,0) [0|8] "" aps
|
||||
SG_ DAS_autopilotActive : 24|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ DAS_accActive : 29|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ DAS_turnIndicatorRequest : 8|3@1+ (1,0) [0|4] "" aps
|
||||
SG_ DAS_highLowBeamDecision : 11|2@1+ (1,0) [0|3] "" aps
|
||||
SG_ DAS_heaterRequest : 13|2@1+ (1,0) [0|2] "" aps
|
||||
SG_ DAS_highLowBeamOffReason : 15|3@1+ (1,0) [0|5] "" aps
|
||||
SG_ DAS_turnIndicatorRequestReason : 18|4@1+ (1,0) [0|12] "" aps
|
||||
SG_ DAS_dynamicBrakeLightRequest : 22|1@1+ (1,0) [0|1] "" aps
|
||||
SG_ DAS_radarHeaterRequest : 23|1@1+ (1,0) [0|1] "" aps
|
||||
SG_ DAS_ahlbOverride : 24|1@1+ (1,0) [0|1] "" aps
|
||||
SG_ DAS_mirrorFoldRequest : 25|2@1+ (1,0) [0|3] "" aps
|
||||
SG_ DAS_bodyControlsCounter : 52|4@1+ (1,0) [0|15] "" aps
|
||||
SG_ DAS_bodyControlsChecksum : 56|8@1+ (1,0) [0|255] "" aps
|
||||
|
||||
BO_ 994 VCLEFT_lightStatus: 7 VEH
|
||||
SG_ VCLEFT_turnSignalStatus : 4|2@1+ (1,0) [0|3] "" XXX
|
||||
|
||||
BO_ 995 VCRIGHT_lightStatus: 2 VEH
|
||||
SG_ VCRIGHT_turnSignalStatus : 4|2@1+ (1,0) [0|3] "" XXX
|
||||
|
||||
BO_ 1013 ID3F5VCFRONT_lighting: 8 VEH
|
||||
SG_ VCFRONT_lowBeamsCalibrated : 62|1@1+ (1,0) [0|1] "" Receiver
|
||||
SG_ VCFRONT_lowBeamsOnForDRL : 61|1@1+ (1,0) [0|1] "" Receiver
|
||||
@@ -388,5 +397,10 @@ BO_ 826 ID33AUI_rangeSOC: 8 VehicleBus
|
||||
BO_ 306 ID132HVBattAmpVolt: 8 VehicleBus
|
||||
SG_ BattVoltage132 : 0|16@1+ (0.01,0) [0|655.35] "V" Receiver
|
||||
|
||||
BO_ 950 ID3B6UI_odometer: 8 VehicleBus
|
||||
SG_ UI_odometer : 0|32@1+ (0.001,0) [0|4294967.295] "km" Receiver
|
||||
SG_ UI_odometerCounter : 52|4@1+ (1,0) [0|15] "" Receiver
|
||||
SG_ UI_odometerChecksum : 56|8@1+ (1,0) [0|255] "" Receiver
|
||||
|
||||
BO_ 658 ID292BMS_SOC: 8 VehicleBus
|
||||
SG_ SOCUI292 : 10|10@1+ (0.1,0) [0|102.3] "%" Receiver
|
||||
|
||||
@@ -541,21 +541,21 @@ BO_ 1437 mRemotestart_FFB: 8 Vector__XXX
|
||||
SG_ RSF_Tastencode_2 : 8|8@1+ (1,0) [1|255] "" Vector__XXX
|
||||
SG_ RSF_Tastencode_Maske : 16|8@1+ (1,0) [1|255] "" Vector__XXX
|
||||
|
||||
BO_ 640 Motor_1: 8 XXX
|
||||
SG_ Fahrerwunschmoment : 56|8@1+ (0.39,0) [0|99] "MDI" XXX
|
||||
SG_ mechanisches_Motor_Verlustmomen : 48|8@1+ (0.39,0) [0|99] "MDI" XXX
|
||||
SG_ Fahrpedalwert_oder_Drosselklapp : 40|8@1+ (0.4,0) [0|101.6] "%" XXX
|
||||
SG_ inneres_Motor_Moment_ohne_exter : 32|8@1+ (0.39,0) [0|99] "MDI" XXX
|
||||
SG_ Motordrehzahl : 16|16@1+ (0.25,0) [0|16256] "U/min" XXX
|
||||
SG_ inneres_Motor_Moment : 8|8@1+ (0.39,0) [0|99] "MDI" XXX
|
||||
SG_ Momentenangaben_ungenau : 7|1@1+ (1,0) [0|0] "" XXX
|
||||
SG_ Fehlerstatus_Getriebe_Momentene : 6|1@1+ (1,0) [0|0] "" XXX
|
||||
SG_ Fehlerstatus_Brems_Momenteneing : 5|1@1+ (1,0) [0|0] "" XXX
|
||||
SG_ Time_Out_Bremsen_Botschaft : 4|1@1+ (1,0) [0|0] "" XXX
|
||||
SG_ Kupplungsschalter : 3|1@1+ (1,0) [0|0] "" XXX
|
||||
SG_ Kickdownschalter : 2|1@1+ (1,0) [0|0] "" XXX
|
||||
SG_ Fahrpedalwert_ungenau__Motor_1_ M : 1|1@1+ (1,0) [0|0] "" XXX
|
||||
SG_ Leergasinformation : 0|1@1+ (1,0) [0|0] "" XXX
|
||||
BO_ 640 Motor_1: 8 Motor
|
||||
SG_ MO1_Wunschmo : 56|8@1+ (0.39,0) [0|99.06] "%" XXX
|
||||
SG_ MO1_Verlustmo : 48|8@1+ (0.39,0) [0|99.06] "%" XXX
|
||||
SG_ MO1_Pedalwert : 40|8@1+ (0.4,0) [0|101.6] "%" XXX
|
||||
SG_ MO1_Mo_o_ex : 32|8@1+ (0.39,0) [0|99.06] "%" XXX
|
||||
SG_ MO1_Drehzahl : 16|16@1+ (0.25,0) [0|16256] "1/min" XXX
|
||||
SG_ MO1_Mo_m_ex : 8|8@1+ (0.39,0) [0|99.06] "%" XXX
|
||||
SG_ MO1_Sta_MotMo : 7|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ MO1_Sta_Getr : 6|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ MO1_Sta_Bremse : 5|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ MO1_TiOut_Br : 4|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ MO1_Kup_schalt : 3|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ MO1_Kickdown : 2|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ MO1_Sta_Pedal : 1|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ MO1_Leergas : 0|1@1+ (1,0) [0|1] "" XXX
|
||||
|
||||
BO_ 262 Master_3: 8 XXX
|
||||
SG_ Frei_Master_3_1 : 56|8@1+ (1,0) [0|0] "" XXX
|
||||
@@ -1353,6 +1353,12 @@ BO_ 982 APD_1: 8 XXX
|
||||
SG_ APD_AngleOffSet : 42|11@1+ (0.01,-10) [-10|10.47] "deg" XXX
|
||||
SG_ APD_GripFactor : 53|11@1+ (0.001,0) [0|2.047] "" XXX
|
||||
|
||||
BO_ 983 SNG_1: 8 XXX
|
||||
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
|
||||
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
|
||||
SG_ SNG_HandoffActive : 12|1@1+ (1,0) [0|1] "" XXX
|
||||
SG_ SNG_DecelReq : 16|8@1+ (0.048,-7.968) [-7.968|4.224] "Unit_MeterPerSeconSquar" XXX
|
||||
|
||||
BO_ 210 HCA_1: 5 XXX
|
||||
SG_ CHECKSUM : 0|8@1+ (1,0) [0|15] "" XXX
|
||||
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,3 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
"""
|
||||
|
||||
from enum import StrEnum
|
||||
from collections import namedtuple
|
||||
|
||||
@@ -30,7 +26,6 @@ class AolCarController:
|
||||
self.lkas_icon = 0
|
||||
self.lfa_icon = 0
|
||||
|
||||
# display LFA "white_wheel" and LKAS "White car + lanes" when not CC.latActive
|
||||
def aol_status_update(self, CC: structs.CarControl, CC_IQ: structs.IQCarControl, frame: int) -> AolDataIQ:
|
||||
enable_aol = CC_IQ.aol.available
|
||||
|
||||
@@ -55,7 +50,6 @@ class AolCarController:
|
||||
else:
|
||||
lkas_icon = 2 if enabled else 1
|
||||
|
||||
# Override common signals for KIA_OPTIMA_G4 and KIA_OPTIMA_G4_FL
|
||||
if CP.carFingerprint in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.HYUNDAI_KONA_NON_SCC):
|
||||
lkas_icon = 3 if (self.aol.lat_active if self.aol.enable_aol else enabled) else 1
|
||||
|
||||
@@ -85,7 +79,7 @@ class AolCarState(AolCarStateBase):
|
||||
pass
|
||||
|
||||
def get_main_cruise(self, ret: structs.CarState) -> bool:
|
||||
if self.CP_IQ.flags & HyundaiFlagsIQ.LONGITUDINAL_MAIN_CRUISE_TOGGLEABLE:
|
||||
if self.CP_IQ.flags & HyundaiFlagsIQ.MAIN_BTN_LONG_TOGGLE:
|
||||
if any(be.type == ButtonType.mainCruise and be.pressed for be in ret.buttonEvents):
|
||||
self.main_cruise_enabled = not self.main_cruise_enabled
|
||||
else:
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
"""
|
||||
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
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
"""
|
||||
|
||||
from iqdbc.car import uds
|
||||
from iqdbc.car.carlog import carlog
|
||||
from iqdbc.car.isotp_parallel_query import IsoTpParallelQuery
|
||||
|
||||
@@ -19,30 +19,13 @@ class EnhancedSmartCruiseControl:
|
||||
return ESCC_MSG
|
||||
|
||||
def update_car_state(self, car_state):
|
||||
"""
|
||||
This method is invoked by the CarController to update the car state on the ESCC object.
|
||||
The updated state is then used to update SCC12 with the current car state values received through ESCC.
|
||||
:param car_state:
|
||||
:return:
|
||||
"""
|
||||
self.car_state = car_state
|
||||
|
||||
def update_scc12(self, values):
|
||||
"""
|
||||
Update SCC12 with the current car state values received through ESCC.
|
||||
These values are sourced directly from the car's SCC radar and provide a more reliable source for AEB and FCA alerts.
|
||||
:param values: SCC12 to be sent in dictionary form before being packed
|
||||
:return: Nothing. SCC12 is updated in place.
|
||||
"""
|
||||
values["AEB_CmdAct"] = self.car_state.escc_cmd_act
|
||||
values["CF_VSM_Warn"] = self.car_state.escc_aeb_warning
|
||||
values["CF_VSM_DecCmdAct"] = self.car_state.escc_aeb_dec_cmd_act
|
||||
values["CR_VSM_DecCmd"] = self.car_state.escc_aeb_dec_cmd
|
||||
# TODO-IQ: we should read it from the car's settings and use that value.
|
||||
# It may not be ideal to set this here directly.
|
||||
# Observed flickering on the dashboard settings switching between "deactivated" and "active assistance" when sending AEB_Status = 1.
|
||||
# These values could differ from the user's configuration from the car's settings.
|
||||
# This indicates that SCC12 likely displays it on the dashboard, and another FCA message may also cause it to appear.
|
||||
values["AEB_Status"] = 2 # AEB enabled
|
||||
|
||||
|
||||
|
||||
@@ -13,19 +13,6 @@ FW_VERSIONS_EXT = {
|
||||
b'\xf1\x00CDH LKAS AT EUR LHD 1.00 1.01 99211-CR700 931',
|
||||
],
|
||||
},
|
||||
# TODO-IQ: HYUNDAI_KONA_EV_NON_SCC has the same FW versions as HYUNDAI_KONA_EV, in the future we may
|
||||
# allow similar FW versions across different platforms
|
||||
# CAR.HYUNDAI_KONA_EV_NON_SCC: {
|
||||
# (Ecu.abs, 0x7d1, None): [
|
||||
# b'\xf1\x00OS IEB \x02 212 \x11\x13 58520-K4000',
|
||||
# ],
|
||||
# (Ecu.eps, 0x7d4, None): [
|
||||
# b'\xf1\x00OS MDPS C 1.00 1.04 56310K4000\x00 4OEDC104',
|
||||
# ],
|
||||
# (Ecu.fwdCamera, 0x7c4, None): [
|
||||
# b'\xf1\x00OSE LKAS AT USA LHD 1.00 1.00 95740-K4100 W40',
|
||||
# ],
|
||||
# },
|
||||
CAR.GENESIS_G70_2021_NON_SCC: {
|
||||
(Ecu.eps, 0x7d4, None): [
|
||||
b'\xf1\x00IK MDPS R 1.00 1.08 57700-G9200 4I2CL108',
|
||||
@@ -38,9 +25,6 @@ FW_VERSIONS_EXT = {
|
||||
],
|
||||
},
|
||||
CAR.HYUNDAI_KONA_NON_SCC: {
|
||||
# (Ecu.abs, 0x7d1, None): [
|
||||
# b'\xf1\x816V5RAJ00040.ELF\xf1\x00\x00\x00\x00\x00\x00\x00',
|
||||
# ],
|
||||
(Ecu.eps, 0x7d4, None): [
|
||||
b'\xf1\x00OS MDPS C 1.00 1.05 56310J9030\x00 4OSDC105',
|
||||
b'\xf1\x00OS MDPS C 1.00 1.04 56310J9030\x00 4OSDC104',
|
||||
@@ -60,12 +44,6 @@ FW_VERSIONS_EXT = {
|
||||
(Ecu.fwdCamera, 0x7C4, None): [
|
||||
b'\xf1\x00BD LKAS AT USA LHD 1.00 1.02 95740-M6000 J31',
|
||||
],
|
||||
# (Ecu.abs, 0x7d1, None): [
|
||||
# b'\xf1\x816VFRAF00018.ELF\xf1\x00\x00\x00\x00\x00\x00\x00',
|
||||
# ],
|
||||
# (Ecu.transmission, 0x7e1, None): [
|
||||
# b'\xf1\x87CXJQAM4966515JB0x\xa9\x98\x9b\x99fff\x98feg\x88\x88w\x88Ff\x8f\xff{\xff\xff\xff\xa8\xf6\xf1\x816V2C1051\x00\x00\xf1\x006V2B0_C2\x00\x006V2C1051\x00\x00CBD0N20NS8q\xc1&\xd2', # noqa: E501
|
||||
# ],
|
||||
},
|
||||
CAR.KIA_FORTE_2021_NON_SCC: {
|
||||
(Ecu.eps, 0x7D4, None): [
|
||||
@@ -74,12 +52,6 @@ FW_VERSIONS_EXT = {
|
||||
(Ecu.fwdCamera, 0x7C4, None): [
|
||||
b'\xf1\x00BD LKAS AT USA LHD 1.00 1.04 95740-M6000 J33',
|
||||
],
|
||||
# (Ecu.abs, 0x7d1, None): [
|
||||
# b'\xf1\x816VFRAL00010.ELF\xf1\x00\x00\x00\x00\x00\x00\x00',
|
||||
# ],
|
||||
# (Ecu.transmission, 0x7e1, None): [
|
||||
# b'\xf1\x87CXLQAM0906975JB0\x89\x88\xa6\x8aVfug\xba\x87\x94yffuxgfo\xff\x8b\xff\xff\xff\x91\x82\xf1\x816V2C1051\x00\x00\xf1\x006V2B0_C2\x00\x006V2C1051\x00\x00CBD0N20NS8q\xc1&\xd2', # noqa: E501
|
||||
# ],
|
||||
},
|
||||
CAR.KIA_SELTOS_2023_NON_SCC: {
|
||||
(Ecu.abs, 0x7d1, None): [
|
||||
@@ -101,7 +73,6 @@ FW_VERSIONS_EXT = {
|
||||
},
|
||||
CAR.HYUNDAI_ELANTRA_2022_NON_SCC: {
|
||||
(Ecu.eps, 0x7d4, None): [
|
||||
# b'\xf1\x8756310AA030\x00\xf1\x00CN7 MDPS C 1.00 1.06 56310AA030\x00 4CNDC106',
|
||||
b'\xf1\x00CN7 MDPS R 1.00 1.04 57700-IB000 4CNNP104',
|
||||
],
|
||||
(Ecu.fwdCamera, 0x7c4, None): [
|
||||
@@ -109,11 +80,9 @@ FW_VERSIONS_EXT = {
|
||||
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.00 99210-IB000 210531',
|
||||
],
|
||||
(Ecu.abs, 0x7d1, None): [
|
||||
# b'\xf1\x8758910-AB500\xf1\x00CN ESC \t 100 \x06\x01 58910-AB500',
|
||||
b'\xf1\x00CN ESC \t 100!\x05\x01 58910-IB000',
|
||||
],
|
||||
(Ecu.transmission, 0x7e1, None): [
|
||||
# b'\xf1\x87CXNQEM4091445JB3g\x98\x98\x89\x99\x87gv\x89wuwgwv\x89hD_\xffx\xff\xff\xff\x86\xeb\xf1\x89HT6VA640A1\xf1\x82CCN0N20NS5\x00\x00\x00\x00\x00\x00', # noqa: E501
|
||||
b'\xf1\x00T02601BL T02900A1 WCN7T20XXX900NS4\xf7\xccz\xf6',
|
||||
],
|
||||
},
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
"""
|
||||
from abc import ABC, abstractmethod
|
||||
from iqdbc.car import structs
|
||||
from iqdbc.car.hyundai.values import HyundaiFlags
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
"""
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from iqdbc.car.hyundai.values import CAR
|
||||
@@ -9,9 +5,6 @@ from iqdbc.car.hyundai.values import CAR
|
||||
|
||||
@dataclass
|
||||
class CarTuningConfig:
|
||||
v_ego_stopping: float = 0.25
|
||||
v_ego_starting: float = 0.10
|
||||
stopping_decel_rate: float = 0.40
|
||||
lookahead_jerk_bp: list[float] = field(default_factory=lambda: [5., 20.])
|
||||
lookahead_jerk_upper_v: list[float] = field(default_factory=lambda: [0.25, 0.5])
|
||||
lookahead_jerk_lower_v: list[float] = field(default_factory=lambda: [0.15, 0.3])
|
||||
@@ -22,22 +15,15 @@ class CarTuningConfig:
|
||||
# Default configurations for different car types
|
||||
TUNING_CONFIGS = {
|
||||
"CANFD": CarTuningConfig(
|
||||
v_ego_stopping=0.365,
|
||||
lookahead_jerk_bp=[2., 5., 20.],
|
||||
lookahead_jerk_upper_v=[0.25, 0.5, 1.0],
|
||||
lookahead_jerk_lower_v=[0.05, 0.10, 0.325],
|
||||
),
|
||||
"EV": CarTuningConfig(
|
||||
stopping_decel_rate=0.45,
|
||||
v_ego_stopping=0.35,
|
||||
lookahead_jerk_upper_v=[0.3, 0.7],
|
||||
lookahead_jerk_lower_v=[0.2, 0.4],
|
||||
),
|
||||
"HYBRID": CarTuningConfig(
|
||||
v_ego_starting=0.15,
|
||||
stopping_decel_rate=0.45,
|
||||
v_ego_stopping=0.4,
|
||||
),
|
||||
"HYBRID": CarTuningConfig(),
|
||||
"DEFAULT": CarTuningConfig(
|
||||
lookahead_jerk_bp=[2., 5., 20.],
|
||||
lookahead_jerk_upper_v=[0.25, 0.5, 1.0],
|
||||
@@ -48,13 +34,11 @@ TUNING_CONFIGS = {
|
||||
# Car-specific configs
|
||||
CAR_SPECIFIC_CONFIGS = {
|
||||
CAR.KIA_NIRO_EV: CarTuningConfig(
|
||||
stopping_decel_rate=0.3,
|
||||
lookahead_jerk_upper_v=[0.3, 1.0],
|
||||
lookahead_jerk_lower_v=[0.2, 0.4],
|
||||
jerk_limits=2.5,
|
||||
),
|
||||
CAR.KIA_NIRO_PHEV_2022: CarTuningConfig(
|
||||
stopping_decel_rate=0.3,
|
||||
lookahead_jerk_upper_v=[0.3, 1.0],
|
||||
lookahead_jerk_lower_v=[0.15, 0.3],
|
||||
jerk_limits=4.0,
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
from iqdbc.car import structs, DT_CTRL, rate_limit
|
||||
@@ -37,10 +33,6 @@ def get_car_config(CP: structs.CarParams) -> CarTuningConfig:
|
||||
|
||||
def get_longitudinal_tune(CP: structs.CarParams) -> None:
|
||||
config = get_car_config(CP)
|
||||
CP.vEgoStopping = config.v_ego_stopping
|
||||
CP.vEgoStarting = config.v_ego_starting
|
||||
CP.stoppingDecelRate = config.stopping_decel_rate
|
||||
CP.startingState = False
|
||||
CP.longitudinalActuatorDelay = config.longitudinal_actuator_delay
|
||||
|
||||
|
||||
|
||||
@@ -73,9 +73,9 @@ class RadarInterfaceExt(EsccRadarInterfaceBase):
|
||||
if valid:
|
||||
self.pts[ii].measured = True
|
||||
self.pts[ii].dRel = msg['ACC_ObjDist']
|
||||
self.pts[ii].yRel = float('nan') # FIXME-IQ: Only some cars have lateral position from SCC
|
||||
self.pts[ii].yRel = float('nan')
|
||||
self.pts[ii].vRel = msg['ACC_ObjRelSpd']
|
||||
self.pts[ii].aRel = float('nan') # TODO-IQ: calculate from ACC_ObjRelSpd and with timestep 50Hz (needs to modify in interfaces.py)
|
||||
self.pts[ii].aRel = float('nan')
|
||||
self.pts[ii].yvRel = float('nan')
|
||||
|
||||
else:
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
"""
|
||||
@@ -1,61 +0,0 @@
|
||||
import pytest
|
||||
from hypothesis import given, strategies as st, settings, HealthCheck
|
||||
from iqdbc.iqpilot.car.hyundai.escc import EnhancedSmartCruiseControl, ESCC_MSG
|
||||
from iqdbc.car.hyundai.carstate import CarState
|
||||
from iqdbc.car import structs
|
||||
from iqdbc.iqpilot.car.hyundai.values import HyundaiFlagsIQ
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def car_params():
|
||||
params = structs.CarParams()
|
||||
params.carFingerprint = "HYUNDAI_SONATA"
|
||||
return params
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def car_params_iq():
|
||||
params = structs.IQCarParams()
|
||||
params.flags = HyundaiFlagsIQ.ENHANCED_SCC
|
||||
return params
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def escc(car_params, car_params_iq):
|
||||
return EnhancedSmartCruiseControl(car_params, car_params_iq)
|
||||
|
||||
|
||||
class TestEscc:
|
||||
def test_escc_msg_id(self, escc):
|
||||
assert escc.trigger_msg == ESCC_MSG
|
||||
|
||||
@settings(suppress_health_check=[HealthCheck.function_scoped_fixture])
|
||||
@given(st.integers(min_value=0, max_value=255))
|
||||
def test_enabled_flag(self, car_params, car_params_iq, value):
|
||||
car_params_iq.flags = value
|
||||
escc = EnhancedSmartCruiseControl(car_params, car_params_iq)
|
||||
assert escc.enabled == (value & HyundaiFlagsIQ.ENHANCED_SCC)
|
||||
|
||||
def test_update_car_state(self, escc, car_params, car_params_iq):
|
||||
car_state = CarState(car_params, car_params_iq)
|
||||
car_state.escc_cmd_act = 1
|
||||
car_state.escc_aeb_warning = 1
|
||||
car_state.escc_aeb_dec_cmd_act = 1
|
||||
car_state.escc_aeb_dec_cmd = 1
|
||||
escc.update_car_state(car_state)
|
||||
assert escc.car_state == car_state
|
||||
|
||||
def test_update_scc12(self, escc, car_params, car_params_iq):
|
||||
car_state = CarState(car_params, car_params_iq)
|
||||
car_state.escc_cmd_act = 1
|
||||
car_state.escc_aeb_warning = 1
|
||||
car_state.escc_aeb_dec_cmd_act = 1
|
||||
car_state.escc_aeb_dec_cmd = 1
|
||||
escc.update_car_state(car_state)
|
||||
scc12_message = {}
|
||||
escc.update_scc12(scc12_message)
|
||||
assert scc12_message["AEB_CmdAct"] == 1
|
||||
assert scc12_message["CF_VSM_Warn"] == 1
|
||||
assert scc12_message["CF_VSM_DecCmdAct"] == 1
|
||||
assert scc12_message["CR_VSM_DecCmd"] == 1
|
||||
assert scc12_message["AEB_Status"] == 2
|
||||
@@ -1,77 +0,0 @@
|
||||
from enum import IntFlag
|
||||
|
||||
from iqdbc.iqpilot.car.hyundai.lead_data_ext import LeadDataCarController, CanLeadData, CanFdLeadData
|
||||
from iqdbc.car import structs
|
||||
from iqdbc.car.hyundai.values import HyundaiFlags
|
||||
|
||||
|
||||
def make_carparams(flags: IntFlag = HyundaiFlags.LEGACY):
|
||||
cp = structs.CarParams()
|
||||
cp.carFingerprint = "HYUNDAI_SONATA"
|
||||
cp.flags = flags.value
|
||||
return cp
|
||||
|
||||
|
||||
def make_iq_carcontrol(leadDistance=10.0, leadRelSpeed=0.0, leadVisible=True):
|
||||
c = structs.IQCarControl()
|
||||
c.leadOne.dRel = leadDistance
|
||||
c.leadOne.vRel = leadRelSpeed
|
||||
c.leadOne.status = leadVisible
|
||||
return c
|
||||
|
||||
|
||||
class TestLeadDataCarController:
|
||||
def test_update_object_gap(self):
|
||||
ctrl = LeadDataCarController(make_carparams())
|
||||
# Initial value should be 0
|
||||
assert ctrl.object_gap == 0
|
||||
|
||||
# Set to 15 (should become 2 after hysteresis)
|
||||
for _ in range(ctrl.LEAD_HYSTERESIS_FRAMES):
|
||||
ctrl._update_object_gap(15)
|
||||
assert ctrl.object_gap == 2
|
||||
|
||||
# Set to 22 (should become 3 after hysteresis)
|
||||
for _ in range(ctrl.LEAD_HYSTERESIS_FRAMES):
|
||||
ctrl._update_object_gap(22)
|
||||
assert ctrl.object_gap == 3
|
||||
|
||||
# Set to 0 (should become 0 after hysteresis)
|
||||
for _ in range(ctrl.LEAD_HYSTERESIS_FRAMES):
|
||||
ctrl._update_object_gap(0)
|
||||
assert ctrl.object_gap == 0
|
||||
|
||||
def test_update_lead_visible_hysteresis(self):
|
||||
ctrl = LeadDataCarController(make_carparams())
|
||||
ctrl._update_lead_visible_hysteresis(True)
|
||||
assert isinstance(ctrl.lead_visible, bool)
|
||||
ctrl._update_lead_visible_hysteresis(False)
|
||||
assert isinstance(ctrl.lead_visible, bool)
|
||||
|
||||
def test_update(self):
|
||||
ctrl = LeadDataCarController(make_carparams())
|
||||
iq_control = make_iq_carcontrol(leadDistance=25, leadRelSpeed=-0.5, leadVisible=True)
|
||||
ctrl.update(iq_control)
|
||||
assert ctrl.lead_distance == 25
|
||||
assert ctrl.lead_rel_speed == -0.5
|
||||
assert isinstance(ctrl.lead_visible, bool)
|
||||
|
||||
def test_lead_data_can(self):
|
||||
ctrl = LeadDataCarController(make_carparams())
|
||||
ctrl.object_gap = 1
|
||||
ctrl.lead_distance = 10
|
||||
ctrl.lead_rel_speed = -0.3
|
||||
ctrl.lead_visible = True
|
||||
ld = ctrl.lead_data
|
||||
assert isinstance(ld, CanLeadData)
|
||||
assert ld.object_rel_gap == 2
|
||||
|
||||
def test_lead_data_canfd(self):
|
||||
ctrl = LeadDataCarController(make_carparams(HyundaiFlags.CANFD))
|
||||
ctrl.object_gap = 1
|
||||
ctrl.lead_distance = 10
|
||||
ctrl.lead_rel_speed = 1.0
|
||||
ctrl.lead_visible = True
|
||||
ld = ctrl.lead_data
|
||||
assert isinstance(ld, CanFdLeadData)
|
||||
assert ld.object_rel_gap == 1
|
||||
@@ -1,119 +0,0 @@
|
||||
from parameterized import parameterized
|
||||
|
||||
from iqdbc.car import CanData
|
||||
from iqdbc.car.car_helpers import interfaces
|
||||
from iqdbc.car.hyundai.values import CAR, HyundaiFlags
|
||||
from iqdbc.iqpilot.car.hyundai.escc import ESCC_MSG
|
||||
|
||||
ESCC_CARS = [
|
||||
(CAR.HYUNDAI_ELANTRA_2021, ESCC_MSG),
|
||||
]
|
||||
|
||||
CAMERA_SCC_CARS = [
|
||||
(CAR.HYUNDAI_KONA_EV_2022, 0, 0x420, "SCC11"),
|
||||
(CAR.HYUNDAI_IONIQ_5, HyundaiFlags.CANFD_CAMERA_SCC.value, 0x1A0, "SCC_CONTROL"),
|
||||
]
|
||||
|
||||
STANDARD_RADAR_CARS = [
|
||||
(CAR.HYUNDAI_ELANTRA_2021, 0),
|
||||
(CAR.HYUNDAI_SANTA_FE, 0),
|
||||
]
|
||||
|
||||
|
||||
class TestRadarInterfaceExt:
|
||||
|
||||
@staticmethod
|
||||
def _setup_platform(car_name, additional_flags=0, escc_msg=None):
|
||||
"""Set up the platform with specific parameters"""
|
||||
CarInterface = interfaces[car_name]
|
||||
|
||||
CP = CarInterface.get_non_essential_params(car_name)
|
||||
CP.flags |= additional_flags
|
||||
|
||||
CP_IQ = CarInterface.get_non_essential_params_iq(CP, car_name)
|
||||
|
||||
CI = CarInterface(CP, CP_IQ)
|
||||
|
||||
RD = CI.RadarInterface(CP, CP_IQ)
|
||||
|
||||
if escc_msg is not None and hasattr(RD, 'use_escc'):
|
||||
try:
|
||||
RD.use_escc = True
|
||||
except AttributeError:
|
||||
object.__setattr__(RD, 'use_escc', True)
|
||||
|
||||
return RD, CP, CP_IQ
|
||||
|
||||
@parameterized.expand(ESCC_CARS)
|
||||
def test_escc_radar_interface(self, car_name, escc_msg):
|
||||
"""Test radar interface for ESCC-enabled cars"""
|
||||
RD, CP, CP_IQ = self._setup_platform(car_name, escc_msg=escc_msg)
|
||||
|
||||
# Assert that ESCC features are present
|
||||
if hasattr(RD, 'use_escc'):
|
||||
assert RD.use_escc, "ESCC car should have use_escc=True"
|
||||
if hasattr(RD, 'use_radar_interface_ext'):
|
||||
assert RD.use_radar_interface_ext, "ESCC car should use radar interface ext"
|
||||
|
||||
# Run radar interface once
|
||||
RD.update([])
|
||||
|
||||
# Test radar fault
|
||||
if not CP.radarUnavailable and RD.rcp is not None:
|
||||
cans = [(0, [CanData(0, b'', 0) for _ in range(5)])]
|
||||
rr = RD.update(cans)
|
||||
assert rr is None or len(rr.errors) > 0
|
||||
|
||||
@parameterized.expand(CAMERA_SCC_CARS)
|
||||
def test_camera_scc_radar_interface(self, car_name, flags, expected_trigger, msg_src):
|
||||
"""Test radar interface for Camera SCC cars"""
|
||||
RD, CP, CP_IQ = self._setup_platform(car_name, additional_flags=flags)
|
||||
|
||||
# Assert Camera SCC flag is set appropriately
|
||||
if flags & HyundaiFlags.CAMERA_SCC:
|
||||
assert CP.flags & HyundaiFlags.CAMERA_SCC, "Car should have CAMERA_SCC flag"
|
||||
if flags & HyundaiFlags.CANFD_CAMERA_SCC:
|
||||
assert CP.flags & HyundaiFlags.CANFD_CAMERA_SCC, "Car should have CANFD_CAMERA_SCC flag"
|
||||
|
||||
# Check if using radar interface ext
|
||||
if hasattr(RD, 'use_radar_interface_ext'):
|
||||
assert RD.use_radar_interface_ext, "Camera SCC car should use radar interface ext"
|
||||
|
||||
# Verify trigger message
|
||||
if hasattr(RD, 'trigger_msg'):
|
||||
assert RD.trigger_msg == expected_trigger, f"Expected trigger_msg {expected_trigger}, got {RD.trigger_msg}"
|
||||
|
||||
# Run radar interface once
|
||||
RD.update([])
|
||||
|
||||
# Test radar fault
|
||||
if not CP.radarUnavailable and RD.rcp is not None:
|
||||
cans = [(0, [CanData(0, b'', 0) for _ in range(5)])]
|
||||
rr = RD.update(cans)
|
||||
assert rr is None or len(rr.errors) > 0
|
||||
|
||||
@parameterized.expand(STANDARD_RADAR_CARS)
|
||||
def test_standard_radar_interface(self, car_name, flags):
|
||||
"""Test radar interface for standard radar cars"""
|
||||
RD, CP, CP_IQ = self._setup_platform(car_name, additional_flags=flags)
|
||||
|
||||
# Standard cars should not use radar interface ext
|
||||
if hasattr(RD, 'use_radar_interface_ext'):
|
||||
assert not RD.use_radar_interface_ext, "Standard car should not use radar interface ext"
|
||||
|
||||
# Run radar interface once
|
||||
RD.update([])
|
||||
|
||||
# For standard radar, test the _update method directly if available
|
||||
if not CP.radarUnavailable and RD.rcp is not None and \
|
||||
hasattr(RD, '_update') and hasattr(RD, 'trigger_msg'):
|
||||
# Setup for _update test if needed
|
||||
if hasattr(RD, 'updated_messages'):
|
||||
RD.updated_messages = {RD.trigger_msg}
|
||||
RD._update(RD.updated_messages)
|
||||
|
||||
# Test radar fault
|
||||
if not CP.radarUnavailable and RD.rcp is not None:
|
||||
cans = [(0, [CanData(0, b'', 0) for _ in range(5)])]
|
||||
rr = RD.update(cans)
|
||||
assert rr is None or len(rr.errors) > 0
|
||||
@@ -1,146 +0,0 @@
|
||||
"""
|
||||
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
|
||||
"""
|
||||
|
||||
import unittest
|
||||
import numpy as np
|
||||
from unittest.mock import Mock
|
||||
|
||||
from iqdbc.iqpilot.car.hyundai.longitudinal.controller import LongitudinalController, LongitudinalState
|
||||
from iqdbc.iqpilot.car.hyundai.values import HyundaiFlagsIQ
|
||||
from iqdbc.car import DT_CTRL, structs
|
||||
from iqdbc.car.interfaces import CarStateBase
|
||||
from iqdbc.car.hyundai.values import HyundaiFlags
|
||||
|
||||
LongCtrlState = structs.CarControl.Actuators.LongControlState
|
||||
|
||||
|
||||
class TestLongitudinalTuningController(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.mock_CP = Mock(carFingerprint="KIA_NIRO_EV", flags=0)
|
||||
self.mock_CP.radarUnavailable = False # ensure tuning branch
|
||||
self.mock_CP_IQ = Mock(flags=0)
|
||||
self.controller = LongitudinalController(self.mock_CP, self.mock_CP_IQ)
|
||||
|
||||
def test_init(self):
|
||||
"""Test controller initialization"""
|
||||
self.assertIsInstance(self.controller.tuning, LongitudinalState)
|
||||
self.assertEqual(self.controller.desired_accel, 0.0)
|
||||
self.assertEqual(self.controller.actual_accel, 0.0)
|
||||
self.assertEqual(self.controller.jerk_upper, 0.0)
|
||||
self.assertEqual(self.controller.jerk_lower, 0.0)
|
||||
self.assertEqual(self.controller.comfort_band_upper, 0.0)
|
||||
self.assertEqual(self.controller.comfort_band_lower, 0.0)
|
||||
|
||||
def test_make_jerk_flag_off(self):
|
||||
"""Test when LONG_TUNING_DYNAMIC flag is off"""
|
||||
mock_CC, mock_CS = Mock(spec=structs.CarControl), Mock(spec=CarStateBase)
|
||||
mock_CS.out = Mock()
|
||||
mock_CS.out.vEgo = 0.0
|
||||
mock_CS.out.aEgo = 0.0
|
||||
mock_CS.aBasis = 0.0
|
||||
|
||||
# Test with PID state
|
||||
self.controller.calculate_jerk(mock_CC, mock_CS, LongCtrlState.pid)
|
||||
print(f"[PID state] jerk_upper={self.controller.jerk_upper:.2f}, jerk_lower={self.controller.jerk_lower:.2f}")
|
||||
self.assertEqual(self.controller.jerk_upper, 3.0)
|
||||
self.assertEqual(self.controller.jerk_lower, 5.0)
|
||||
|
||||
# Test with non-PID state
|
||||
self.controller.calculate_jerk(mock_CC, mock_CS, LongCtrlState.stopping)
|
||||
print(f"[Non-PID state] jerk_upper={self.controller.jerk_upper:.2f}, jerk_lower={self.controller.jerk_lower:.2f}")
|
||||
self.assertEqual(self.controller.jerk_upper, 1.0)
|
||||
self.assertEqual(self.controller.jerk_lower, 5.0)
|
||||
|
||||
def test_make_jerk_flag_on(self):
|
||||
"""Only verify that limits update when flags are on."""
|
||||
self.controller.CP_IQ.flags = HyundaiFlagsIQ.LONG_TUNING_DYNAMIC
|
||||
self.controller.CP.flags = HyundaiFlags.CANFD
|
||||
mock_CC = Mock()
|
||||
mock_CC.actuators = Mock(accel=1.0)
|
||||
mock_CC.longActive = True
|
||||
self.controller.stopping = False
|
||||
mock_CS = Mock()
|
||||
mock_CS.out = Mock(aEgo=0.8, vEgo=3.0)
|
||||
mock_CS.aBasis = 0.8
|
||||
|
||||
self.controller.calculate_jerk(mock_CC, mock_CS, LongCtrlState.pid)
|
||||
print(f"[FlagOn] jerk_upper={self.controller.jerk_upper:.3f}, jerk_lower={self.controller.jerk_lower:.3f}")
|
||||
self.assertGreater(self.controller.jerk_upper, 0.0)
|
||||
self.assertGreater(self.controller.jerk_lower, 0.0)
|
||||
|
||||
def test_a_value_jerk_scaling(self):
|
||||
"""Test a_value jerk scaling under tuning branch."""
|
||||
self.controller.CP_IQ.flags = HyundaiFlagsIQ.LONG_TUNING_DYNAMIC
|
||||
self.controller.CP.radarUnavailable = False
|
||||
mock_CC = Mock()
|
||||
mock_CC.actuators = Mock(accel=1.0)
|
||||
mock_CC.longActive = True
|
||||
print("[a_value] starting accel_last:", self.controller.tuning.accel_last)
|
||||
# first pass: limit to jerk_upper * DT_CTRL * 2 = 0.1
|
||||
self.controller.jerk_upper = 0.1 / (DT_CTRL * 2)
|
||||
self.controller.accel_cmd = 1.0 # ensure accel_cmd is set
|
||||
self.controller.calculate_accel(mock_CC)
|
||||
print(f"[a_value] pass1 actual_accel={self.controller.actual_accel:.5f}")
|
||||
self.assertAlmostEqual(self.controller.actual_accel, 0.1, places=5)
|
||||
|
||||
# second pass: limit increment by new jerk_upper
|
||||
mock_CC.actuators.accel = 0.7
|
||||
self.controller.jerk_upper = 0.2 / (DT_CTRL * 2)
|
||||
self.controller.accel_cmd = 0.7 # update accel_cmd
|
||||
self.controller.calculate_accel(mock_CC)
|
||||
print(f"[a_value] pass2 actual_accel={self.controller.actual_accel:.5f}")
|
||||
self.assertAlmostEqual(self.controller.actual_accel, 0.3, places=5)
|
||||
|
||||
def test_make_jerk_realistic_profile(self):
|
||||
"""Test make_jerk with realistic velocity and acceleration profile"""
|
||||
np.random.seed(42)
|
||||
num_points = 30
|
||||
segments = [
|
||||
np.random.uniform(0.3, 0.8, num_points//4),
|
||||
np.random.uniform(0.8, 1.6, num_points//4),
|
||||
np.random.uniform(-0.2, 0.2, num_points//4),
|
||||
np.random.uniform(-1.2, -0.5, num_points//8),
|
||||
np.random.uniform(-2.2, -1.2, num_points//8)
|
||||
]
|
||||
accels = np.concatenate(segments)[:num_points]
|
||||
vels = np.zeros_like(accels)
|
||||
vels[0] = 5.0
|
||||
for i in range(1, len(accels)):
|
||||
vels[i] = max(0.0, min(30.0, vels[i-1] + accels[i-1] * (DT_CTRL*2)))
|
||||
mock_CC, mock_CS = Mock(), Mock()
|
||||
mock_CC.actuators, mock_CS.out = Mock(), Mock()
|
||||
mock_CC.longActive = True
|
||||
self.controller.stopping = False
|
||||
|
||||
# Test with LONG_TUNING_DYNAMIC only
|
||||
self.controller.CP_IQ.flags = HyundaiFlagsIQ.LONG_TUNING_DYNAMIC
|
||||
for v, a in zip(vels, accels, strict=True):
|
||||
mock_CS.out.vEgo = float(v)
|
||||
mock_CS.out.aEgo = float(a)
|
||||
mock_CS.aBasis = float(a)
|
||||
mock_CC.actuators.accel = float(a)
|
||||
self.controller.calculate_jerk(mock_CC, mock_CS, LongCtrlState.pid)
|
||||
print(f"[realistic][LONG_TUNING_DYNAMIC] v={v:.2f}, a={a:.2f}, jerk_upper={self.controller.jerk_upper:.2f}, jerk_lower={self.controller.jerk_lower:.2f}")
|
||||
self.assertGreater(self.controller.jerk_upper, 0.0)
|
||||
|
||||
# Reset controller before next test
|
||||
self.controller.tuning = LongitudinalState()
|
||||
self.controller.jerk_upper = 0.5
|
||||
self.controller.jerk_lower = 0.5
|
||||
|
||||
# Test with LONG_TUNING_DYNAMIC and LONG_TUNING_PREDICTIVE
|
||||
self.controller.CP_IQ.flags = HyundaiFlagsIQ.LONG_TUNING_DYNAMIC | HyundaiFlagsIQ.LONG_TUNING_PREDICTIVE
|
||||
for v, a in zip(vels, accels, strict=True):
|
||||
mock_CS.out.vEgo = float(v)
|
||||
mock_CS.out.aEgo = float(a)
|
||||
mock_CS.aBasis = float(a)
|
||||
mock_CC.actuators.accel = float(a)
|
||||
self.controller.calculate_jerk(mock_CC, mock_CS, LongCtrlState.pid)
|
||||
print(f"[realistic][LONG_TUNING_PREDICTIVE] v={v:.2f}, a={a:.2f}, " +
|
||||
f"jerk_upper={self.controller.jerk_upper:.2f}, jerk_lower={self.controller.jerk_lower:.2f}")
|
||||
self.assertGreater(self.controller.jerk_upper, 0.0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user