diff --git a/artifacts/iqpilot_hephaestusd_private/manifest.json b/artifacts/iqpilot_hephaestusd_private/manifest.json
index 60389e4..c56ced4 100644
--- a/artifacts/iqpilot_hephaestusd_private/manifest.json
+++ b/artifacts/iqpilot_hephaestusd_private/manifest.json
@@ -16,27 +16,27 @@
},
"python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "0d09e647c74e2fe7711d86f03ed46b8dbcea1cc481db79831f524052bfe3df9a",
+ "sha256": "1ca35a437eaf1c50ce6f58eb38cdfb56eacab6f7d5201eef446495a68d90d69b",
"size": 135536
},
"python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "5433b48250397a598883e373b62dec1e196ca0252a834e4df951714f737225a0",
+ "sha256": "98039925b5104eb48b69d2ea6a34600daab8251d926fecab666ac51e565d1571",
"size": 67664
},
"python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "1ff757bd5846b8643757b6c9b19e469023ebc40abe9c1cc81843e213c9fca36c",
+ "sha256": "85edb71bacde7958772f85a07e56506e974214756198b0fc8b91a21188d336e6",
"size": 204624
},
"python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "10820bac096f6d19c2c2730da7b514d39740071aa2e06ef0aff62d29dd038f79",
+ "sha256": "1c8a4bf98aa378c3a4d924725a6f8f42c4de13452a18064bc76539354659d84e",
"size": 69752
},
"python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "53869c7ac607b3df9b2582a7a696c78f240b65aa912adaa5bbf821cb2d6e43be",
+ "sha256": "a5ce7828c559a5841317d79e01a7e571debbce4d4992827aedab27d6d2b2eb15",
"size": 203072
},
"python/iqpilot_private/konn3kt/flockd/__init__.py": {
@@ -46,12 +46,12 @@
},
"python/iqpilot_private/konn3kt/flockd/flockd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "16af7e2135b778b8c00b37913ff2789382fcf4bdf752677c112646444ff4128a",
+ "sha256": "2fe267d00d04e9f94ef16885cb88b4b28ad7f6e1b1ca41caf23883d46ab03961",
"size": 202168
},
"python/iqpilot_private/konn3kt/flockd/signatures.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "ea3cefbd825298085ff45dd9c8a6dfceac2f59ae159897288190c6e1916f9914",
+ "sha256": "d3ff0a6d4d9f1653418de8fc3fa52baed0067c48c02438b30e1d27cf92e5aeb4",
"size": 68080
},
"python/iqpilot_private/konn3kt/hephaestus/__init__.py": {
@@ -61,67 +61,67 @@
},
"python/iqpilot_private/konn3kt/hephaestus/_vendor/localapi_runtime.zip": {
"mode": 420,
- "sha256": "addff42a1545df02047da7e44aaef7ac86299d18559beb6889ce0e59281d2989",
+ "sha256": "1854ddf5a9e969ce210acf55fd4e53cc158e0117c67f65132e9c21fb49d1b53e",
"size": 2100238
},
"python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "93afb33797a4a0808eb0f07f8a1507a933aff5e46c88611be73c5fb6ea25db03",
+ "sha256": "983a5825aaf5178081c5f44f1ba7e950b117774fcf751881c013dd05796b70d4",
"size": 268064
},
"python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "cba46bd69c7680542c9bd81e351152d9e74d02870706211e440f14f60e124e5a",
+ "sha256": "87586aec493893ccae8c67fc89fc71006762f87100d3d396d9735d6603b86cb9",
"size": 340584
},
"python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "aee81fc9495d0d57885be7680a5c8b5b909acb1cc3dbbdcbd000ce006b7b8db9",
+ "sha256": "cff0554eebc045f8d46d5153d88949123ddc26cc251dec1fe6303c1911b9c8ad",
"size": 68048
},
"python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "268b6dcef5769fcdf55014fd23c8fe6cd782f5ca2b13c376fe7f6832370394af",
+ "sha256": "a1f10df44d7a49066b2383ad06dde00337f9dc2126f5eeeeca5a7d6c4689da07",
"size": 335728
},
"python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "fffd2076ec445350819197f4e976df5eaa2f75091f12b5fdd5e3c8173a50f45c",
+ "sha256": "d0f12e27574b34033a86e29e186d4a551cd8c9f03c2e478ac656003ce164cbc9",
"size": 271680
},
"python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "d216f9a9778494f15681deb712d804dea1b16efcf39c64aa5b8dac2f69d1e18d",
+ "sha256": "ab76c8af88512b3839150810f9083f26f0238ac644585a1cb9d4e462a2ea92b2",
"size": 134408
},
"python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "98f4eedb594fda692a9d8df3d629f140b9be141b9ebf249f4b9b1fd6f08f7ab2",
- "size": 3514416
+ "sha256": "80183a42c221b9ac60681ad585d629fe22313f655e8dcb955dc05128bcf16147",
+ "size": 3647464
},
"python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "0497c9f642821c7d5a751cb017d267b05a0351f7132739d4cfe4045725c9c288",
+ "sha256": "05bac25363b7dc2b1cab18fbf54511c98fc8806034eba759f56008451efd1c64",
"size": 136448
},
"python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "f2213863c2ac3dca7adbeb1aa8f4e3aa826f314e00242f57cc226e182cb1a827",
+ "sha256": "0e3104b80f8eb480caa673fee837f9b8159e479f8761c443caa3e88f6d65fc82",
"size": 68136
},
"python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "56bd84482c5608a24566f397fcae1a8e3cfdf056d4b8cfbafc4e3940df7ff7a4",
+ "sha256": "3ce3d559312252ab44fd4b2d68b25393751d74e14d0f5142ab2d14e5dd2a466b",
"size": 67840
},
"python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "d072ae1e45b6af63bd53d9347c0abd5349e7ac4a38f2771ed90cbab23f53fa0e",
+ "sha256": "b85ce7db3fbd4879067c068175d0c40f4c1eb9aa54811396519ce2f8fff7ad3c",
"size": 135648
},
"python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "de65e895460391aaa375829c6ecb32f4afdb38f788eb8b08037da92e45612819",
+ "sha256": "2e7b7f1b4ed526c924c06aa63ecfaffc1ed726e3a31ba267712a1502e0f30020",
"size": 269568
},
"python/iqpilot_private/konn3kt/uploaderd/__init__.py": {
@@ -131,7 +131,7 @@
},
"python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
- "sha256": "cf6a5657d7df10401bc9c0a8beb0cfd66f17647a8ab15b533973470754434cf2",
+ "sha256": "66cec9701718c377178142f92912d8093dd62a58bb00fa2f865b76457db959db",
"size": 204184
},
"runtime": {
@@ -171,25 +171,25 @@
}
},
"signatures": {
- "python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so": "MhygD4Nh+eJC3m2vDtF641GcCMQwyRq3shJFQMv2SA+152534qnm/FnmG31lqFq08SNxJSUpbYs5d56dzVJoAw==",
- "python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so": "URQ2U1GvLsYG+Nur/06oweZqpcyPeniGu0fmRgIrYmvrMETgJkTVjERAb18jnUEUb2SLT6IDzpVJYQwvancEDA==",
- "python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so": "N0G4N2rA3BwaCJxYGDYwk/HJzIMqdVNH/MVKtnit3zt8f1j/Cx742cFD+K+8AiLbBAKk5m1Hu1+h30P8IIOKAw==",
- "python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so": "BtRiu8ovXJ/34exEQl5B3rytuRAabbfu5ivDlTpVjE8g1B/Gtuq4+WnnyY3MxceuRPDDwdh6H+wEs86JQgIeAg==",
- "python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so": "Zx2W7qGJeeNQm4Rh83jbwN8CoBLRiBxHOaCBuhPLs6eH9yGTWChReVUlfSO6ERLjwDdj7ZZxJrAwejyYlAr6CA==",
- "python/iqpilot_private/konn3kt/flockd/flockd.cpython-312-aarch64-linux-gnu.so": "eaV/SCWv/7CGkqcP+9aEPGRqDgLtjd4pwLbu/XdHWj/gtK4yvlFP7Es/klwBGIrEK9D7Go9ld6XKfHhOPYmfAQ==",
- "python/iqpilot_private/konn3kt/flockd/signatures.cpython-312-aarch64-linux-gnu.so": "I+/gJLOtUIPx3BfBfLynJZz79SX/TtEqhc9awsk+xI6+HPHjvU5+2DD5HRWlgVWO7bdJKf5m24hP4QHO8sfzCw==",
- "python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so": "4dPhClIrA3dBR9/JO5sgcluwzZc8FJREIOSNQ40n3A7vw3CXw6ImVwhmjE/yVQ5wIjndhKb+KLy21V37lzGfAw==",
- "python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so": "wGbVY1IQZaD2u9Ied+zcBM2XjIOoRxSectUKRKry7D6yuxB7Mqtoa8LLq9GOZCRFZDHPQ9rk2f9QSgBZfT5VAg==",
- "python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so": "YqAqfi21Vy0kyOb2FQONlS6F8gW8Cvi8/CjYsaxiItGS8E6y6bzhYe5/AlMyd385NYoD4upXfbMGXHXDqblsCQ==",
- "python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so": "gWd6Vfq+80Z4uxFmDfvaYkp1Wzw18kEzA/mG0Xd54EbDJ4GefnGkAHuvssMYGNE+TCEpqaVt85Jf8QWflirzAw==",
- "python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so": "xXbkx1zJrM5NPlBeVhengh56WJ6CXXb4V8aswT4zasmr3DcxrpV7Y7Wbk13UEwV8ix+huvs9wVlojOfdZqiIAA==",
- "python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so": "chkeeRV4erIsiTmJ51G7/qFJ8fPACpkuO8sveQv5okaopUar+O2/m+lDLBnYkR4Es/TFnCGRv4N0RwvzT49rCg==",
- "python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so": "p40DN5yfj4tyY6kzcA7VEmbMxhjQ77QwiNR3vMGEuoKh7mcK3jmbBdGPa4gANN30n/UyLEG2+sg4dhM0RVm4BA==",
- "python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so": "0ZIlxKWPjaZGQFKWhKp07Rt62fwr6QJYUxtY8bQ3mNYsWV72Ix36Q2TfALEVVlE/zSHwP34eV4mSFA8Q1qyhBw==",
- "python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so": "F7nzMGhcWJ7daMQgd6zpPtzD1q5Up8sJyztfGo30md7aeiSMGX8BONlW6FglTR+WZoNei7p9HA1YWGelGuYzDA==",
- "python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so": "rECWieVZcSBvEoDvGdg0+hpR7EkzmZtsuS6b/f1RAQPk8k96sLsUOXO4myL0xlnuzY7dim3UL9g8BqqW8qutAg==",
- "python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so": "CtyIPJuuLXHQ9VaMtLsZVHD18UWlw1JfNTYqlvJtwsTZK88ct+9S99n6ROkdqIr5qn3LQjMr7QxvEGe457IFBA==",
- "python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so": "u4+khM3qZF78JaJKBVdnSHb4VARUJXg/BS+1SuX/DydJuEmziX4FTCi+LiO1X6GjEi1ciJP9jz6bWEC39b7xAw==",
- "python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so": "65hNz0AqEUYmvWaVGGFSp7y0BtVRT8KG/3B1lil/eg6p9BCDvPbH6vmku7/Zm7T7bQjYmjvofzRjiqi1hbLcBA=="
+ "python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so": "S6pnKIiETehDkX4x+40+Q+fBQ04N9x1OI7NQS5+j6JVNNIE0PA4MuMB+Vl9rt3o+fJrFoyIL1g+tMWT2gMluDA==",
+ "python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so": "NckVEdkvdS5EmHJKOIe1EakeyNUbYFxDG2tohT0MMzKM3Tk47f0k4cs/QOqFRNsb612WwPH9PaPdhOmNXUKLCQ==",
+ "python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so": "3byD6wJefryFq1S6jV0TT+Ui/Yn+pyj3Iu+RI2vxIuue9qIknyIy0zc156kXSotiYkip0XOuzwB1HNWo4qTPCg==",
+ "python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so": "0S7cE4HK9ZoATxXvrWcQF9Hf+iy8JKdBd/OAQJt6IHrmgDeExkn5NQD5VjMpOejsGBTCQEgL/xx7JpYxlr5wCQ==",
+ "python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so": "3adGsr3oPmcldMROx5pjkCxa2Vrbaj2lRhFjNgz151VHRULAOTuxyX7nAZQmxNuDEumyji5TW5d1zTqAoMFnBg==",
+ "python/iqpilot_private/konn3kt/flockd/flockd.cpython-312-aarch64-linux-gnu.so": "gIbpR3VZKr2n0sXnV6PJhHiF6spttO6PFPgxxGoo7ml8tmYFx7SoUhUiEEhNQXGpcN27iW/5IT7RGIE4m8kPCg==",
+ "python/iqpilot_private/konn3kt/flockd/signatures.cpython-312-aarch64-linux-gnu.so": "iLZnAzgx87+P3adKMeOOJswOKmCdt4gqG4EJ/lEHjjWZC+GZlnTr/qQ3fiQ1R1qp6Jvb3MrFI4FyFnsbURfPCQ==",
+ "python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so": "QTiHED4yIIVzPcU6BapHNU/nlX1g6cP8AaxteooJDR/DqCnUbW/3YUsVSmqvwTLNTF6YWNOLa2dgvybyYRBSAQ==",
+ "python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so": "MPoy7t15DrxRSJBi+ZFRqHU/ahIc03h8XxuOiho/zaU4I6LIy4QwP18duc+YkeJ5R6jkPduoWgLyHKbAXPTYCg==",
+ "python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so": "I9uohiZn6lrerZFWee6cf2yXkeDxZTSBxKVQWSGKq5woFAK5fZ94FMf8qKfow8dOw8etLXC8XOYA2oH5TfK+AQ==",
+ "python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so": "smEWcWBel8zd78q5YvTnVKlM3EMh15FxywK/Dlx6lCHJ5eLAPsoYo+YimWd9qUFBOF/rmkO5k/9TlqsKE31vBw==",
+ "python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so": "wrvw7RvBfiEt0dz2TKMuDb03FIIaPLEclAYYmWObzwF1NAmyiBRqup0F0y3k7vtmwbubjns7+j2ZvA4j+k18AQ==",
+ "python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so": "/IBbuQ0E7ym7EGLV9EYDqcWLaSgBa6IImVgapC50F7LhNXmuUhOZJc9sVyV50Xa/e+60toBSPsJETud6sSeTCA==",
+ "python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so": "iqiqKn2zwfgBtsiqKtNTMgfnCfek9F41ZLVi3GTOzJucXsyKMCCLfyn4zImGf1w9zG+XWPWwudDBYEYWKr8AAQ==",
+ "python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so": "uzsNWnyFDbCTEYVdDEF2dS+Hk/WnB/Je4bT5Htge8TX/1O/pEpgCKpLE1j1H5Nt+/M5HDvgSXJScQxmlWJBaDQ==",
+ "python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so": "TwgqVE8NrG59tVrr9z1Lvo7yh1gVyI8548cP7PT44F4bnDVx9oJvqaZOqF1vEV4xWdoYKSIBPVA3YnINnwEICw==",
+ "python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so": "uBZA3ZSrCNfpy/vWbtYApt9UOStxuBBe0LP6AhEZEHWfebrM0CeCK1qimb+kfGDoQyTXLmie6v8PiKWYeTmODQ==",
+ "python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so": "OwU3WbDPCT0ggbPBWjuYvTiPuPW+j557MyciaBFq1C5+xElg94DHWH6DpV/WzUFkRwjb4226epgYjSCQHva/Ag==",
+ "python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so": "j7lzNRlIQ0kr0Pw4C8Oo/fw1i/ihgmNTXP+cro9J3ivRm1xpe5aPPY22I5cw763tGHo2h9YCAO5EBAHz+FSsCg==",
+ "python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so": "Z3vtFdwz1cLaTACNhZoaO5UXG4HCzEOB/2/RCdii1epsXE9amtWEbwx2miS2qlN03gC28Ieak9SECjxMyGafAg=="
}
}
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so
index 02cde4d..eed3bd6 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so
index 2b9e52f..d6b80b4 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so
index 082d47d..002e5cc 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so
index bfb62a6..1b6da19 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so
index c54e182..27ea6b8 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/flockd/flockd.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/flockd/flockd.cpython-312-aarch64-linux-gnu.so
index f33e7a3..aa8334b 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/flockd/flockd.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/flockd/flockd.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/flockd/signatures.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/flockd/signatures.cpython-312-aarch64-linux-gnu.so
index ba6db65..7174afd 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/flockd/signatures.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/flockd/signatures.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/_vendor/localapi_runtime.zip b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/_vendor/localapi_runtime.zip
index 60a29f2..8d85a6e 100644
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/_vendor/localapi_runtime.zip and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/_vendor/localapi_runtime.zip differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so
index 00e2b80..509009c 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so
index 307c6d7..3df4f4a 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so
index 260cd7a..9f0093f 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so
index 02bfe85..8334826 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so
index 9a85209..1d9c92e 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so
index 12a6c5b..6fe3cbc 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so
index de09bd8..f0d71b1 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so
index 40d805f..e7cc75d 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so
index 0b6d8e8..209a630 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so
index df223ca..18a5090 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so
index 02abbdb..b88ee48 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so
index 9e58b49..4733e5a 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so differ
diff --git a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so
index 99ebda7..ae42981 100755
Binary files a/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so and b/artifacts/iqpilot_hephaestusd_private/python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so differ
diff --git a/cereal/custom.capnp b/cereal/custom.capnp
index 110dc8e..a63212c 100644
--- a/cereal/custom.capnp
+++ b/cereal/custom.capnp
@@ -332,6 +332,7 @@ struct IQCarParams @0xd4189b5c8aca9f78 {
iqLateralNet @4 :LateralNet;
longitudinalStoppingSpeedOverride @5 :Float32; # m/s; zero keeps the upstream default
+ stoppingDecelRateOverride @6 :Float32; # m/s^3; zero keeps the upstream default
struct LateralNet {
fuzzyFingerprint @0 :Bool;
diff --git a/common/api/base.py b/common/api/base.py
index 5cb5934..7e53329 100644
--- a/common/api/base.py
+++ b/common/api/base.py
@@ -3,6 +3,7 @@ import os
import requests
import unicodedata
from datetime import datetime, timedelta, UTC
+from functools import lru_cache
from openpilot.system.hardware.hw import Paths
from openpilot.system.version import get_version
@@ -11,6 +12,16 @@ KEYS = {"id_rsa": "RS256",
"id_ecdsa": "ES256"}
+@lru_cache(maxsize=4)
+def load_signing_key(private_key: str):
+ # PyJWT re-parses a PEM string on every encode; an RSA parse is ~40ms, so cache the key object
+ try:
+ from cryptography.hazmat.primitives.serialization import load_pem_private_key
+ return load_pem_private_key(private_key.encode(), password=None)
+ except Exception:
+ return private_key
+
+
class BaseApi:
def __init__(self, dongle_id, api_host, user_agent="openpilot-"):
self.dongle_id = dongle_id
@@ -38,7 +49,8 @@ class BaseApi:
}
if payload_extra is not None:
payload.update(payload_extra)
- token = jwt.encode(payload, self.private_key, algorithm=self.jwt_algorithm)
+ key = load_signing_key(self.private_key) if self.private_key else self.private_key
+ token = jwt.encode(payload, key, algorithm=self.jwt_algorithm)
if isinstance(token, bytes):
token = token.decode('utf8')
return token
diff --git a/common/utils.py b/common/utils.py
index ccc6719..e0aa160 100644
--- a/common/utils.py
+++ b/common/utils.py
@@ -167,6 +167,91 @@ def managed_proc(cmd: list[str], env: dict[str, str]):
proc.kill()
+def tabulate(tabular_data, headers=(), tablefmt="simple", floatfmt="g", stralign="left", numalign=None):
+ rows = [list(row) for row in tabular_data]
+
+ def fmt(val):
+ if isinstance(val, str):
+ return val
+ if isinstance(val, (bool, int)):
+ return str(val)
+ try:
+ return format(val, floatfmt)
+ except (TypeError, ValueError):
+ return str(val)
+
+ formatted = [[fmt(c) for c in row] for row in rows]
+ hdrs = [str(h) for h in headers] if headers else None
+
+ ncols = max((len(r) for r in formatted), default=0)
+ if hdrs:
+ ncols = max(ncols, len(hdrs))
+ if ncols == 0:
+ return ""
+
+ for r in formatted:
+ r.extend([""] * (ncols - len(r)))
+ if hdrs:
+ hdrs.extend([""] * (ncols - len(hdrs)))
+
+ widths = [0] * ncols
+ if hdrs:
+ for i in range(ncols):
+ widths[i] = len(hdrs[i])
+ for row in formatted:
+ for i in range(ncols):
+ widths[i] = max(widths[i], max(len(ln) for ln in row[i].split('\n')))
+
+ def _align(s, w):
+ if stralign == "center":
+ return s.center(w)
+ return s.ljust(w)
+
+ if tablefmt == "html":
+ parts = ["
"]
+ if hdrs:
+ parts.append("")
+ parts.append("" + "".join(f"| {h} | " for h in hdrs) + "
")
+ parts.append("")
+ parts.append("")
+ for row in formatted:
+ parts.append("" + "".join(f"| {c} | " for c in row) + "
")
+ parts.append("")
+ parts.append("
")
+ return "\n".join(parts)
+
+ if tablefmt == "simple_grid":
+ def _sep(left, mid, right):
+ return left + mid.join("─" * (w + 2) for w in widths) + right
+
+ top, mid_sep, bot = _sep("┌", "┬", "┐"), _sep("├", "┼", "┤"), _sep("└", "┴", "┘")
+
+ def _fmt_row(cells):
+ split = [c.split('\n') for c in cells]
+ nlines = max(len(s) for s in split)
+ for s in split:
+ s.extend([""] * (nlines - len(s)))
+ return ["│" + "│".join(f" {_align(split[i][li], widths[i])} " for i in range(ncols)) + "│" for li in range(nlines)]
+
+ lines = [top]
+ if hdrs:
+ lines.extend(_fmt_row(hdrs))
+ lines.append(mid_sep)
+ for ri, row in enumerate(formatted):
+ lines.extend(_fmt_row(row))
+ lines.append(mid_sep if ri < len(formatted) - 1 else bot)
+ return "\n".join(lines)
+
+ gap = " "
+ lines = []
+ if hdrs:
+ lines.append(gap.join(h.ljust(w) for h, w in zip(hdrs, widths, strict=True)))
+ lines.append(gap.join("-" * w for w in widths))
+ for row in formatted:
+ lines.append(gap.join(_align(row[i], widths[i]) for i in range(ncols)))
+ return "\n".join(lines)
+
+
def retry(attempts=3, delay=1.0, ignore_failure=False):
def decorator(func):
@functools.wraps(func)
diff --git a/iqdbc_repo/.codespellignore b/iqdbc_repo/.codespellignore
deleted file mode 100644
index 9161693..0000000
--- a/iqdbc_repo/.codespellignore
+++ /dev/null
@@ -1 +0,0 @@
-Wen
diff --git a/iqdbc_repo/LICENSE b/iqdbc_repo/LICENSE
index f1fd199..31df1b9 100644
--- a/iqdbc_repo/LICENSE
+++ b/iqdbc_repo/LICENSE
@@ -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:
diff --git a/iqdbc_repo/LICENSE.md b/iqdbc_repo/LICENSE.md
index a2f4893..31df1b9 100644
--- a/iqdbc_repo/LICENSE.md
+++ b/iqdbc_repo/LICENSE.md
@@ -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.
diff --git a/iqdbc_repo/MANIFEST.in b/iqdbc_repo/MANIFEST.in
deleted file mode 100644
index aae73e4..0000000
--- a/iqdbc_repo/MANIFEST.in
+++ /dev/null
@@ -1,3 +0,0 @@
-include iqdbc/car/car.capnp
-include iqdbc/car/include/c++.capnp
-recursive-include iqdbc/safety *.h
diff --git a/iqdbc_repo/credits/CREDITS.MD b/iqdbc_repo/credits/CREDITS.MD
new file mode 100644
index 0000000..c2909f6
--- /dev/null
+++ b/iqdbc_repo/credits/CREDITS.MD
@@ -0,0 +1,55 @@
+## 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) - carrotpilot
+
+#### Contributors
+
+Full credit for the Hyundai / Kia / Genesis port and its HKG-specific tuning belongs to:
+
+- carrotpilot
+- ajouatom
+
+#### Attribution
+
+This repository carries the carrotpilot HKG implementation from `ajouatom/openpilot`, imported from commit `b54d44efd514bc61f86f08b01c23a6c190885c07`. IQ.Lvbs claims no copyright, credit, or authorship over that implementation.
+
+#### 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 the Hyundai/Kia/Genesis car, DBC, and safety implementations and the supporting schema and compatibility changes required by that port.
+
+### 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`.
diff --git a/iqdbc_repo/docs/CARS.md b/iqdbc_repo/docs/CARS.md
deleted file mode 100644
index 534c98a..0000000
--- a/iqdbc_repo/docs/CARS.md
+++ /dev/null
@@ -1,441 +0,0 @@
-
-
-# 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.
diff --git a/iqdbc_repo/examples/joystick.py b/iqdbc_repo/examples/joystick.py
deleted file mode 100755
index ed989cf..0000000
--- a/iqdbc_repo/examples/joystick.py
+++ /dev/null
@@ -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)
diff --git a/iqdbc_repo/examples/kbhit.py b/iqdbc_repo/examples/kbhit.py
deleted file mode 100755
index 58fde34..0000000
--- a/iqdbc_repo/examples/kbhit.py
+++ /dev/null
@@ -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()
diff --git a/iqdbc_repo/iqdbc/can/dbc.py b/iqdbc_repo/iqdbc/can/dbc.py
index d924dc3..5242076 100644
--- a/iqdbc_repo/iqdbc/can/dbc.py
+++ b/iqdbc_repo/iqdbc/can/dbc.py
@@ -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)
diff --git a/iqdbc_repo/iqdbc/can/parser.py b/iqdbc_repo/iqdbc/can/parser.py
index 929c8d6..ab21ce8 100644
--- a/iqdbc_repo/iqdbc/can/parser.py
+++ b/iqdbc_repo/iqdbc/can/parser.py
@@ -1,5 +1,6 @@
import math
import numbers
+import time
from collections import defaultdict, deque
from dataclasses import dataclass, field
@@ -154,7 +155,7 @@ class CANParser:
self.last_nonempty_nanos: int = 0
self._last_update_nanos: int = 0
- def _add_message(self, name_or_addr: str | int, freq: int | None = None) -> None:
+ def _add_message(self, name_or_addr: str | int, freq: int | None = None, ignore_counter: bool = False) -> None:
if isinstance(name_or_addr, numbers.Number):
msg = self.dbc.addr_to_msg.get(int(name_or_addr))
else:
@@ -171,16 +172,15 @@ class CANParser:
self.vl_all[msg.name] = self.vl_all[msg.address]
self.ts_nanos[msg.address] = {s: 0 for s in signal_names}
self.ts_nanos[msg.name] = self.ts_nanos[msg.address]
- self.dat[msg.address] = b""
- self.dat[msg.name] = b""
-
state = MessageState(
address=msg.address,
name=msg.name,
size=msg.size,
signals=list(msg.sigs.values()),
ignore_alive=freq is not None and math.isnan(freq),
+ ignore_counter=ignore_counter,
)
+ state.first_seen_nanos = time.monotonic_ns()
if freq is not None and freq > 0:
state.frequency = freq
else:
diff --git a/iqdbc_repo/iqdbc/can/tests/test_packer_parser.py b/iqdbc_repo/iqdbc/can/tests/test_packer_parser.py
index d9a63d8..8dc59e5 100644
--- a/iqdbc_repo/iqdbc/can/tests/test_packer_parser.py
+++ b/iqdbc_repo/iqdbc/can/tests/test_packer_parser.py
@@ -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)
diff --git a/iqdbc_repo/iqdbc/car/CARS_template.md b/iqdbc_repo/iqdbc/car/CARS_template.md
deleted file mode 100644
index 58510e6..0000000
--- a/iqdbc_repo/iqdbc/car/CARS_template.md
+++ /dev/null
@@ -1,74 +0,0 @@
-
-
-# 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.
diff --git a/iqdbc_repo/iqdbc/car/car.capnp b/iqdbc_repo/iqdbc/car/car.capnp
index 971dc89..8bc3d70 100644
--- a/iqdbc_repo/iqdbc/car/car.capnp
+++ b/iqdbc_repo/iqdbc/car/car.capnp
@@ -238,6 +238,42 @@ struct CarState {
fuelTankLevelL @63 :Float32; # raw fuel tank level in liters (konn3kt: VW PQ Kombi_1.Tankinhalt)
batteryDetails @65 :BatteryDetails;
+ # carrotpilot HKG extension state
+ vCluRatio @68 :Float32;
+ logCarrot @69 :Text;
+ softHoldActive @70 :Int16;
+ activateCruise @71 :Int16;
+ latEnabled @72 :Bool;
+ pcmCruiseGap @73 :Int16;
+ speedLimit @74 :Float32;
+ speedLimitDistance @75 :Float32;
+ gearStep @76 :Int16;
+ tpms @77 :Tpms;
+ useLaneLineSpeed @78 :Float32;
+ leftLatDist @79 :Float32;
+ rightLatDist @80 :Float32;
+ leftLongDist @81 :Float32;
+ rightLongDist @82 :Float32;
+ carrotCruise @83 :Int16;
+ leftLaneLine @84 :Int16;
+ rightLaneLine @85 :Int16;
+ datetime @86 :UInt64;
+ leftRearLongDist @87 :Float32;
+ rightRearLongDist @88 :Float32;
+ leftRearLatDist @89 :Float32;
+ rightRearLatDist @90 :Float32;
+ trailerConnected @91 :Bool;
+ ureaGauge @92 :Float32;
+ evModeActive @93 :Bool;
+ evModeValid @94 :Bool;
+
+ struct Tpms {
+ fl @0 :Float32;
+ fr @1 :Float32;
+ rl @2 :Float32;
+ rr @3 :Float32;
+ }
+
struct BatteryDetails {
capacity @0 :Float32;
charge @1 :Float32;
@@ -310,8 +346,8 @@ struct CarState {
# deprecated
errorsDEPRECATED @0 :List(OnroadEventDEPRECATED.EventName);
- gasDEPRECATED @3 :Float32; # this is user pedal only
- brakeLightsDEPRECATED @19 :Bool;
+ gas @3 :Float32; # this is user pedal only
+ brakeLights @19 :Bool;
steeringRateLimitedDEPRECATED @29 :Bool;
canMonoTimesDEPRECATED @12: List(UInt64);
canRcvTimeoutDEPRECATED @49 :Bool;
@@ -349,6 +385,18 @@ struct RadarData @0x888ad6581cf0aacb {
# some radars flag measurements VS estimates
measured @6 :Bool;
+
+ vLead @7 :Float32; # m/s
+ aLead @8 :Float32; # m/s^2
+ jLead @9 :Float32; # m/s^3
+ radarSource @10 :RadarSource;
+
+ enum RadarSource {
+ frontRadar @0;
+ scc @1;
+ corner235 @2;
+ corner180 @3;
+ }
}
enum ErrorDEPRECATED {
@@ -404,6 +452,8 @@ struct CarControl {
brake @1: Float32; # [0.0, 1.0]
torqueOutputCan @8: Float32; # value sent over can to the car
speed @6: Float32; # m/s
+ jerk @9: Float32; # m/s^3
+ aTarget @10: Float32; # m/s^2
enum LongControlState @0xe40f3a917d908282{
off @0;
@@ -439,6 +489,12 @@ struct CarControl {
leadFollowTime @11: Float32;
leadDistance @12: Float32;
driverUnresponsive @13: Bool;
+ activeCarrot @14: Int16;
+ leadRelSpeed @15: Float32;
+ leadDPath @16: Float32;
+ leadRadar @17: Int16;
+ modelDesire @18: Int16;
+ atcDistance @19: Float32;
# not used with the dash, TODO: separate structs for dash UI and device UI
audibleAlert @5: AudibleAlert;
@@ -502,6 +558,7 @@ struct CarParams {
enableBsm @56 :Bool; # blind spot monitoring
flags @64 :UInt32; # flags for car specific quirks
alphaLongitudinalAvailable @71 :Bool;
+ extFlags @79 :UInt32; # carrotpilot HKG extension flags
minEnableSpeed @7 :Float32;
minSteerSpeed @8 :Float32;
@@ -538,14 +595,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
@@ -603,7 +655,7 @@ struct CarParams {
kpV @1 :List(Float32);
kiBP @2 :List(Float32);
kiV @3 :List(Float32);
- kfDEPRECATED @6 :Float32;
+ kf @6 :Float32;
deadzoneBPDEPRECATED @4 :List(Float32);
deadzoneVDEPRECATED @5 :List(Float32);
}
@@ -776,6 +828,11 @@ struct CarParams {
maxSteeringAngleDegDEPRECATED @54 :Float32;
longitudinalActuatorDelayLowerBoundDEPRECATED @61 :Float32;
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
+ radarTimeStep @45: Float32 = 0.05; # time delta between radar updates, 20Hz is very standard
enableDsuDEPRECATED @5 :Bool; # driving support unit
+ vEgoStarting @59 :Float32;
+ startAccel @32 :Float32;
+ startingState @70 :Bool;
+ vEgoStoppingDEPRECATED @29 :Float32;
+ stoppingDecelRateDEPRECATED @52 :Float32;
}
diff --git a/iqdbc_repo/iqdbc/car/car_helpers.py b/iqdbc_repo/iqdbc/car/car_helpers.py
index 1c69e32..e5d2084 100644
--- a/iqdbc_repo/iqdbc/car/car_helpers.py
+++ b/iqdbc_repo/iqdbc/car/car_helpers.py
@@ -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()
diff --git a/iqdbc_repo/iqdbc/car/chrysler/carcontroller.py b/iqdbc_repo/iqdbc/car/chrysler/carcontroller.py
index 1e62de3..eda8201 100644
--- a/iqdbc_repo/iqdbc/car/chrysler/carcontroller.py
+++ b/iqdbc_repo/iqdbc/car/chrysler/carcontroller.py
@@ -5,16 +5,16 @@ from iqdbc.car.chrysler import chryslercan
from iqdbc.car.chrysler.values import RAM_CARS, CarControllerParams, ChryslerFlags, RAM_DT
from iqdbc.car.interfaces import CarControllerBase
-from iqdbc.lvbs.car.chrysler.carcontroller_ext import CarControllerExt
+from iqdbc.lvbs.car.chrysler.iq_carcontroller import IQCarController
from iqdbc.lvbs.car.chrysler.aol import AolCarController
-from iqdbc.lvbs.car.chrysler.values_ext import ChryslerFlagsIQ
+from iqdbc.lvbs.car.chrysler.iq_values import ChryslerFlagsIQ
-class CarController(CarControllerBase, AolCarController, CarControllerExt):
+class CarController(CarControllerBase, AolCarController, IQCarController):
def __init__(self, dbc_names, CP, CP_IQ):
CarControllerBase.__init__(self, dbc_names, CP, CP_IQ)
AolCarController.__init__(self)
- CarControllerExt.__init__(self, CP, CP_IQ)
+ IQCarController.__init__(self, CP, CP_IQ)
self.apply_torque_last = 0
self.hud_count = 0
@@ -58,7 +58,7 @@ class CarController(CarControllerBase, AolCarController, CarControllerExt):
# TODO: can we make this more sane? why is it different for all the cars?
lkas_control_bit = self.lkas_control_bit_prev
if self.CP_IQ.flags & ChryslerFlagsIQ.NO_MIN_STEERING_SPEED or self.CP.carFingerprint in RAM_DT:
- lkas_control_bit = CarControllerExt.get_lkas_control_bit(self, CS, CC, lkas_control_bit)
+ lkas_control_bit = IQCarController.get_lkas_control_bit(self, CS, CC, lkas_control_bit)
elif CS.out.vEgo > self.CP.minSteerSpeed:
lkas_control_bit = True
elif self.CP.flags & ChryslerFlags.HIGHER_MIN_STEERING_SPEED:
diff --git a/iqdbc_repo/iqdbc/car/chrysler/carstate.py b/iqdbc_repo/iqdbc/car/chrysler/carstate.py
index 83c0cb1..fc0cf47 100644
--- a/iqdbc_repo/iqdbc/car/chrysler/carstate.py
+++ b/iqdbc_repo/iqdbc/car/chrysler/carstate.py
@@ -4,17 +4,17 @@ from iqdbc.car.chrysler.values import DBC, STEER_THRESHOLD, RAM_CARS
from iqdbc.car.common.conversions import Conversions as CV
from iqdbc.car.interfaces import CarStateBase
-from iqdbc.lvbs.car.chrysler.carstate_ext import CarStateExt
from iqdbc.lvbs.car.chrysler.aol import AolCarState
+from iqdbc.lvbs.car.chrysler.iq_carstate import IQCarState
ButtonType = structs.CarState.ButtonEvent.Type
-class CarState(CarStateBase, AolCarState, CarStateExt):
+class CarState(CarStateBase, AolCarState, IQCarState):
def __init__(self, CP, CP_IQ):
CarStateBase.__init__(self, CP, CP_IQ)
AolCarState.__init__(self, CP, CP_IQ)
- CarStateExt.__init__(self, CP, CP_IQ)
+ IQCarState.__init__(self, CP, CP_IQ)
self.CP = CP
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
@@ -102,7 +102,7 @@ class CarState(CarStateBase, AolCarState, CarStateExt):
self.button_counter = cp.vl["CRUISE_BUTTONS"]["COUNTER"]
AolCarState.update_aol(self, ret, can_parsers)
- CarStateExt.update(self, ret, ret_iq, can_parsers)
+ IQCarState.update(self, ret, ret_iq, can_parsers)
ret.buttonEvents = [
*create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise}),
@@ -114,7 +114,10 @@ class CarState(CarStateBase, AolCarState, CarStateExt):
@staticmethod
def get_can_parsers(CP, CP_IQ):
+ pt_messages: list = []
+ cam_messages: list = []
+ AolCarState.get_parser(CP, pt_messages, cam_messages)
return {
- Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 0),
- Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 2),
+ Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], pt_messages, 0),
+ Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], cam_messages, 2),
}
diff --git a/iqdbc_repo/iqdbc/car/chrysler/fingerprints.py b/iqdbc_repo/iqdbc/car/chrysler/fingerprints.py
index 87d1e5f..a9c4fa4 100644
--- a/iqdbc_repo/iqdbc/car/chrysler/fingerprints.py
+++ b/iqdbc_repo/iqdbc/car/chrysler/fingerprints.py
@@ -1,9 +1,9 @@
""" AUTO-FORMATTED USING iqdbc/car/debug/format_fingerprints.py, EDIT STRUCTURE THERE."""
from iqdbc.car.structs import CarParams
from iqdbc.car.chrysler.values import CAR
+from iqdbc.lvbs.car.iq_fingerprints import extend_fw_versions
+from iqdbc.lvbs.car.chrysler.iq_fingerprints import FW_VERSIONS_EXT
-from iqdbc.lvbs.car.fingerprints_ext import extend_fw_versions
-from iqdbc.lvbs.car.chrysler.fingerprints_ext import FW_VERSIONS_EXT
Ecu = CarParams.Ecu
@@ -789,4 +789,6 @@ FW_VERSIONS = {
},
}
+
+
FW_VERSIONS = extend_fw_versions(FW_VERSIONS, FW_VERSIONS_EXT)
diff --git a/iqdbc_repo/iqdbc/car/chrysler/interface.py b/iqdbc_repo/iqdbc/car/chrysler/interface.py
index de41141..7b880ba 100755
--- a/iqdbc_repo/iqdbc/car/chrysler/interface.py
+++ b/iqdbc_repo/iqdbc/car/chrysler/interface.py
@@ -5,7 +5,7 @@ from iqdbc.car.chrysler.carstate import CarState
from iqdbc.car.chrysler.radar_interface import RadarInterface
from iqdbc.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags, ChryslerSafetyFlags
from iqdbc.car.interfaces import CarInterfaceBase
-from iqdbc.lvbs.car.chrysler.values_ext import ChryslerFlagsIQ
+from iqdbc.lvbs.car.chrysler.iq_values import ChryslerFlagsIQ
class CarInterface(CarInterfaceBase):
@@ -100,9 +100,10 @@ class CarInterface(CarInterfaceBase):
stock_cp.wheelbase = 3.79
stock_cp.steerRatio = 19.
+ # LKAS heartbeat on bus 0 (msg 0x4FF) means the camera is on the ADAS bus and
+ # IQ.Pilot can steer down to a standstill.
if 0x4FF in fingerprint[0]:
ret.flags |= ChryslerFlagsIQ.NO_MIN_STEERING_SPEED.value
stock_cp.minSteerSpeed = 0.
-
return ret
diff --git a/iqdbc_repo/iqdbc/car/docs.py b/iqdbc_repo/iqdbc/car/docs.py
index 9e3d89d..43e85fb 100755
--- a/iqdbc_repo/iqdbc/car/docs.py
+++ b/iqdbc_repo/iqdbc/car/docs.py
@@ -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()
diff --git a/iqdbc_repo/iqdbc/car/ford/carstate.py b/iqdbc_repo/iqdbc/car/ford/carstate.py
index 6c23161..7080d2e 100644
--- a/iqdbc_repo/iqdbc/car/ford/carstate.py
+++ b/iqdbc_repo/iqdbc/car/ford/carstate.py
@@ -5,17 +5,14 @@ from iqdbc.car.ford.fordcan import CanBus
from iqdbc.car.ford.values import DBC, CarControllerParams, FordFlags
from iqdbc.car.interfaces import CarStateBase
-from iqdbc.lvbs.car.ford.aol import AolCarState
-
ButtonType = structs.CarState.ButtonEvent.Type
GearShifter = structs.CarState.GearShifter
TransmissionType = structs.CarParams.TransmissionType
-class CarState(CarStateBase, AolCarState):
+class CarState(CarStateBase):
def __init__(self, CP, CP_IQ):
CarStateBase.__init__(self, CP, CP_IQ)
- AolCarState.__init__(self, CP, CP_IQ)
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
if CP.transmissionType == TransmissionType.automatic:
self.shifter_values = can_define.dv["PowertrainData_10"]["TrnRng_D_Rq"]
@@ -112,8 +109,6 @@ class CarState(CarStateBase, AolCarState):
self.acc_tja_status_stock_values = cp_cam.vl["ACCDATA_3"]
self.lkas_status_stock_values = cp_cam.vl["IPMA_Data"]
- AolCarState.update_aol(self, ret, can_parsers)
-
ret.buttonEvents = [
*create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise}),
*create_button_events(self.lc_button, prev_lc_button, {1: ButtonType.lkas}),
diff --git a/iqdbc_repo/iqdbc/car/gm/carstate.py b/iqdbc_repo/iqdbc/car/gm/carstate.py
index 87aecd3..b7c18c3 100644
--- a/iqdbc_repo/iqdbc/car/gm/carstate.py
+++ b/iqdbc_repo/iqdbc/car/gm/carstate.py
@@ -5,8 +5,8 @@ from iqdbc.car.common.conversions import Conversions as CV
from iqdbc.car.interfaces import CarStateBase
from iqdbc.car.gm.values import DBC, AccState, CruiseButtons, STEER_THRESHOLD, SDGM_CAR, ALT_ACCS
-from iqdbc.lvbs.car.gm.carstate_ext import CarStateExt
-from iqdbc.lvbs.car.gm.values_ext import GMFlagsIQ
+from iqdbc.lvbs.car.gm.iq_carstate import IQCarState
+from iqdbc.lvbs.car.gm.iq_values import GMFlagsIQ
ButtonType = structs.CarState.ButtonEvent.Type
TransmissionType = structs.CarParams.TransmissionType
@@ -18,10 +18,10 @@ BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.D
CruiseButtons.MAIN: ButtonType.mainCruise, CruiseButtons.CANCEL: ButtonType.cancel}
-class CarState(CarStateBase, CarStateExt):
+class CarState(CarStateBase, IQCarState):
def __init__(self, CP, CP_IQ):
CarStateBase.__init__(self, CP, CP_IQ)
- CarStateExt.__init__(self, CP, CP_IQ)
+ IQCarState.__init__(self, CP, CP_IQ)
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
self.shifter_values = can_define.dv["ECMPRDNL2"]["PRNDL2"]
self.cluster_speed_hyst_gap = CV.KPH_TO_MS / 2.
@@ -163,7 +163,7 @@ class CarState(CarStateBase, CarStateExt):
if ret.vEgo < self.CP.minSteerSpeed:
ret.lowSpeedAlert = True
- CarStateExt.update(self, ret, can_parsers)
+ IQCarState.update(self, ret, can_parsers)
return ret, ret_iq
diff --git a/iqdbc_repo/iqdbc/car/gm/fingerprints.py b/iqdbc_repo/iqdbc/car/gm/fingerprints.py
index 3705935..25063d7 100644
--- a/iqdbc_repo/iqdbc/car/gm/fingerprints.py
+++ b/iqdbc_repo/iqdbc/car/gm/fingerprints.py
@@ -1,9 +1,8 @@
# ruff: noqa: E501
""" AUTO-FORMATTED USING iqdbc/car/debug/format_fingerprints.py, EDIT STRUCTURE THERE."""
from iqdbc.car.gm.values import CAR
-
-from iqdbc.lvbs.car.fingerprints_ext import extend_fingerprints
-from iqdbc.lvbs.car.gm.fingerprints_ext import FINGERPRINTS_EXT
+from iqdbc.lvbs.car.iq_fingerprints import extend_fingerprints
+from iqdbc.lvbs.car.gm.iq_fingerprints import FINGERPRINTS_EXT
# Trailblazer also matches as a SILVERADO, TODO: split with fw versions
# FIXME: There are Equinox users with different message lengths, specifically 304 and 320
@@ -54,6 +53,9 @@ FINGERPRINTS = {
}],
CAR.CHEVROLET_SILVERADO: [{
190: 6, 193: 8, 197: 8, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 460: 5, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 528: 5, 532: 6, 534: 2, 560: 8, 562: 8, 563: 5, 565: 5, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 761: 7, 789: 5, 800: 6, 801: 8, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 869: 4, 880: 6, 977: 8, 1001: 8, 1011: 6, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1611: 8, 1930: 7
+ },
+ {
+ 190: 6, 193: 8, 197: 8, 201: 8, 208: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 3, 288: 5, 289: 8, 298: 8, 304: 3, 309: 8, 311: 8, 313: 8, 320: 4, 322: 7, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 460: 5, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 528: 5, 532: 6, 534: 2, 560: 8, 562: 8, 563: 5, 565: 5, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 761: 7, 789: 5, 800: 6, 801: 8, 810: 8, 840: 5, 842: 5, 844: 8, 848: 4, 869: 4, 880: 6, 977: 8, 1001: 8, 1011: 6, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1611: 8, 1930: 7
}],
CAR.CHEVROLET_EQUINOX: [{
190: 6, 193: 8, 197: 8, 201: 8, 209: 7, 211: 2, 241: 6, 249: 8, 257: 8, 288: 5, 289: 8, 298: 8, 304: 1, 309: 8, 311: 8, 313: 8, 320: 3, 328: 1, 352: 5, 381: 8, 384: 4, 386: 8, 388: 8, 413: 8, 451: 8, 452: 8, 453: 6, 455: 7, 463: 3, 479: 3, 481: 7, 485: 8, 489: 8, 497: 8, 500: 6, 501: 8, 510: 8, 528: 5, 532: 6, 560: 8, 562: 8, 563: 5, 565: 5, 587: 8, 608: 8, 609: 6, 610: 6, 611: 6, 612: 8, 613: 8, 707: 8, 715: 8, 717: 5, 753: 5, 761: 7, 789: 5, 800: 6, 810: 8, 840: 5, 842: 5, 844: 8, 869: 4, 880: 6, 977: 8, 1001: 8, 1011: 6, 1017: 8, 1020: 8, 1033: 7, 1034: 7, 1217: 8, 1221: 5, 1233: 8, 1249: 8, 1259: 8, 1261: 7, 1263: 4, 1265: 8, 1267: 1, 1271: 8, 1280: 4, 1296: 4, 1300: 8, 1611: 8, 1930: 7
@@ -78,4 +80,5 @@ FINGERPRINTS = {
FW_VERSIONS: dict[str, dict[tuple, list[bytes]]] = {
}
+
FINGERPRINTS = extend_fingerprints(FINGERPRINTS, FINGERPRINTS_EXT)
diff --git a/iqdbc_repo/iqdbc/car/gm/interface.py b/iqdbc_repo/iqdbc/car/gm/interface.py
index 5175ba0..238a992 100755
--- a/iqdbc_repo/iqdbc/car/gm/interface.py
+++ b/iqdbc_repo/iqdbc/car/gm/interface.py
@@ -10,13 +10,13 @@ from iqdbc.car.gm.radar_interface import RadarInterface, RADAR_HEADER_MSG, CAMER
from iqdbc.car.gm.values import CAR, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, SDGM_CAR, ALT_ACCS, CanBus, GMSafetyFlags
from iqdbc.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, LateralAccelFromTorqueCallbackType
-from iqdbc.lvbs.car.gm.interface_ext import CarInterfaceExt
-from iqdbc.lvbs.car.gm.values_ext import GMFlagsIQ, GMSafetyFlagsIQ
+from iqdbc.lvbs.car.gm.iq_interface import IQCarInterface
+from iqdbc.lvbs.car.gm.iq_values import GMFlagsIQ, GMSafetyFlagsIQ
TransmissionType = structs.CarParams.TransmissionType
NetworkLocation = structs.CarParams.NetworkLocation
-# iqpilot-specific torque parameters for Bolt cars that actually use the d parameter
+# Bolt Non-ACC uses the 4th (d) tune parameter; stock tunes zero it out.
NON_LINEAR_TORQUE_PARAMS_IQ = {
CAR.CHEVROLET_BOLT_NON_ACC: [2.24, 1.1, 0.28, -0.07],
CAR.CHEVROLET_BOLT_NON_ACC_1ST_GEN: [1.8, 1.1, 0.3, -0.045],
@@ -30,7 +30,7 @@ NON_LINEAR_TORQUE_PARAMS = {
}
-class CarInterface(CarInterfaceBase, CarInterfaceExt):
+class CarInterface(CarInterfaceBase, IQCarInterface):
CarState = CarState
CarController = CarController
RadarInterface = RadarInterface
@@ -40,7 +40,7 @@ class CarInterface(CarInterfaceBase, CarInterfaceExt):
def __init__(self, CP, CP_IQ):
CarInterfaceBase.__init__(self, CP, CP_IQ)
- CarInterfaceExt.__init__(self, CP, CarInterfaceBase)
+ IQCarInterface.__init__(self, CP, CarInterfaceBase)
@staticmethod
def get_pid_accel_limits(CP, CP_IQ, current_speed, cruise_speed):
@@ -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
@@ -244,11 +241,10 @@ class CarInterface(CarInterfaceBase, CarInterfaceExt):
CAR.CHEVROLET_BOLT_NON_ACC_2ND_GEN, CAR.CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN):
stock_cp.steerActuatorDelay = 0.2
CarInterfaceBase.configure_torque_tune(candidate, stock_cp.lateralTuning)
-
elif candidate in (CAR.CHEVROLET_EQUINOX_NON_ACC_3RD_GEN, ):
CarInterfaceBase.configure_torque_tune(candidate, stock_cp.lateralTuning)
- # NON_ACC vehicles should use camera car speed thresholds
+ # Non-ACC cars steer/long via the forward camera and pcmCruise, not the ASCM.
if ret.flags & GMFlagsIQ.NON_ACC:
stock_cp.dashcamOnly = False
stock_cp.alphaLongitudinalAvailable = False
@@ -257,13 +253,13 @@ class CarInterface(CarInterfaceBase, CarInterfaceExt):
stock_cp.pcmCruise = True
stock_cp.safetyConfigs[0].safetyParam |= GMSafetyFlags.HW_CAM.value
ret.iqSafetyFlags |= GMSafetyFlagsIQ.NON_ACC
- stock_cp.minEnableSpeed = 24 * CV.MPH_TO_MS # 24 mph
- stock_cp.minSteerSpeed = 3.0 # ~6 mph
+ stock_cp.minEnableSpeed = 24 * CV.MPH_TO_MS
+ stock_cp.minSteerSpeed = 3.0
- # dashcamOnly platforms: untested platforms, need user validations
+ # Untested Non-ACC platforms ship dashcam-only pending user validation.
if candidate in (CAR.CHEVROLET_BOLT_NON_ACC_2ND_GEN, CAR.CHEVROLET_EQUINOX_NON_ACC_3RD_GEN,
- CAR.CHEVROLET_SUBURBAN_NON_ACC_11TH_GEN, CAR.CADILLAC_CT6_NON_ACC_1ST_GEN, CAR.CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN,
- CAR.CADILLAC_XT5_NON_ACC_1ST_GEN):
+ CAR.CHEVROLET_SUBURBAN_NON_ACC_11TH_GEN, CAR.CADILLAC_CT6_NON_ACC_1ST_GEN,
+ CAR.CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN, CAR.CADILLAC_XT5_NON_ACC_1ST_GEN):
stock_cp.dashcamOnly = True
return ret
diff --git a/iqdbc_repo/iqdbc/car/gm/values.py b/iqdbc_repo/iqdbc/car/gm/values.py
index 4d29e5b..62c0611 100644
--- a/iqdbc_repo/iqdbc/car/gm/values.py
+++ b/iqdbc_repo/iqdbc/car/gm/values.py
@@ -4,10 +4,9 @@ from enum import Enum, IntFlag
from iqdbc.car import Bus, PlatformConfig, DbcDict, Platforms, CarSpecs
from iqdbc.car.structs import CarParams
from iqdbc.car.docs_definitions import CarDocs, CarFootnote, CarHarness, CarParts, Column, SupportType
+from iqdbc.lvbs.car.gm.iq_values import GMFlagsIQ
from iqdbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
-from iqdbc.lvbs.car.gm.values_ext import GMFlagsIQ
-
Ecu = CarParams.Ecu
@@ -88,13 +87,6 @@ class GMCarDocs(CarDocs):
self.car_parts = CarParts.common([CarHarness.obd_ii])
-@dataclass
-class GMNonAccCarDocs(GMCarDocs):
- package: str = "No Adaptive Cruise Control (Non-ACC)"
- support_type: SupportType = SupportType.COMMUNITY
- support_link: str = "community"
-
-
@dataclass(frozen=True, kw_only=True)
class GMCarSpecs(CarSpecs):
tireStiffnessFactor: float = 0.444 # not optimized yet
@@ -123,6 +115,13 @@ class GMSDGMPlatformConfig(GMPlatformConfig):
self.car_docs = []
+@dataclass
+class GMNonAccCarDocs(GMCarDocs):
+ package: str = "No Adaptive Cruise Control (Non-ACC)"
+ support_type: SupportType = SupportType.COMMUNITY
+ support_link: str = "community"
+
+
@dataclass
class GMNonSccPlatformConfig(GMPlatformConfig):
def init(self):
@@ -209,13 +208,7 @@ class CAR(Platforms):
GMCarSpecs(mass=2490, wheelbase=2.94, steerRatio=17.3, centerToFrontRatio=0.5, tireStiffnessFactor=1.0),
)
- # port extensions
- # Separate car def is required when there is no ASCM
- # (for now) unless there is a way to detect it when it has been unplugged...
- # CHEVROLET_VOLT_CC = GMNonSccPlatformConfig(
- # [GMNonAccCarDocs("Chevrolet Volt LT 2017-18")],
- # CHEVROLET_VOLT.specs,
- # )
+ # IQ.Pilot Non-ACC camera-harness ports (no factory adaptive cruise).
CHEVROLET_BOLT_NON_ACC = GMNonSccPlatformConfig(
[GMNonAccCarDocs("Chevrolet Bolt EV Non-ACC 2017")],
CHEVROLET_BOLT_EUV.specs,
@@ -333,7 +326,7 @@ FW_QUERY_CONFIG = FwQueryConfig(
# TODO: detect most of these sets live
EV_CAR = {CAR.CHEVROLET_VOLT, CAR.CHEVROLET_VOLT_2019, CAR.CHEVROLET_BOLT_EUV,
- # port extensions, Non-ACC
+ # Non-ACC EV ports
CAR.CHEVROLET_BOLT_NON_ACC, CAR.CHEVROLET_BOLT_NON_ACC_1ST_GEN, CAR.CHEVROLET_BOLT_NON_ACC_2ND_GEN}
# We're integrated at the camera with VOACC on these cars (instead of ASCM w/ OBD-II harness)
diff --git a/iqdbc_repo/iqdbc/car/honda/carstate.py b/iqdbc_repo/iqdbc/car/honda/carstate.py
index 4f19e6c..f827771 100644
--- a/iqdbc_repo/iqdbc/car/honda/carstate.py
+++ b/iqdbc_repo/iqdbc/car/honda/carstate.py
@@ -10,7 +10,7 @@ from iqdbc.car.honda.values import CAR, DBC, STEER_THRESHOLD, HONDA_BOSCH, HONDA
HondaFlags, CruiseButtons, CruiseSettings, GearShifter, CarControllerParams
from iqdbc.car.interfaces import CarStateBase
-from iqdbc.lvbs.car.honda.carstate_ext import CarStateExt
+from iqdbc.lvbs.car.honda.iq_carstate import IQCarState
TransmissionType = structs.CarParams.TransmissionType
ButtonType = structs.CarState.ButtonEvent.Type
@@ -20,10 +20,10 @@ BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.D
SETTINGS_BUTTONS_DICT = {CruiseSettings.DISTANCE: ButtonType.gapAdjustCruise, CruiseSettings.LKAS: ButtonType.lkas}
-class CarState(CarStateBase, CarStateExt):
+class CarState(CarStateBase, IQCarState):
def __init__(self, CP, CP_IQ):
CarStateBase.__init__(self, CP, CP_IQ)
- CarStateExt.__init__(self, CP, CP_IQ)
+ IQCarState.__init__(self, CP, CP_IQ)
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
if CP.transmissionType != TransmissionType.manual:
@@ -246,7 +246,7 @@ class CarState(CarStateBase, CarStateExt):
*create_button_events(self.cruise_setting, prev_cruise_setting, SETTINGS_BUTTONS_DICT),
]
- CarStateExt.update(self, ret, can_parsers)
+ IQCarState.update(self, ret, can_parsers)
return ret, ret_iq
diff --git a/iqdbc_repo/iqdbc/car/honda/fingerprints.py b/iqdbc_repo/iqdbc/car/honda/fingerprints.py
index f667c62..89b1da0 100644
--- a/iqdbc_repo/iqdbc/car/honda/fingerprints.py
+++ b/iqdbc_repo/iqdbc/car/honda/fingerprints.py
@@ -2,8 +2,8 @@
from iqdbc.car.structs import CarParams
from iqdbc.car.honda.values import CAR
-from iqdbc.lvbs.car.fingerprints_ext import extend_fw_versions
-from iqdbc.lvbs.car.honda.fingerprints_ext import FW_VERSIONS_EXT
+from iqdbc.lvbs.car.iq_fingerprints import extend_fw_versions
+from iqdbc.lvbs.car.honda.iq_fingerprints import FW_VERSIONS_EXT
Ecu = CarParams.Ecu
@@ -994,6 +994,7 @@ FW_VERSIONS = {
b'8S102-T56-A070\x00\x00',
b'8S102-T60-AA10\x00\x00',
b'8S102-T64-A040\x00\x00',
+ b'8S102-T64-A050\x00\x00',
],
(Ecu.vsa, 0x18da28f1, None): [
b'57114-T20-AB40\x00\x00',
diff --git a/iqdbc_repo/iqdbc/car/honda/hondacan.py b/iqdbc_repo/iqdbc/car/honda/hondacan.py
index f55cd67..818c86e 100644
--- a/iqdbc_repo/iqdbc/car/honda/hondacan.py
+++ b/iqdbc_repo/iqdbc/car/honda/hondacan.py
@@ -2,7 +2,7 @@ from iqdbc.car import CanBusBase
from iqdbc.car.common.conversions import Conversions as CV
from iqdbc.car.honda.values import (HondaFlags, HONDA_BOSCH, HONDA_BOSCH_ALT_RADAR, HONDA_BOSCH_RADARLESS,
HONDA_BOSCH_CANFD, CarControllerParams)
-from iqdbc.lvbs.car.honda.values_ext import HondaFlagsIQ
+from iqdbc.lvbs.car.honda.iq_values import HondaFlagsIQ
# CAN bus layout with relay
# 0 = ACC-CAN - radar side
diff --git a/iqdbc_repo/iqdbc/car/honda/interface.py b/iqdbc_repo/iqdbc/car/honda/interface.py
index 80114ca..cf24f09 100755
--- a/iqdbc_repo/iqdbc/car/honda/interface.py
+++ b/iqdbc_repo/iqdbc/car/honda/interface.py
@@ -11,7 +11,7 @@ from iqdbc.car.honda.carstate import CarState
from iqdbc.car.honda.radar_interface import RadarInterface
from iqdbc.car.interfaces import CarInterfaceBase
-from iqdbc.lvbs.car.honda.values_ext import HondaFlagsIQ, HondaSafetyFlagsIQ
+from iqdbc.lvbs.car.honda.iq_values import HondaFlagsIQ, HondaSafetyFlagsIQ
TransmissionType = structs.CarParams.TransmissionType
@@ -88,9 +88,11 @@ class CarInterface(CarInterfaceBase):
ret.steerActuatorDelay = 0.1
if candidate in HONDA_BOSCH:
- ret.longitudinalActuatorDelay = 0.5 # s
if candidate in HONDA_BOSCH_RADARLESS:
ret.stopAccel = CarControllerParams.BOSCH_ACCEL_MIN # stock uses -4.0 m/s^2 once stopped but limited by safety model
+ ret.longitudinalActuatorDelay = 0.25 # s
+ else:
+ ret.longitudinalActuatorDelay = 0.5 # s
else:
# default longitudinal tuning for all hondas
ret.longitudinalTuning.kiBP = [0., 5., 35.]
@@ -335,6 +337,12 @@ class CarInterface(CarInterfaceBase):
stock_cp.autoResumeSng = stock_cp.autoResumeSng or ret.enableGasInterceptor
+ if candidate == CAR.HONDA_CITY_7G:
+ ret.longitudinalStoppingSpeedOverride = 2.0
+ ret.stoppingDecelRateOverride = 0.3
+ else:
+ ret.longitudinalStoppingSpeedOverride = 0.5
+ ret.stoppingDecelRateOverride = 0.1
return ret
diff --git a/iqdbc_repo/iqdbc/car/hyundai/carcontroller.py b/iqdbc_repo/iqdbc/car/hyundai/carcontroller.py
index c9ff133..4368cbf 100644
--- a/iqdbc_repo/iqdbc/car/hyundai/carcontroller.py
+++ b/iqdbc_repo/iqdbc/car/hyundai/carcontroller.py
@@ -1,27 +1,47 @@
import numpy as np
from iqdbc.can import CANPacker
from iqdbc.car import Bus, DT_CTRL, make_tester_present_msg, structs
-from iqdbc.car.lateral import apply_driver_steer_torque_limits, common_fault_avoidance
+from iqdbc.car.lateral import apply_driver_steer_torque_limits, apply_std_steer_angle_limits, common_fault_avoidance
from iqdbc.car.common.conversions import Conversions as CV
from iqdbc.car.hyundai import hyundaicanfd, hyundaican
+from iqdbc.car.hyundai.carstate import CarState
from iqdbc.car.hyundai.hyundaicanfd import CanBus
-from iqdbc.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CAR
+from iqdbc.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CAR, CAN_GEARS, HyundaiExtFlags
from iqdbc.car.interfaces import CarControllerBase
-
-from iqdbc.lvbs.car.hyundai.escc import EsccCarController
-from iqdbc.lvbs.car.hyundai.longitudinal.controller import LongitudinalController
-from iqdbc.lvbs.car.hyundai.lead_data_ext import LeadDataCarController
-from iqdbc.lvbs.car.hyundai.aol import AolCarController
+from iqdbc.car.vehicle_model import VehicleModel
VisualAlert = structs.CarControl.HUDControl.VisualAlert
LongCtrlState = structs.CarControl.Actuators.LongControlState
+
+from openpilot.common.params import Params
+
# EPS faults if you apply torque while the steering angle is above 90 degrees for more than 1 second
# All slightly below EPS thresholds to avoid fault
MAX_ANGLE = 85
MAX_ANGLE_FRAMES = 89
MAX_ANGLE_CONSECUTIVE_FRAMES = 2
+DRIVER_TORQUE_FILTER_TAU = 0.12
+PRE_OVERRIDE_PREDICTION_TIME = 0.15
+PRE_OVERRIDE_START_RATIO = 0.90
+PRE_OVERRIDE_FULL_RATIO = 1.05
+PRE_OVERRIDE_RAW_MIN_RATIO = 0.70
+PRE_OVERRIDE_FILTERED_MIN_RATIO = 0.65
+PRE_OVERRIDE_MIN_RATE_RATIO = 0.50
+PRE_OVERRIDE_CONFIRM_FRAMES = 2
+PRE_OVERRIDE_MAX_TORQUE_DELTA = -10.0
+LOW_SPEED_ANGLE_RATE_RAMP_SPEED = 15.0 * CV.KPH_TO_MS
+MID_SPEED_ANGLE_RATE_LIMIT_SPEED = 40.0 * CV.KPH_TO_MS
+vibrate_intervals = [
+ (0.0, 0.5),
+ (1.0, 1.5),
+ #(2.5, 3.0),
+ #(3.5, 4.0),
+ (5.0, 5.5),
+ (6.0, 6.5),
+ (7.5, 8.0),
+]
def process_hud_alert(enabled, fingerprint, hud_control):
sys_warning = (hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw))
@@ -46,14 +66,75 @@ def process_hud_alert(enabled, fingerprint, hud_control):
return sys_warning, sys_state, left_lane_warning, right_lane_warning
+def rate_limit(x, x_last, lo, hi):
+ return float(np.clip(x, x_last + lo, x_last + hi))
-class CarController(CarControllerBase, EsccCarController, LeadDataCarController, LongitudinalController, AolCarController):
- def __init__(self, dbc_names, CP, CP_IQ):
- CarControllerBase.__init__(self, dbc_names, CP, CP_IQ)
- EsccCarController.__init__(self, CP, CP_IQ)
- AolCarController.__init__(self)
- LeadDataCarController.__init__(self, CP)
- LongitudinalController.__init__(self, CP, CP_IQ)
+def apply_steer_angle_limits_physics(desired_sw_deg: float,
+ last_sw_deg: float,
+ v_ego: float,
+ steering_sw_deg: float,
+ lat_active: bool,
+ wheelbase_m: float,
+ steer_ratio: float,
+ steer_sw_max_deg: float,
+ model_v2=None) -> float:
+ max_lat_accel = 8.5 # m/s^2
+ max_lat_jerk = 4.0 # m/s^3
+ y_std_1s = 0.1
+ if model_v2 is not None and len(model_v2.position.yStd) > 10:
+ model_y_std_1s = float(model_v2.position.yStd[10])
+ if np.isfinite(model_y_std_1s) and model_y_std_1s >= 0.0:
+ y_std_1s = model_y_std_1s
+ max_sw_rate_deg_per_tick = float(np.interp(y_std_1s, [0.1, 0.2, 0.4], [2.0, 1.5, 0.8]))
+ v = max(float(v_ego), 1.0)
+
+ target_sw = float(np.clip(desired_sw_deg, -steer_sw_max_deg, steer_sw_max_deg))
+ if v_ego < MID_SPEED_ANGLE_RATE_LIMIT_SPEED:
+ # Keep low/mid-speed angle commands quieter without reducing LKAS_ANGLE_MAX_TORQUE.
+ # Allow the angle, but slow the arrival: 0~15 kph ramps 0.8->1.1 deg/tick,
+ # then 15~40 kph tapers 1.1->0.8 deg/tick. Above 40 kph, physics limits take over.
+ low_mid_speed_cap = float(np.interp(v_ego,
+ [0.0, LOW_SPEED_ANGLE_RATE_RAMP_SPEED, MID_SPEED_ANGLE_RATE_LIMIT_SPEED],
+ [0.8, 1.1, 0.8]))
+ max_sw_rate_deg_per_tick = min(max_sw_rate_deg_per_tick, low_mid_speed_cap)
+
+ target_rw = target_sw / steer_ratio
+ last_rw = float(last_sw_deg) / steer_ratio
+
+ # --- accel limit ---
+ rw_max_rad = np.arctan((max_lat_accel * wheelbase_m) / (v * v))
+ rw_max = float(np.degrees(rw_max_rad))
+
+ # --- jerk -> rate limit ---
+ sec2 = 1.2
+ max_drw_dt = (max_lat_jerk * wheelbase_m) / (v * v * sec2) # rad/s
+ max_drw_per_tick = max_drw_dt * DT_CTRL # rad/tick
+ max_drw_per_tick_deg = float(np.degrees(max_drw_per_tick))
+
+ err = abs(target_sw - last_sw_deg)
+ if err > 20.0:
+ max_sw_rate_deg_per_tick = min(max_sw_rate_deg_per_tick, 1.0)
+
+ max_drw_per_tick_deg = min(
+ max_drw_per_tick_deg,
+ max_sw_rate_deg_per_tick / steer_ratio
+ )
+
+ # --- rate limit ---
+ cmd_rw = rate_limit(target_rw, last_rw, -max_drw_per_tick_deg, max_drw_per_tick_deg)
+
+ # --- accel clip ---
+ cmd_rw = float(np.clip(cmd_rw, -rw_max, rw_max))
+
+ if not lat_active:
+ cmd_rw = float(steering_sw_deg) / steer_ratio
+
+ cmd_sw = cmd_rw * steer_ratio
+ return float(np.clip(cmd_sw, -steer_sw_max_deg, steer_sw_max_deg))
+
+class CarController(CarControllerBase):
+ def __init__(self, dbc_names, CP, CP_IQ=None):
+ super().__init__(dbc_names, CP, CP_IQ or structs.IQCarParams())
self.CAN = CanBus(CP)
self.params = CarControllerParams(CP)
self.packer = CANPacker(dbc_names[Bus.pt])
@@ -64,56 +145,302 @@ class CarController(CarControllerBase, EsccCarController, LeadDataCarController,
self.car_fingerprint = CP.carFingerprint
self.last_button_frame = 0
+ self.hyundai_jerk = HyundaiJerk()
+ self.speedCameraHapticEndFrame = 0
+ self.hapticFeedbackWhenSpeedCamera = 0
+ self.max_angle_frames = MAX_ANGLE_FRAMES
+ self.blinking_signal = False # 1Hz
+ self.blinking_frame = int(1.0 / DT_CTRL)
+ self.soft_hold_mode = 2
+
+ self.activateCruise = 0
+ self.button_wait = 12
+ self.cruise_buttons_msg_values = None
+ self.cruise_buttons_msg_cnt = 0
+ self.button_spamming_count = 0
+ self.prev_clu_speed = 0
+ self.button_spam1 = 8
+ self.button_spam2 = 30
+ self.button_spam3 = 1
+
+ self.apply_angle_last = 0
+ self.lkas_max_torque = 0
+ self.angle_max_torque = 250
+ self.steering_pressed_prev = False
+ self.recovering_from_override = False
+ self.full_recovery_frames = 0
+ self.repeated_override_count = 0
+ self.override_latched = False
+ self.override_release_frames = 0
+ self.driver_torque_filtered = 0.0
+ self.driver_torque_filtered_prev = 0.0
+ self.pre_override_frames = 0
+
+ self.lkas11_active = False
+
+ self.canfd_debug = 0
+ self.MainMode_ACC_trigger = 0
+ self.LFA_trigger = 0
+
+ self.activeCarrot = 0
+ self.camera_scc_params = Params().get_int("HyundaiCameraSCC")
+ self.is_ldws_car = Params().get_bool("IsLdwsCar")
+ self.enable_corner_radar = 0
+
+ self.steerDeltaUpOrg = self.steerDeltaUp = self.steerDeltaUpLC = self.params.STEER_DELTA_UP
+ self.steerDeltaDownOrg = self.steerDeltaDown = self.steerDeltaDownLC = self.params.STEER_DELTA_DOWN
+
def update(self, CC, CC_IQ, CS, now_nanos):
- EsccCarController.update(self, CS)
- LeadDataCarController.update(self, CC_IQ)
- AolCarController.update(self, self.CP, CC, CC_IQ, self.frame)
- if self.frame % 2 == 0:
- LongitudinalController.update(self, CC, CS)
+
+ if self.frame % 50 == 0:
+ params = Params()
+ self.max_angle_frames = params.get_int("MaxAngleFrames")
+ steerMax = params.get_int("CustomSteerMax")
+ steerDeltaUp = params.get_int("CustomSteerDeltaUp")
+ steerDeltaDown = params.get_int("CustomSteerDeltaDown")
+ steerDeltaUpLC = params.get_int("CustomSteerDeltaUpLC")
+ steerDeltaDownLC = params.get_int("CustomSteerDeltaDownLC")
+ if steerMax > 0:
+ self.params.STEER_MAX = steerMax
+ if steerDeltaUp > 0:
+ self.steerDeltaUp = steerDeltaUp
+ #self.params.ANGLE_TORQUE_UP_RATE = steerDeltaUp
+ else:
+ self.steerDeltaUp = self.steerDeltaUpOrg
+ if steerDeltaDown > 0:
+ self.steerDeltaDown = steerDeltaDown
+ #self.params.ANGLE_TORQUE_DOWN_RATE = steerDeltaDown
+ else:
+ self.steerDeltaDown = self.steerDeltaDownOrg
+
+ if steerDeltaUpLC > 0:
+ self.steerDeltaUpLC = steerDeltaUpLC
+ else:
+ self.steerDeltaUpLC = self.steerDeltaUp
+ if steerDeltaDownLC > 0:
+ self.steerDeltaDownLC = steerDeltaDownLC
+ else:
+ self.steerDeltaDownLC = self.steerDeltaDown
+
+ self.soft_hold_mode = 1 if params.get_int("AutoCruiseControl") > 1 else 2
+ self.hapticFeedbackWhenSpeedCamera = int(params.get_int("HapticFeedbackWhenSpeedCamera"))
+
+ self.button_spam1 = params.get_int("CruiseButtonTest1")
+ self.button_spam2 = params.get_int("CruiseButtonTest2")
+ self.button_spam3 = params.get_int("CruiseButtonTest3")
+ self.speed_from_pcm = params.get_int("SpeedFromPCM")
+
+ self.canfd_debug = params.get_int("CanfdDebug")
+ self.camera_scc_params = params.get_int("HyundaiCameraSCC")
+ self.enable_corner_radar = params.get_int("EnableCornerRadar")
actuators = CC.actuators
hud_control = CC.hudControl
+ if hud_control.modelDesire in [3,4]:
+ self.params.STEER_DELTA_UP = self.steerDeltaUpLC
+ self.params.STEER_DELTA_DOWN = self.steerDeltaDownLC
+ else:
+ self.params.STEER_DELTA_UP = self.steerDeltaUp
+ self.params.STEER_DELTA_DOWN = self.steerDeltaDown
+
+ angle_control = self.CP.flags & HyundaiFlags.ANGLE_CONTROL
+
# steering torque
new_torque = int(round(actuators.torque * self.params.STEER_MAX))
apply_torque = apply_driver_steer_torque_limits(new_torque, self.apply_torque_last, CS.out.steeringTorque, self.params)
# >90 degree steering fault prevention
self.angle_limit_counter, apply_steer_req = common_fault_avoidance(abs(CS.out.steeringAngleDeg) >= MAX_ANGLE, CC.latActive,
- self.angle_limit_counter, MAX_ANGLE_FRAMES,
+ self.angle_limit_counter, self.max_angle_frames,
MAX_ANGLE_CONSECUTIVE_FRAMES)
+ #apply_angle = apply_std_steer_angle_limits(actuators.steeringAngleDeg, self.apply_angle_last, CS.out.vEgoRaw,
+ # CS.out.steeringAngleDeg, CC.latActive, self.params.ANGLE_LIMITS)
+
+ apply_angle = apply_steer_angle_limits_physics(
+ actuators.steeringAngleDeg,
+ self.apply_angle_last,
+ CS.out.vEgoRaw,
+ CS.out.steeringAngleDeg,
+ CC.latActive,
+ self.CP.wheelbase,
+ self.CP.steerRatio,
+ self.params.ANGLE_LIMITS.STEER_ANGLE_MAX,
+ CS.modelV2,
+ )
+
+
+ if angle_control:
+ apply_steer_req = CC.latActive
+
+ angle_torque_cap = self.angle_max_torque
+
+ steering_pressed_rising = CS.out.steeringPressed and not self.steering_pressed_prev
+ if steering_pressed_rising:
+ if 0 < self.full_recovery_frames < int(5.0 / DT_CTRL):
+ self.repeated_override_count = min(self.repeated_override_count + 1, 3)
+ self.full_recovery_frames = 0
+ self.recovering_from_override = True
+
+ torque_threshold = max(self.params.STEER_THRESHOLD, 1.0)
+ # Filter signed torque so alternating sensor noise cancels out before its
+ # magnitude is used for pre-override prediction.
+ driver_torque = float(CS.out.steeringTorque)
+ driver_torque_abs = abs(driver_torque)
+ if not CC.latActive:
+ self.driver_torque_filtered = driver_torque
+ self.driver_torque_filtered_prev = driver_torque
+ self.pre_override_frames = 0
+ else:
+ torque_filter_alpha = DT_CTRL / (DRIVER_TORQUE_FILTER_TAU + DT_CTRL)
+ self.driver_torque_filtered_prev = self.driver_torque_filtered
+ self.driver_torque_filtered += torque_filter_alpha * (driver_torque - self.driver_torque_filtered)
+
+ driver_torque_filtered_abs = abs(self.driver_torque_filtered)
+ driver_torque_filtered_prev_abs = abs(self.driver_torque_filtered_prev)
+ driver_torque_rate = max(0.0, (driver_torque_filtered_abs - driver_torque_filtered_prev_abs) / DT_CTRL)
+ torque_ratio = driver_torque_filtered_abs / torque_threshold
+ raw_torque_ratio = driver_torque_abs / torque_threshold
+ predicted_torque_ratio = (
+ driver_torque_filtered_abs + driver_torque_rate * PRE_OVERRIDE_PREDICTION_TIME
+ ) / torque_threshold
+ pre_override_candidate = (
+ CC.latActive and
+ not CS.out.steeringPressed and
+ raw_torque_ratio > PRE_OVERRIDE_RAW_MIN_RATIO and
+ torque_ratio > PRE_OVERRIDE_FILTERED_MIN_RATIO and
+ predicted_torque_ratio > PRE_OVERRIDE_START_RATIO and
+ driver_torque_rate > torque_threshold * PRE_OVERRIDE_MIN_RATE_RATIO
+ )
+ self.pre_override_frames = self.pre_override_frames + 1 if pre_override_candidate else 0
+ pre_override_yield = 0.0
+ if self.pre_override_frames >= PRE_OVERRIDE_CONFIRM_FRAMES:
+ pre_override_yield = float(np.interp(
+ predicted_torque_ratio,
+ [PRE_OVERRIDE_START_RATIO, PRE_OVERRIDE_FULL_RATIO],
+ [0.0, 1.0],
+ ))
+ recovery_allowed = False
+
+ if CS.out.steeringPressed:
+ # Start yielding immediately when driver override is confirmed.
+ self.override_latched = True
+ self.override_release_frames = 0
+ torque_delta = -20.0
+ elif pre_override_yield > 0.0:
+ # Start handing off gently before steeringPressed flips to avoid a sharp torque drop.
+ torque_delta = PRE_OVERRIDE_MAX_TORQUE_DELTA * pre_override_yield
+ elif self.lkas_max_torque >= self.angle_max_torque:
+ # Once fully recovered, hold full authority until the next driver override.
+ torque_delta = 0.0
+ elif self.override_latched:
+ # Hold reduced authority until driver torque stays below 60% for 0.2 seconds.
+ self.override_release_frames = self.override_release_frames + 1 if torque_ratio < 0.6 else 0
+ if self.override_release_frames >= int(0.2 / DT_CTRL):
+ self.override_latched = False
+ self.override_release_frames = 0
+ recovery_allowed = True
+ else:
+ torque_delta = 0.0
+ else:
+ recovery_allowed = True
+
+ if recovery_allowed:
+ # Use one-second model uncertainty to set the base torque recovery time.
+ # Missing or invalid model data falls back to a moderate 1.5-second recovery.
+ y_std_1s = 0.2
+ if CS.modelV2 is not None and len(CS.modelV2.position.yStd) > 10:
+ model_y_std_1s = float(CS.modelV2.position.yStd[10])
+ if np.isfinite(model_y_std_1s) and model_y_std_1s >= 0.0:
+ y_std_1s = model_y_std_1s
+
+ recovery_time = float(np.interp(y_std_1s, [0.1, 0.2, 0.3, 0.4], [0.5, 0.8, 1.5, 3.0]))
+ recovery_time = max(recovery_time, float(np.interp(
+ self.repeated_override_count,
+ [0, 1, 2, 3],
+ [0.1, 1.0, 2.0, 3.0],
+ )))
+ base_rate_up = (self.angle_max_torque - self.params.ANGLE_MIN_TORQUE) * DT_CTRL / recovery_time
+
+ # During recovery, taper the rate to zero. Only steeringPressed can reduce authority.
+ torque_delta = base_rate_up * float(np.interp(torque_ratio, [0.6, 0.8], [1.0, 0.0]))
+ self.lkas_max_torque = float(np.clip(self.lkas_max_torque + torque_delta,
+ self.params.ANGLE_MIN_TORQUE, angle_torque_cap))
+
+ if not CS.out.steeringPressed and self.recovering_from_override and self.lkas_max_torque >= self.angle_max_torque:
+ self.recovering_from_override = False
+ self.full_recovery_frames = 1
+ elif not CS.out.steeringPressed and self.full_recovery_frames > 0:
+ self.full_recovery_frames += 1
+ if self.full_recovery_frames >= int(5.0 / DT_CTRL):
+ self.full_recovery_frames = 0
+ self.repeated_override_count = 0
+
if not CC.latActive:
apply_torque = 0
- if self.apply_torque_last > 0:
- self.apply_torque_last = max(self.apply_torque_last - self.params.STEER_DELTA_DOWN, 0)
- elif self.apply_torque_last < 0:
- self.apply_torque_last = min(self.apply_torque_last + self.params.STEER_DELTA_DOWN, 0)
- else:
- self.apply_torque_last = apply_torque
+ self.lkas_max_torque = 0
+ self.recovering_from_override = False
+ self.full_recovery_frames = 0
+ self.repeated_override_count = 0
+ self.override_latched = False
+ self.override_release_frames = 0
+ self.driver_torque_filtered = 0.0
+ self.driver_torque_filtered_prev = 0.0
+ self.pre_override_frames = 0
- if apply_torque == 0 and CC.latActive and CS.out.steeringPressed:
- apply_steer_req = False
+ self.steering_pressed_prev = CS.out.steeringPressed if CC.latActive else False
+
+ self.apply_angle_last = apply_angle
# 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
+ self.apply_torque_last = apply_torque
+
# accel + longitudinal
accel = float(np.clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX))
stopping = actuators.longControlState == LongCtrlState.stopping
set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH)
+ # HUD messages
+ sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
+ hud_control)
+
+ active_speed_decel = hud_control.activeCarrot == 3 and self.activeCarrot != 3 # 3: Speed Decel
+ self.activeCarrot = hud_control.activeCarrot
+ if active_speed_decel and self.speedCameraHapticEndFrame < 0: # 과속카메라 감속시작
+ self.speedCameraHapticEndFrame = self.frame + (8.0 / DT_CTRL) #8초간 켜줌.
+ elif not active_speed_decel:
+ self.speedCameraHapticEndFrame = -1
+
+ if 0 <= self.speedCameraHapticEndFrame - self.frame < int(8.0 / DT_CTRL) and self.hapticFeedbackWhenSpeedCamera > 0:
+ t = (self.frame - (self.speedCameraHapticEndFrame - int(8.0 / DT_CTRL))) * DT_CTRL
+
+ for start, end in vibrate_intervals:
+ if start <= t < end:
+ left_lane_warning = right_lane_warning = self.hapticFeedbackWhenSpeedCamera
+ break
+
+ if self.frame >= self.speedCameraHapticEndFrame:
+ self.speedCameraHapticEndFrame = -1
+
+ if self.frame % self.blinking_frame == 0:
+ self.blinking_signal = True
+ elif self.frame % self.blinking_frame == self.blinking_frame / 2:
+ self.blinking_signal = False
+
+
+
can_sends = []
# *** common hyundai stuff ***
# tester present - w/ no response (keeps relevant ECU disabled)
- if self.frame % 100 == 0 and not ((self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC) or self.ESCC.enabled) and \
- self.CP.openpilotLongitudinalControl:
+ if self.frame % 100 == 0 and not (self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC) and self.CP.openpilotLongitudinalControl:
# for longitudinal control, either radar or ADAS driving ECU
addr, bus = 0x7d0, self.CAN.ECAN if self.CP.flags & HyundaiFlags.CANFD else 0
- if self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING.value:
+ if self.CP.flags & HyundaiFlags.CANFD_HDA2.value:
addr, bus = 0x730, self.CAN.ECAN
can_sends.append(make_tester_present_msg(addr, bus, suppress_response=True))
@@ -121,40 +448,135 @@ class CarController(CarControllerBase, EsccCarController, LeadDataCarController,
if self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
can_sends.append(make_tester_present_msg(0x7b1, self.CAN.ECAN, suppress_response=True))
- # *** CAN/CAN FD specific ***
+ camera_scc = self.CP.flags & HyundaiFlags.CAMERA_SCC
+ # CAN-FD platforms
if self.CP.flags & HyundaiFlags.CANFD:
- can_sends.extend(self.create_canfd_msgs(apply_steer_req, apply_torque, set_speed_in_units, accel,
- stopping, hud_control, CS, CC))
+ hda2 = self.CP.flags & HyundaiFlags.CANFD_HDA2
+ hda2_long = hda2 and self.CP.openpilotLongitudinalControl
+ # steering control
+ if camera_scc:
+ can_sends.extend(hyundaicanfd.create_steering_messages_camera_scc(self.frame, self.packer, self.CP, self.CAN, CC, apply_steer_req, apply_torque, CS, apply_angle, self.lkas_max_torque, angle_control))
+ else:
+ can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_torque, apply_angle, self.lkas_max_torque, angle_control))
+
+ # prevent LFA from activating on HDA2 by sending "no lane lines detected" to ADAS ECU
+ if self.frame % 5 == 0 and hda2 and not camera_scc:
+ can_sends.extend(hyundaicanfd.create_suppress_lfa(self.packer, self.CAN, CS))
+
+ # LFA and HDA icons
+ if self.frame % 5 == 0 and (not hda2 or hda2_long or camera_scc):
+ can_sends.extend(hyundaicanfd.create_lfahda_cluster(self.packer, CS, self.CAN, CC.longActive, CC.latActive))
+ if not camera_scc:
+ can_sends.extend(hyundaicanfd.create_lfa_icon_non_camera_scc(self.packer, CS, self.CAN, CC))
+
+ # blinkers
+ if hda2 and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
+ can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.CAN, self.frame, CC.leftBlinker, CC.rightBlinker))
+
+ if self.camera_scc_params in [2, 3]:
+ self.canfd_toggle_adas(CC, CS)
+ if self.CP.openpilotLongitudinalControl:
+ self.hyundai_jerk.make_jerk(self.CP, CS, accel, actuators, hud_control)
+ self.hyundai_jerk.check_carrot_cruise(CC, CS, hud_control, stopping, accel, actuators.aTarget)
+
+ if True: #not camera_scc:
+ can_sends.extend(hyundaicanfd.create_ccnc_messages(self.CP, self.packer, self.CAN, self.frame, CC, CS, hud_control, apply_angle, left_lane_warning, right_lane_warning, self.enable_corner_radar, stopping, self.canfd_debug))
+ if hda2:
+ can_sends.extend(hyundaicanfd.create_adrv_messages(self.CP, self.packer, self.CAN, self.frame))
+ else:
+ can_sends.extend(hyundaicanfd.create_fca_warning_light(self.CP, self.packer, self.CAN, self.frame))
+ if self.frame % 2 == 0:
+ if self.CP.flags & HyundaiFlags.CAMERA_SCC.value:
+ msg = hyundaicanfd.create_acc_control_scc2(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
+ set_speed_in_units, hud_control, self.hyundai_jerk, CS)
+ if msg is not None:
+ can_sends.append(msg)
+ can_sends.extend(hyundaicanfd.create_tcs_messages(self.packer, self.CAN, CS)) # for sorento SCC radar...
+ else:
+ can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
+ set_speed_in_units, hud_control, self.hyundai_jerk.jerk_u, self.hyundai_jerk.jerk_l, CS))
+ self.accel_last = accel
+ else:
+ # button presses
+ if self.camera_scc_params == 3: # camera scc but stock long
+ send_button = self.make_spam_button(CC, CS)
+ can_sends.extend(hyundaicanfd.forward_button_message(self.packer, self.CAN, self.frame, CS, send_button, self.MainMode_ACC_trigger, self.LFA_trigger))
+ else:
+ can_sends.extend(self.create_button_messages(CC, CS, use_clu11=False))
else:
- can_sends.extend(self.create_can_msgs(apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel,
- stopping, hud_control, actuators, CS, CC))
+ if CS.lkas11 is not None:
+ if self.lkas11_active:
+ can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.CP, apply_torque, apply_steer_req,
+ torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
+ hud_control.leftLaneVisible, hud_control.rightLaneVisible,
+ left_lane_warning, right_lane_warning, self.is_ldws_car))
+ self.lkas11_active = True
+
+ if not self.CP.openpilotLongitudinalControl:
+ can_sends.extend(self.create_button_messages(CC, CS, use_clu11=True))
+ if self.CP.carFingerprint in CAN_GEARS["send_mdps12"] and CS.mdps12 is not None: # send mdps12 to LKAS to prevent LKAS error
+ can_sends.append(hyundaican.create_mdps12(self.packer, self.frame, CS.mdps12))
+
+ casper_ev = self.CP.carFingerprint == CAR.HYUNDAI_CASPER_EV
+ if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl:
+ self.hyundai_jerk.make_jerk(self.CP, CS, accel, actuators, hud_control)
+ self.hyundai_jerk.check_carrot_cruise(CC, CS, hud_control, stopping, accel, actuators.aTarget)
+ #jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
+ use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
+ if camera_scc:
+
+ can_sends.extend(hyundaican.create_acc_commands_scc(self.packer, CC.enabled, accel, self.hyundai_jerk, int(self.frame / 2),
+ hud_control, set_speed_in_units, stopping,
+ CC.cruiseControl.override, casper_ev, CS, self.soft_hold_mode))
+ else:
+ can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, self.hyundai_jerk, int(self.frame / 2),
+ hud_control, set_speed_in_units, stopping,
+ CC.cruiseControl.override, use_fca, self.CP, CS, self.soft_hold_mode))
+
+
+ # 20 Hz LFA MFA message
+ if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
+ can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC, self.blinking_signal))
+
+ # 5 Hz ACC options
+ if self.frame % 20 == 0 and self.CP.openpilotLongitudinalControl:
+ if camera_scc:
+ if CS.scc13 is not None:
+ if casper_ev:
+ #can_sends.append(hyundaican.create_acc_opt_copy(CS, self.packer))
+ pass
+ pass
+ else:
+ can_sends.extend(hyundaican.create_acc_opt(self.packer, self.CP))
+
+ # 2 Hz front radar options
+ if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl and not camera_scc:
+ can_sends.append(hyundaican.create_frt_radar_opt(self.packer))
new_actuators = actuators.as_builder()
new_actuators.torque = apply_torque / self.params.STEER_MAX
- new_actuators.torqueOutputCan = apply_torque
- new_actuators.accel = self.tuning.actual_accel
+ # torqueOutputCan reflects the steering authority value actually sent over CAN.
+ # Torque-control platforms send the signed torque command, while angle-control
+ # platforms send LKAS_ANGLE_MAX_TORQUE alongside the requested angle.
+ new_actuators.torqueOutputCan = self.lkas_max_torque if angle_control else apply_torque
+ new_actuators.steeringAngleDeg = float(apply_angle)
+ new_actuators.accel = accel
self.frame += 1
return new_actuators, can_sends
- def create_can_msgs(self, apply_steer_req, apply_torque, torque_fault, set_speed_in_units, accel, stopping, hud_control, actuators, CS, CC):
+
+ def create_button_messages(self, CC: structs.CarControl, CS: CarState, use_clu11: bool):
can_sends = []
+ if CS.out.brakePressed or CS.out.brakeHoldActive:
+ return can_sends
+ if use_clu11:
+ if CS.clu11 is None:
+ return can_sends
- # HUD messages
- sys_warning, sys_state, left_lane_warning, right_lane_warning = process_hud_alert(CC.enabled, self.car_fingerprint,
- hud_control)
-
- can_sends.append(hyundaican.create_lkas11(self.packer, self.frame, self.CP, apply_torque, apply_steer_req,
- torque_fault, CS.lkas11, sys_warning, sys_state, CC.enabled,
- hud_control.leftLaneVisible, hud_control.rightLaneVisible,
- left_lane_warning, right_lane_warning,
- self.lkas_icon))
-
- # Button messages
- if not self.CP.openpilotLongitudinalControl:
if CC.cruiseControl.cancel:
can_sends.append(hyundaican.create_clu11(self.packer, self.frame, CS.clu11, Buttons.CANCEL, self.CP))
- elif CC.cruiseControl.resume:
+ elif False: #CC.cruiseControl.resume:
# send resume at a max freq of 10Hz
if (self.frame - self.last_button_frame) * DT_CTRL > 0.1:
# send 25 messages at a time to increases the likelihood of resume being accepted
@@ -162,81 +584,205 @@ class CarController(CarControllerBase, EsccCarController, LeadDataCarController,
if (self.frame - self.last_button_frame) * DT_CTRL >= 0.15:
self.last_button_frame = self.frame
- if self.frame % 2 == 0 and self.CP.openpilotLongitudinalControl:
- # TODO: unclear if this is needed
- jerk = 3.0 if actuators.longControlState == LongCtrlState.pid else 1.0
- use_fca = self.CP.flags & HyundaiFlags.USE_FCA.value
- can_sends.extend(hyundaican.create_acc_commands(self.packer, CC.enabled, accel, jerk, int(self.frame / 2),
- self.lead_data, hud_control, set_speed_in_units, stopping,
- CC.cruiseControl.override, use_fca, self.CP,
- CS.main_cruise_enabled, self.tuning, self.ESCC))
+ if self.last_button_frame != self.frame:
+ send_button = self.make_spam_button(CC, CS)
+ if send_button > 0:
+ can_sends.append(hyundaican.create_clu11_button(self.packer, self.frame, CS.clu11, send_button, self.CP))
- # 20 Hz LFA MFA message
- if self.frame % 5 == 0 and self.CP.flags & HyundaiFlags.SEND_LFA.value:
- can_sends.append(hyundaican.create_lfahda_mfc(self.packer, CC.enabled, self.lfa_icon))
-
- # 5 Hz ACC options
- if self.frame % 20 == 0 and self.CP.openpilotLongitudinalControl:
- can_sends.extend(hyundaican.create_acc_opt(self.packer, self.CP, self.ESCC))
-
- # 2 Hz front radar options
- if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl and not self.ESCC.enabled:
- can_sends.append(hyundaican.create_frt_radar_opt(self.packer))
-
- return can_sends
-
- def create_canfd_msgs(self, apply_steer_req, apply_torque, set_speed_in_units, accel, stopping, hud_control, CS, CC):
- can_sends = []
-
- lka_steering = self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING
- lka_steering_long = lka_steering and self.CP.openpilotLongitudinalControl
-
- # steering control
- can_sends.extend(hyundaicanfd.create_steering_messages(self.packer, self.CP, self.CAN, CC.enabled, apply_steer_req, apply_torque, self.lkas_icon))
-
- # prevent LFA from activating on LKA steering cars by sending "no lane lines detected" to ADAS ECU
- if self.frame % 5 == 0 and lka_steering:
- can_sends.append(hyundaicanfd.create_suppress_lfa(self.packer, self.CAN, CS.lfa_block_msg,
- self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT))
-
- # LFA and HDA icons
- if self.frame % 5 == 0 and (not lka_steering or lka_steering_long):
- can_sends.append(hyundaicanfd.create_lfahda_cluster(self.packer, self.CAN, CC.enabled, self.lfa_icon))
-
- # blinkers
- if lka_steering and self.CP.flags & HyundaiFlags.ENABLE_BLINKERS:
- can_sends.extend(hyundaicanfd.create_spas_messages(self.packer, self.CAN, CC.leftBlinker, CC.rightBlinker))
-
- if self.CP.openpilotLongitudinalControl:
- if lka_steering:
- can_sends.extend(hyundaicanfd.create_adrv_messages(self.packer, self.CAN, self.frame))
- else:
- can_sends.extend(hyundaicanfd.create_fca_warning_light(self.packer, self.CAN, self.frame))
- if self.frame % 2 == 0:
- can_sends.append(hyundaicanfd.create_acc_control(self.packer, self.CAN, CC.enabled, self.accel_last, accel, stopping, CC.cruiseControl.override,
- set_speed_in_units, hud_control, self.lead_data, CS.main_cruise_enabled, self.tuning))
- self.accel_last = accel
else:
- # button presses
+
+ # carrot.. 왜 alt_cruise_button는 값이 리스트일까?, 그리고 왜? 빈데이터가 들어오는것일까?
+ if CS.cruise_buttons_msg is not None and self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
+ try:
+ cruise_buttons_msg_values = {key: value[0] for key, value in CS.cruise_buttons_msg.items()}
+ except: # IndexError:
+ #print("IndexError....")
+ cruise_buttons_msg_values = None
+ self.cruise_buttons_msg_cnt += 1
+ if cruise_buttons_msg_values is not None:
+ self.cruise_buttons_msg_values = cruise_buttons_msg_values
+ self.cruise_buttons_msg_cnt = 0
+
if (self.frame - self.last_button_frame) * DT_CTRL > 0.25:
# cruise cancel
if CC.cruiseControl.cancel:
- if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
- can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.cruise_info))
- self.last_button_frame = self.frame
- else:
- for _ in range(20):
- can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter + 1, Buttons.CANCEL))
+ if (self.frame - self.last_button_frame) * DT_CTRL > 0.1:
+ print("cruiseControl.cancel222222")
+ if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
+ #can_sends.append(hyundaicanfd.create_acc_cancel(self.packer, self.CP, self.CAN, CS.scc_control))
+ if self.cruise_buttons_msg_values is not None:
+ can_sends.append(hyundaicanfd.alt_cruise_buttons(self.packer, self.CP, self.CAN, Buttons.CANCEL, self.cruise_buttons_msg_values, self.cruise_buttons_msg_cnt))
+
+ else:
+ for _ in range(20):
+ can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.CANCEL))
self.last_button_frame = self.frame
# cruise standstill resume
- elif CC.cruiseControl.resume:
+ elif False: #CC.cruiseControl.resume:
if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
# TODO: resume for alt button cars
pass
else:
for _ in range(20):
- can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter + 1, Buttons.RES_ACCEL))
+ can_sends.append(hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, Buttons.RES_ACCEL))
self.last_button_frame = self.frame
+ ## button 스패밍을 안했을때...
+ if self.last_button_frame != self.frame:
+ dat = self.canfd_speed_control_pcm(CC, CS, self.cruise_buttons_msg_values)
+ if dat is not None:
+ for _ in range(self.button_spam3):
+ can_sends.append(dat)
+ self.cruise_buttons_msg_cnt += 1
+
return can_sends
+
+ def canfd_toggle_adas(self, CC, CS):
+ trigger_min = -200
+ trigger_start = 6
+ self.MainMode_ACC_trigger = max(trigger_min, self.MainMode_ACC_trigger - 1)
+ self.LFA_trigger = max(trigger_min, self.LFA_trigger - 1)
+ if self.MainMode_ACC_trigger == trigger_min and self.LFA_trigger == trigger_min:
+ if CC.enabled and not CS.MainMode_ACC and CS.out.vEgo > 3.:
+ self.MainMode_ACC_trigger = trigger_start
+ elif CC.latActive and CS.LFA_ICON == 0:
+ self.LFA_trigger = trigger_start
+
+ def canfd_speed_control_pcm(self, CC, CS, cruise_buttons_msg_values):
+
+ alt_buttons = True if self.CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS else False
+
+ if alt_buttons and cruise_buttons_msg_values is None:
+ return None
+
+ send_button = self.make_spam_button(CC, CS)
+ if send_button > 0:
+ if alt_buttons:
+ return hyundaicanfd.alt_cruise_buttons(self.packer, self.CP, self.CAN, send_button, cruise_buttons_msg_values, self.cruise_buttons_msg_cnt)
+ else:
+ return hyundaicanfd.create_buttons(self.packer, self.CP, self.CAN, CS.buttons_counter+1, send_button)
+
+ return None
+
+
+ def make_spam_button(self, CC, CS):
+ hud_control = CC.hudControl
+ set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH)
+ target = int(set_speed_in_units+0.5)
+ current = int(CS.out.cruiseState.speed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH) + 0.5)
+ v_ego_kph = CS.out.vEgo * CV.MS_TO_KPH
+
+ send_button = 0
+ activate_cruise = False
+
+ if CC.enabled:
+ if not CS.out.cruiseState.enabled:
+ if (hud_control.leadVisible or v_ego_kph > 10.0) and self.activateCruise == 0:
+ send_button = Buttons.RES_ACCEL
+ self.activateCruise = 1
+ activate_cruise = True
+ elif CC.cruiseControl.resume:
+ send_button = Buttons.RES_ACCEL
+ elif target < current and current>= 31 and self.speed_from_pcm != 1:
+ send_button = Buttons.SET_DECEL
+ elif target > current and current < 160 and self.speed_from_pcm != 1:
+ send_button = Buttons.RES_ACCEL
+ elif CS.out.activateCruise: #CC.cruiseControl.activate:
+ if (hud_control.leadVisible or v_ego_kph > 10.0) and self.activateCruise == 0:
+ self.activateCruise = 1
+ send_button = Buttons.RES_ACCEL
+ activate_cruise = True
+
+ if CS.out.brakePressed or CS.out.gasPressed:
+ self.activateCruise = 0
+
+ if send_button == 0:
+ self.button_spamming_count = 0
+ self.prev_clu_speed = current
+ return 0
+
+ speed_diff = self.prev_clu_speed - current
+ spamming_max = self.button_spam1
+ if CS.cruise_buttons[-1] != Buttons.NONE:
+ self.last_button_frame = self.frame
+ self.button_wait = self.button_spam2
+ self.button_spamming_count = 0
+ elif abs(self.button_spamming_count) >= spamming_max or abs(speed_diff) > 0:
+ self.last_button_frame = self.frame
+ self.button_wait = self.button_spam2 if abs(self.button_spamming_count) >= spamming_max else 7
+ self.button_spamming_count = 0
+
+ self.prev_clu_speed = current
+ send_button_allowed = (self.frame - self.last_button_frame) > self.button_wait
+ #CC.debugTextCC = "{} speed_diff={:.1f},{:.0f}/{:.0f}, button={}, button_wait={}, count={}".format(
+ # send_button_allowed, speed_diff, target, current, send_button, self.button_wait, self.button_spamming_count)
+
+ if send_button_allowed or activate_cruise or (CC.cruiseControl.resume and self.frame % 2 == 0):
+ self.button_spamming_count = self.button_spamming_count + 1 if send_button == Buttons.RES_ACCEL else self.button_spamming_count - 1
+ return send_button
+ else:
+ self.button_spamming_count = 0
+ return 0
+
+from openpilot.common.filter_simple import MyMovingAverage
+class HyundaiJerk:
+ def __init__(self):
+ self.params = Params()
+ self.jerk = 0.0
+ self.jerk_u = self.jerk_l = 0.0
+ self.cb_upper = self.cb_lower = 0.0
+ self.jerk_u_min = 0.5
+ self.carrot_cruise = 1
+ self.carrot_cruise_accel = 0.0
+
+ def check_carrot_cruise(self, CC, CS, hud_control, stopping, accel, a_target):
+ carrot_cruise_decel = self.params.get_float("CarrotCruiseDecel")
+ carrot_cruise_atc_decel = self.params.get_float("CarrotCruiseAtcDecel")
+ if carrot_cruise_atc_decel >= 0 and 0 < hud_control.atcDistance < 500:
+ carrot_cruise_decel = max(carrot_cruise_decel, carrot_cruise_atc_decel)
+ self.carrot_cruise = 0
+ if CS.out.carrotCruise > 0 and not CC.cruiseControl.override:
+ if CS.softHoldActive == 0 and not stopping:
+ if CS.out.vEgo > 10/3.6:
+ if carrot_cruise_decel < 0:
+ if (a_target > -0.1 or accel > -0.1):
+ self.carrot_cruise = 1
+ self.carrot_cruise_accel = 0.0
+ else:
+ self.carrot_cruise = 2
+ carrot_cruise = min(accel, -carrot_cruise_decel * 0.01)
+ self.carrot_cruise_accel = max(carrot_cruise, self.carrot_cruise_accel - 1.0 * DT_CTRL) # 점진적으로 줄임.
+ if self.carrot_cruise == 0:
+ self.carrot_cruise_accel = CS.out.aEgo
+
+ def make_jerk(self, CP, CS, accel, actuators, hud_control):
+ if actuators.longControlState == LongCtrlState.stopping:
+ self.jerk = self.jerk_u_min / 2 - CS.out.aEgo
+ else:
+ jerk = actuators.jerk if actuators.longControlState == LongCtrlState.pid else 0.0
+ #a_error = actuators.aTarget - CS.out.aEgo
+ self.jerk = jerk# + a_error
+
+ jerk_max_l = 5.0
+ jerk_max_u = jerk_max_l
+ if actuators.longControlState == LongCtrlState.off:
+ self.jerk_u = jerk_max_u
+ self.jerk_l = jerk_max_l
+ self.cb_upper = self.cb_lower = 0.0
+ else:
+ if CP.flags & HyundaiFlags.CANFD:
+ # Keep deceleration authority after the MPC jerk settles to zero. Stock SCC raises the
+ # lower jerk limit with the raw acceleration request instead of relying on jerk alone.
+ jerk_l_base = 1.2
+ jerk_l_raw = np.clip(jerk_l_base + 2.0 * max(0.0, -accel - 2.8), jerk_l_base, jerk_max_l)
+ jerk_l_mpc = np.clip(-self.jerk * 4.0, jerk_l_base, jerk_max_l)
+
+ self.jerk_u = min(max(self.jerk_u_min, self.jerk * 2.0), jerk_max_u)
+ self.jerk_l = max(jerk_l_raw, jerk_l_mpc)
+ self.cb_upper = self.cb_lower = 0.0
+ else:
+ self.jerk_u = min(max(self.jerk_u_min, self.jerk * 2.0), jerk_max_u)
+ self.jerk_l = min(max(1.0, -self.jerk * 4.0), jerk_max_l)
+ self.cb_upper = np.clip(0.9 + accel * 0.2, 0, 1.2)
+ self.cb_lower = np.clip(0.8 + accel * 0.2, 0, 1.2)
diff --git a/iqdbc_repo/iqdbc/car/hyundai/carstate.py b/iqdbc_repo/iqdbc/car/hyundai/carstate.py
index 8321577..48eb597 100644
--- a/iqdbc_repo/iqdbc/car/hyundai/carstate.py
+++ b/iqdbc_repo/iqdbc/car/hyundai/carstate.py
@@ -1,47 +1,83 @@
from collections import deque
import copy
import math
+import numpy as np
+import ast
from iqdbc.can import CANDefine, CANParser
-from iqdbc.car import Bus, create_button_events, structs
+from iqdbc.car import Bus, create_button_events, structs, DT_CTRL
from iqdbc.car.common.conversions import Conversions as CV
from iqdbc.car.hyundai.hyundaicanfd import CanBus
-from iqdbc.car.hyundai.values import HyundaiFlags, CAR, DBC, Buttons, CarControllerParams
+from iqdbc.car.hyundai.values import HyundaiFlags, CAR, DBC, Buttons, CarControllerParams, CAMERA_SCC_CAR, HyundaiExtFlags, \
+ EV_MODE_ACTIVE_VALUES, EV_MODE_STATUS_ADDR, EV_MODE_STATUS_DLC, EV_MODE_STATUS_MSG, \
+ EV_MODE_STATUS_SIGNAL
from iqdbc.car.interfaces import CarStateBase
-from iqdbc.lvbs.car.hyundai.carstate_ext import CarStateExt
-from iqdbc.lvbs.car.hyundai.escc import EsccCarStateBase
-from iqdbc.lvbs.car.hyundai.aol import AolCarState
-from iqdbc.lvbs.car.hyundai.values import HyundaiFlagsIQ
+from openpilot.common.params import Params
+
+from datetime import datetime
+from zoneinfo import ZoneInfo
+
ButtonType = structs.CarState.ButtonEvent.Type
PREV_BUTTON_SAMPLES = 8
CLUSTER_SAMPLE_RATE = 20 # frames
-STANDSTILL_THRESHOLD = 12 * 0.03125
+STANDSTILL_THRESHOLD = 12 * 0.03125 * CV.KPH_TO_MS
-# Cancel button can sometimes be ACC pause/resume button, main button can also enable on some cars
-ENABLE_BUTTONS = (Buttons.RES_ACCEL, Buttons.SET_DECEL, Buttons.CANCEL)
BUTTONS_DICT = {Buttons.RES_ACCEL: ButtonType.accelCruise, Buttons.SET_DECEL: ButtonType.decelCruise,
- Buttons.GAP_DIST: ButtonType.gapAdjustCruise, Buttons.CANCEL: ButtonType.cancel}
+ Buttons.GAP_DIST: ButtonType.gapAdjustCruise, Buttons.CANCEL: ButtonType.cancel, Buttons.LFA_BUTTON: ButtonType.lfaButton}
+
+GearShifter = structs.CarState.GearShifter
+
+READY_COUNT_OK = 200
+TRAILER_DISCONNECT_GRACE_FRAMES = int(5.0 / DT_CTRL)
+EV_MODE_STATUS_TIMEOUT_NS = 500_000_000
-class CarState(CarStateBase, EsccCarStateBase, AolCarState, CarStateExt):
- def __init__(self, CP, CP_IQ):
- CarStateBase.__init__(self, CP, CP_IQ)
- EsccCarStateBase.__init__(self)
- AolCarState.__init__(self, CP, CP_IQ)
- CarStateExt.__init__(self, CP, CP_IQ)
+def _get_ev_mode_state(cp: CANParser) -> tuple[bool, bool]:
+ timestamps = cp.ts_nanos.get(EV_MODE_STATUS_MSG)
+ if timestamps is None:
+ return False, False
+
+ timestamp = timestamps.get(EV_MODE_STATUS_SIGNAL, 0)
+ dat = cp.dat.get(EV_MODE_STATUS_ADDR, b"")
+ # The update timestamp advances even when the whole ECAN bus is silent.
+ # last_nonempty_nanos would leave the final decoded state valid forever.
+ age = cp._last_update_nanos - timestamp
+ valid = timestamp > 0 and len(dat) == EV_MODE_STATUS_DLC and not cp.bus_timeout and 0 <= age <= EV_MODE_STATUS_TIMEOUT_NS
+ active = valid and int(cp.vl[EV_MODE_STATUS_MSG][EV_MODE_STATUS_SIGNAL]) in EV_MODE_ACTIVE_VALUES
+ return active, valid
+
+
+NUMERIC_TO_TZ = {
+ 840: "America/New_York", # 미국 (US) → 동부 시간대
+ 124: "America/Toronto", # 캐나다 (CA) → 동부 시간대
+ 250: "Europe/Paris", # 프랑스 (FR)
+ 276: "Europe/Berlin", # 독일 (DE)
+ 826: "Europe/London", # 영국 (GB)
+ 392: "Asia/Tokyo", # 일본 (JP)
+ 156: "Asia/Shanghai", # 중국 (CN)
+ 410: "Asia/Seoul", # 한국 (KR)
+ 36: "Australia/Sydney", # 호주 (AU)
+ 356: "Asia/Kolkata", # 인도 (IN)
+}
+
+class CarState(CarStateBase):
+ def __init__(self, CP, CP_IQ=None):
+ super().__init__(CP, CP_IQ or structs.IQCarParams())
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
self.cruise_buttons: deque = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
self.main_buttons: deque = deque([Buttons.NONE] * PREV_BUTTON_SAMPLES, maxlen=PREV_BUTTON_SAMPLES)
- self.lda_button = 0
- self.gear_msg_canfd = "ACCELERATOR" if CP.flags & HyundaiFlags.EV else \
+ self.gear_msg_canfd = "GEAR" if CP.extFlags & HyundaiExtFlags.CANFD_GEARS_69 else \
+ "ACCELERATOR" if CP.flags & HyundaiFlags.EV else \
"GEAR_ALT" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS else \
"GEAR_ALT_2" if CP.flags & HyundaiFlags.CANFD_ALT_GEARS_2 else \
"GEAR_SHIFTER"
+
+ self.use_accelerator = self.gear_msg_canfd == "ACCELERATOR"
if CP.flags & HyundaiFlags.CANFD:
self.shifter_values = can_define.dv[self.gear_msg_canfd]["GEAR"]
elif CP.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV):
@@ -63,31 +99,210 @@ class CarState(CarStateBase, EsccCarStateBase, AolCarState, CarStateExt):
self.is_metric = False
self.buttons_counter = 0
- self.cruise_info = {}
+ # for generic CAN parsing
+ self.fca11 = None
+ self.scc11 = None
+ self.scc12 = None
+ self.scc13 = None
+ self.scc14 = None
+ self.lkas11 = None
+ self.clu11 = None
+
+ # for CANFD parsing
+ self.scc_control = None
+ self.lfa = None
+ self.lfa_alt = None
+ self.lfahda_cluster = None
+ self.adrv_0x161 = None
+ self.adrv_0x200 = None
+ self.adrv_0x1ea = None
+ self.adrv_0x160 = None
+ self.ccnc_0x162 = None
+ self.hda_info_4a3 = None
+ self.tcs = None
+ self.mdps = None
+ self.steer_touch_2af = None
+ self.cruise_buttons_msg = None
+ self.cam_0x362 = None
+ self.cam_0x2a4 = None
+ self.manual_speed_limit_assist = None
+ self.accelerator = None
+ self.blinkers = None
+ self.blinkers_alt = None
+ self.doors_seatbelts = None
+ self.cruise_buttons_alt2 = None
# On some cars, CLU15->CF_Clu_VehicleSpeed can oscillate faster than the dash updates. Sample at 5 Hz
self.cluster_speed = 0
self.cluster_speed_counter = CLUSTER_SAMPLE_RATE
self.params = CarControllerParams(CP)
+ self.op_params = Params()
+
+ self.main_enabled = True if self.op_params.get_int("AutoEngage") == 2 else False
+ self.gear_shifter = GearShifter.drive # Gear_init for Nexo ?? unknown 21.02.23.LSW
+
+ self.totalDistance = 0.0
+ self.speedLimitDistance = 0
+ self.pcmCruiseGap = 0
+
+ self.cruise_buttons_alt = True if self.CP.carFingerprint in (CAR.HYUNDAI_CASPER, CAR.HYUNDAI_CASPER_EV) else False
+ self.MainMode_ACC = False
+ self.ACCMode = 0
+ self.LFA_ICON = 0
+ self.paddle_button_prev = 0
+
+ self.lf_distance = 0
+ self.rf_distance = 0
+ self.lr_distance = 0
+ self.rr_distance = 0
+ #self.lf_lateral = 0
+ #self.rf_lateral = 0
+
+ fingerprints_str = Params().get("FingerPrints")
+ try:
+ fingerprints = ast.literal_eval(fingerprints_str) if fingerprints_str else {i: {} for i in range(8)}
+ except (SyntaxError, ValueError):
+ fingerprints = {i: {} for i in range(8)}
+ #print("fingerprints =", fingerprints)
+ ecu_disabled = False
+ if self.CP.openpilotLongitudinalControl and not (self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC):
+ ecu_disabled = True
+
+
+ self.HAS_LFA_BUTTON = True if 913 in fingerprints[0] else False
+ self.CRUISE_BUTTON_ALT = True if 1007 in fingerprints[0] else False
+
+ cam_bus = CanBus(CP).CAM
+ pt_bus = CanBus(CP).ECAN
+ alt_bus = CanBus(CP).ACAN
+ self.GEAR = True if 69 in fingerprints[pt_bus] else False
+ self.GEAR_ALT = True if 64 in fingerprints[pt_bus] else False
+ self.TPMS = True if 0x3a0 in fingerprints[pt_bus] else False
+ self.LOCAL_TIME = True if 1264 in fingerprints[pt_bus] else False
+
+ self.cp_bsm = None
+ self.time_zone = "UTC"
+
+ self.cp = None
+ self.cp_cam = None
+ self.cp_alt = None
+ self.controls_ready_count = 0
+
+ # trailer detection
+ self.trailer_connected = False
+ self.trailer_timeout_cnt = 0
+ self.trailer_connected_prev = False
+ self.trailer_status = None
+
+ def monitor_fingerprint(self, can_parsers, canfd):
+ if self.controls_ready_count <= READY_COUNT_OK:
+ if Params().get_bool("ControlsReady"):
+ self.controls_ready_count += 1
+
+ self.cp = can_parsers[Bus.pt]
+ self.cp_cam = can_parsers[Bus.cam]
+ self.cp_alt = can_parsers[Bus.alt] if Bus.alt in can_parsers else None
+
+ def add_if_seen(parser, name, ignore_counter = False):
+ msg = parser.dbc.name_to_msg.get(name)
+ if not msg:
+ print(f"{name} not in DBC")
+ return
+ if msg.address not in parser.seen_addresses:
+ return
+ if msg.address in parser.addresses:
+ return
+ parser._add_message(name, ignore_counter = ignore_counter) # ← 이름으로 등록
+
+ def add_and_cache(parser, name: str, attr: str, ignore_counter: bool = False):
+ add_if_seen(parser, name, ignore_counter)
+ if name in parser.vl: # 등록 성공했을 때만
+ setattr(self, attr, parser.vl[name])
+ return True
+ return False
+
+ if self.controls_ready_count == 50:
+ self.cp.controls_ready = self.cp_cam.controls_ready = True
+ if self.cp_alt is not None:
+ self.cp_alt.controls_ready = True
+ elif self.controls_ready_count == 100:
+ self.cp.enable_capture = self.cp_cam.enable_capture = False
+ if self.cp_alt is not None:
+ self.cp_alt.enable_capture = False
+ elif self.controls_ready_count == 101:
+ print("cp_cam.seen_addresses =", self.cp_cam.seen_addresses)
+ elif self.controls_ready_count == 102:
+ print("cp.seen_addresses =", self.cp.seen_addresses)
+ elif self.controls_ready_count == 103:
+ if self.cp_alt is not None:
+ print("cp_alt.seen_addresses =", self.cp_alt.seen_addresses)
+ else:
+ print("cp_alt.seen_addresses = None")
+ if not canfd:
+ if self.controls_ready_count == 104:
+ if not add_and_cache(self.cp_cam, "FCA11", "fca11"):
+ add_and_cache(self.cp, "FCA11", "fca11")
+ add_and_cache(self.cp_cam, "LKAS11", "lkas11")
+ add_and_cache(self.cp, "CLU11", "clu11")
+ elif self.controls_ready_count == 105:
+ cp_cruise = self.cp_cam if self.CP.flags & HyundaiFlags.CAMERA_SCC else self.cp
+ scc_messages_expected = not self.CP.openpilotLongitudinalControl or self.CP.flags & HyundaiFlags.CAMERA_SCC
+ if scc_messages_expected:
+ add_and_cache(cp_cruise, "SCC11", "scc11")
+ add_and_cache(cp_cruise, "SCC12", "scc12")
+ add_and_cache(cp_cruise, "SCC13", "scc13")
+ add_and_cache(cp_cruise, "SCC14", "scc14")
+ else: # canfd
+ if self.controls_ready_count == 120:
+ cp_cruise = self.cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else self.cp
+ add_and_cache(cp_cruise, "SCC_CONTROL", "scc_control")
+ elif self.controls_ready_count == 121:
+ add_and_cache(self.cp, "TCS", "tcs")
+ add_and_cache(self.cp, "MDPS", "mdps")
+ add_and_cache(self.cp_cam, "LFA", "lfa")
+ add_and_cache(self.cp_cam, "LFA_ALT", "lfa_alt")
+ add_and_cache(self.cp_cam, "LFAHDA_CLUSTER", "lfahda_cluster")
+ elif self.controls_ready_count == 122:
+ add_and_cache(self.cp_cam, "ADRV_0x161", "adrv_0x161")
+ add_and_cache(self.cp_cam, "ADRV_0x200", "adrv_0x200")
+ add_and_cache(self.cp_cam, "ADRV_0x1ea", "adrv_0x1ea")
+ add_and_cache(self.cp_cam, "ADRV_0x160", "adrv_0x160")
+ add_and_cache(self.cp_cam, "CCNC_0x162", "ccnc_0x162")
+ elif self.controls_ready_count == 123:
+ add_and_cache(self.cp, "HDA_INFO_4A3", "hda_info_4a3")
+ add_and_cache(self.cp, "STEER_TOUCH_2AF", "steer_touch_2af")
+ elif self.controls_ready_count == 124:
+ add_and_cache(self.cp, self.cruise_btns_msg_canfd, "cruise_buttons_msg")
+ if not add_and_cache(self.cp_cam, "CAM_0x362", "cam_0x362") and self.cp_alt is not None:
+ add_and_cache(self.cp_alt, "CAM_0x362", "cam_0x362")
+ if not add_and_cache(self.cp_alt, "CAM_0x2a4", "cam_0x2a4") and self.cp_cam is not None:
+ add_and_cache(self.cp_cam, "CAM_0x2a4", "cam_0x2a4")
+ elif self.controls_ready_count == 125:
+ add_and_cache(self.cp, "MANUAL_SPEED_LIMIT_ASSIST", "manual_speed_limit_assist", ignore_counter = True)
+ if self.gear_msg_canfd == "ACCELERATOR":
+ add_and_cache(self.cp, "ACCELERATOR", "accelerator", ignore_counter = True)
+ add_and_cache(self.cp, "BLINKERS", "blinkers")
+ add_and_cache(self.cp, "BLINKERS_ALT", "blinkers_alt")
+ add_and_cache(self.cp, "DOORS_SEATBELTS", "doors_seatbelts")
+ elif self.controls_ready_count == 126:
+ add_and_cache(self.cp, "CRUISE_BUTTONS_ALT2", "cruise_buttons_alt2", ignore_counter = True)
+ add_and_cache(self.cp, "TRAILER_STATUS", "trailer_status", ignore_counter = True)
+
+
- self.steer_fault_counter = 0
- def recent_button_interaction(self) -> bool:
- # On some newer model years, the CANCEL button acts as a pause/resume button based on the PCM state
- # To avoid re-engaging when openpilot cancels, check user engagement intention via buttons
- # Main button also can trigger an engagement on these cars
- return any(btn in ENABLE_BUTTONS for btn in self.cruise_buttons) or any(self.main_buttons)
def update(self, can_parsers) -> tuple[structs.CarState, structs.IQCarState]:
+ self.monitor_fingerprint(can_parsers, self.CP.flags & HyundaiFlags.CANFD)
cp = can_parsers[Bus.pt]
cp_cam = can_parsers[Bus.cam]
+ cp_alt = can_parsers[Bus.alt] if Bus.alt in can_parsers else None
if self.CP.flags & HyundaiFlags.CANFD:
- return self.update_canfd(can_parsers)
+ return self.update_canfd(can_parsers), self.out_iq
ret = structs.CarState()
- ret_iq = structs.IQCarState()
cp_cruise = cp_cam if self.CP.flags & HyundaiFlags.CAMERA_SCC else cp
self.is_metric = cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"] == 0
speed_conv = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
@@ -97,13 +312,18 @@ class CarState(CarStateBase, EsccCarStateBase, AolCarState, CarStateExt):
ret.seatbeltUnlatched = cp.vl["CGW1"]["CF_Gway_DrvSeatBeltSw"] == 0
- self.parse_wheel_speeds(ret,
+ if cp.ts_nanos["EMS21"]["SCR_UREA_LEVEL"] > 0:
+ ret.ureaGauge = float(np.clip(cp.vl["EMS21"]["SCR_UREA_LEVEL"] / 100.0, 0.0, 1.0))
+
+ ret.wheelSpeeds = self.get_wheel_speeds(
cp.vl["WHL_SPD11"]["WHL_SPD_FL"],
cp.vl["WHL_SPD11"]["WHL_SPD_FR"],
cp.vl["WHL_SPD11"]["WHL_SPD_RL"],
cp.vl["WHL_SPD11"]["WHL_SPD_RR"],
)
- ret.standstill = cp.vl["WHL_SPD11"]["WHL_SPD_FL"] <= STANDSTILL_THRESHOLD and cp.vl["WHL_SPD11"]["WHL_SPD_RR"] <= STANDSTILL_THRESHOLD
+ ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
+ ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
+ ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
self.cluster_speed_counter += 1
if self.cluster_speed_counter > CLUSTER_SAMPLE_RATE:
@@ -116,73 +336,109 @@ class CarState(CarStateBase, EsccCarStateBase, AolCarState, CarStateExt):
if not self.is_metric and self.CP.carFingerprint not in (CAR.KIA_SORENTO,):
self.cluster_speed = math.floor(self.cluster_speed * CV.KPH_TO_MPH + CV.KPH_TO_MPH)
- ret.vEgoCluster = self.cluster_speed * speed_conv
+ #ret.vEgoCluster = self.cluster_speed * speed_conv
ret.steeringAngleDeg = cp.vl["SAS11"]["SAS_Angle"]
ret.steeringRateDeg = cp.vl["SAS11"]["SAS_Speed"]
+ ret.yawRate = cp.vl["ESP12"]["YAW_RATE"]
ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(
50, cp.vl["CGW1"]["CF_Gway_TurnSigLh"], cp.vl["CGW1"]["CF_Gway_TurnSigRh"])
ret.steeringTorque = cp.vl["MDPS12"]["CR_Mdps_StrColTq"]
ret.steeringTorqueEps = cp.vl["MDPS12"]["CR_Mdps_OutTq"]
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
- steer_fault_raw = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
- self.steer_fault_counter = self.steer_fault_counter + 1 if steer_fault_raw else 0
- ret.steerFaultTemporary = self.steer_fault_counter > 5
+ ret.steerFaultTemporary = cp.vl["MDPS12"]["CF_Mdps_ToiUnavail"] != 0 or cp.vl["MDPS12"]["CF_Mdps_ToiFlt"] != 0
# cruise state
if self.CP.openpilotLongitudinalControl:
# These are not used for engage/disengage since openpilot keeps track of state using the buttons
- ret.cruiseState.available = cp.vl["TCS13"]["ACCEnable"] == 0
+ ret.cruiseState.available = self.main_enabled and self.controls_ready_count >= READY_COUNT_OK #cp.vl["TCS13"]["ACCEnable"] == 0
ret.cruiseState.enabled = cp.vl["TCS13"]["ACC_REQ"] == 1
ret.cruiseState.standstill = False
ret.cruiseState.nonAdaptive = False
- elif not self.CP_IQ.flags & HyundaiFlagsIQ.NON_SCC:
- ret.cruiseState.available = cp_cruise.vl["SCC11"]["MainMode_ACC"] == 1
+ elif not self.CP.flags & HyundaiFlags.CC_ONLY_CAR:
+ self.main_enabled = ret.cruiseState.available = cp_cruise.vl["SCC11"]["MainMode_ACC"] == 1
ret.cruiseState.enabled = cp_cruise.vl["SCC12"]["ACCMode"] != 0
ret.cruiseState.standstill = cp_cruise.vl["SCC11"]["SCCInfoDisplay"] == 4.
ret.cruiseState.nonAdaptive = cp_cruise.vl["SCC11"]["SCCInfoDisplay"] == 2. # Shows 'Cruise Control' on dash
ret.cruiseState.speed = cp_cruise.vl["SCC11"]["VSetDis"] * speed_conv
+ ret.pcmCruiseGap = cp_cruise.vl["SCC11"]["TauGapSet"]
+
# TODO: Find brake pressure
ret.brake = 0
- ret.brakePressed = cp.vl["TCS13"]["DriverOverride"] == 2 # 2 includes regen braking by user on HEV/EV
- ret.brakeHoldActive = cp.vl["TCS15"]["AVH_LAMP"] == 2 # 0 OFF, 1 ERROR, 2 ACTIVE, 3 READY
- ret.parkingBrake = cp.vl["TCS13"]["PBRAKE_ACT"] == 1
- ret.espDisabled = cp.vl["TCS11"]["TCS_PAS"] == 1
- ret.espActive = cp.vl["TCS11"]["ABS_ACT"] == 1
- ret.accFaulted = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
+ if not self.CP.flags & HyundaiFlags.CC_ONLY_CAR:
+ ret.brakePressed = cp.vl["TCS13"]["DriverOverride"] == 2 # 2 includes regen braking by user on HEV/EV
+ ret.brakeHoldActive = cp.vl["TCS15"]["AVH_LAMP"] == 2 # 0 OFF, 1 ERROR, 2 ACTIVE, 3 READY
+ ret.parkingBrake = cp.vl["TCS13"]["PBRAKE_ACT"] == 1
+ ret.espDisabled = cp.vl["TCS11"]["TCS_PAS"] == 1
+ ret.espActive = cp.vl["TCS11"]["ABS_ACT"] == 1
+ ret.accFaulted = cp.vl["TCS13"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
+ ret.brakeLights = bool(cp.vl["TCS13"]["BrakeLight"] or ret.brakePressed)
if self.CP.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV | HyundaiFlags.FCEV):
if self.CP.flags & HyundaiFlags.FCEV:
- ret.gasPressed = cp.vl["FCEV_ACCELERATOR"]["ACCELERATOR_PEDAL"] > 0
+ ret.gas = cp.vl["FCEV_ACCELERATOR"]["ACCELERATOR_PEDAL"] / 254.
elif self.CP.flags & HyundaiFlags.HYBRID:
- ret.gasPressed = cp.vl["E_EMS11"]["CR_Vcu_AccPedDep_Pos"] > 0
+ ret.gas = cp.vl["E_EMS11"]["CR_Vcu_AccPedDep_Pos"] / 254.
else:
- ret.gasPressed = cp.vl["E_EMS11"]["Accel_Pedal_Pos"] > 0
+ ret.gas = cp.vl["E_EMS11"]["Accel_Pedal_Pos"] / 254.
+ ret.gasPressed = ret.gas > 0
else:
+ ret.gas = cp.vl["EMS12"]["PV_AV_CAN"] / 100.
ret.gasPressed = bool(cp.vl["EMS16"]["CF_Ems_AclAct"])
# Gear Selection via Cluster - For those Kia/Hyundai which are not fully discovered, we can use the Cluster Indicator for Gear Selection,
# as this seems to be standard over all cars, but is not the preferred method.
if self.CP.flags & (HyundaiFlags.HYBRID | HyundaiFlags.EV):
gear = cp.vl["ELECT_GEAR"]["Elect_Gear_Shifter"]
+ ret.gearStep = cp.vl["ELECT_GEAR"]["Elect_Gear_Step"]
+ if self.CP.carFingerprint == CAR.HYUNDAI_CASPER_EV:
+ ret.gearStep = 0
elif self.CP.flags & HyundaiFlags.FCEV:
gear = cp.vl["EMS20"]["HYDROGEN_GEAR_SHIFTER"]
elif self.CP.flags & HyundaiFlags.CLUSTER_GEARS:
gear = cp.vl["CLU15"]["CF_Clu_Gear"]
+ if self.CP.carFingerprint == CAR.KIA_K7:
+ ret.gearStep = cp.vl["LVR11"]["CF_Lvr_GearInf"]
elif self.CP.flags & HyundaiFlags.TCU_GEARS:
gear = cp.vl["TCU12"]["CUR_GR"]
else:
gear = cp.vl["LVR12"]["CF_Lvr_Gear"]
+ ret.gearStep = cp.vl["LVR11"]["CF_Lvr_GearInf"]
- ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
+ if not self.CP.carFingerprint in (CAR.HYUNDAI_NEXO):
+ ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
+ else:
+ gear = cp.vl["ELECT_GEAR"]["Elect_Gear_Shifter"]
+ gear_disp = cp.vl["ELECT_GEAR"]
- if (not self.CP.openpilotLongitudinalControl or self.CP.flags & HyundaiFlags.CAMERA_SCC) and not self.CP_IQ.flags & HyundaiFlagsIQ.NON_SCC:
+ gear_shifter = GearShifter.unknown
+
+ if gear == 1546: # Thank you for Neokii # fix PolorBear 22.06.05
+ gear_shifter = GearShifter.drive
+ elif gear == 2314:
+ gear_shifter = GearShifter.neutral
+ elif gear == 2569:
+ gear_shifter = GearShifter.park
+ elif gear == 2566:
+ gear_shifter = GearShifter.reverse
+
+ if gear_shifter != GearShifter.unknown and self.gear_shifter != gear_shifter:
+ self.gear_shifter = gear_shifter
+
+ ret.gearShifter = self.gear_shifter
+
+ if not self.CP.flags & HyundaiFlags.CC_ONLY_CAR and (not self.CP.openpilotLongitudinalControl or self.CP.flags & HyundaiFlags.CAMERA_SCC):
aeb_src = "FCA11" if self.CP.flags & HyundaiFlags.USE_FCA.value else "SCC12"
aeb_sig = "FCA_CmdAct" if self.CP.flags & HyundaiFlags.USE_FCA.value else "AEB_CmdAct"
aeb_warning = cp_cruise.vl[aeb_src]["CF_VSM_Warn"] != 0
scc_warning = cp_cruise.vl["SCC12"]["TakeOverReq"] == 1 # sometimes only SCC system shows an FCW
aeb_braking = cp_cruise.vl[aeb_src]["CF_VSM_DecCmdAct"] != 0 or cp_cruise.vl[aeb_src][aeb_sig] != 0
+ if self.CP.carFingerprint == CAR.HYUNDAI_CASPER_EV and aeb_src == "FCA11":
+ fca_fault = cp_cruise.vl["FCA11"]["FCA_Failinfo"] != 0 or cp_cruise.vl["FCA11"]["FCA_Status"] == 3
+ if fca_fault:
+ aeb_warning = False
+ aeb_braking = False
ret.stockFcw = (aeb_warning or scc_warning) and not aeb_braking
ret.stockAeb = aeb_warning and aeb_braking
@@ -190,157 +446,393 @@ class CarState(CarStateBase, EsccCarStateBase, AolCarState, CarStateExt):
ret.leftBlindspot = cp.vl["LCA11"]["CF_Lca_IndLeft"] != 0
ret.rightBlindspot = cp.vl["LCA11"]["CF_Lca_IndRight"] != 0
- # save the entire LKAS11 and CLU11
- self.lkas11 = copy.copy(cp_cam.vl["LKAS11"])
- self.clu11 = copy.copy(cp.vl["CLU11"])
self.steer_state = cp.vl["MDPS12"]["CF_Mdps_ToiActive"] # 0 NOT ACTIVE, 1 ACTIVE
prev_cruise_buttons = self.cruise_buttons[-1]
+ #self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
+ #carrot {{
+ #if self.CRUISE_BUTTON_ALT and cp.vl["CRUISE_BUTTON_ALT"]["SET_ME_1"] == 1:
+ # self.cruise_buttons_alt = True
+
+ cruise_button = [Buttons.NONE]
+ if self.cruise_buttons_alt:
+ lfa_button = cp.vl["CRUISE_BUTTON_LFA"]["CruiseSwLfa"]
+ cruise_button = [Buttons.LFA_BUTTON] if lfa_button > 0 else [cp.vl["CRUISE_BUTTON_ALT"]["CruiseSwState"]]
+ elif self.HAS_LFA_BUTTON and cp.vl["BCM_PO_11"]["LFA_Pressed"] == 1: # for K5
+ cruise_button = [Buttons.LFA_BUTTON]
+ else:
+ cruise_button = cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"]
+ self.cruise_buttons.extend(cruise_button)
+ # }} carrot
prev_main_buttons = self.main_buttons[-1]
- prev_lda_button = self.lda_button
- self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
- self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
- if self.CP.flags & HyundaiFlags.HAS_LDA_BUTTON:
- self.lda_button = cp.vl["BCM_PO_11"]["LDA_BTN"]
+ #self.cruise_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwState"])
+ if self.cruise_buttons_alt:
+ self.main_buttons.extend(cp.vl_all["CRUISE_BUTTON_ALT"]["CruiseSwMain"])
+ else:
+ self.main_buttons.extend(cp.vl_all["CLU11"]["CF_Clu_CruiseSwMain"])
+ self.mdps12 = copy.copy(cp.vl["MDPS12"])
ret.buttonEvents = [*create_button_events(self.cruise_buttons[-1], prev_cruise_buttons, BUTTONS_DICT),
- *create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise}),
- *create_button_events(self.lda_button, prev_lda_button, {1: ButtonType.lkas})]
+ *create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise})]
- if self.CP.openpilotLongitudinalControl:
- ret.cruiseState.available = self.get_main_cruise(ret)
- CarStateExt.update(self, ret, ret_iq, can_parsers, speed_conv)
+ if not self.CP.flags & HyundaiFlags.CC_ONLY_CAR:
+ tpms_unit = cp.vl["TPMS11"]["UNIT"] * 0.725 if int(cp.vl["TPMS11"]["UNIT"]) > 0 else 1.
+ ret.tpms.fl = tpms_unit * cp.vl["TPMS11"]["PRESSURE_FL"]
+ ret.tpms.fr = tpms_unit * cp.vl["TPMS11"]["PRESSURE_FR"]
+ ret.tpms.rl = tpms_unit * cp.vl["TPMS11"]["PRESSURE_RL"]
+ ret.tpms.rr = tpms_unit * cp.vl["TPMS11"]["PRESSURE_RR"]
- ret.blockPcmEnable = not self.recent_button_interaction()
+ cluSpeed = cp.vl["CLU11"]["CF_Clu_Vanz"]
+ decimal = cp.vl["CLU11"]["CF_Clu_VanzDecimal"]
+ if 0. < decimal < 0.5:
+ cluSpeed += decimal
- # low speed steer alert hysteresis logic (only for cars with steer cut off above 10 m/s)
- if ret.vEgo < (self.CP.minSteerSpeed + 2.) and self.CP.minSteerSpeed > 10.:
- self.low_speed_alert = True
- if ret.vEgo > (self.CP.minSteerSpeed + 4.):
- self.low_speed_alert = False
- ret.lowSpeedAlert = self.low_speed_alert
+ ret.vEgoCluster = cluSpeed * speed_conv
+ vEgoClu, aEgoClu = self.update_clu_speed_kf(ret.vEgoCluster)
+ ret.vCluRatio = (ret.vEgo / vEgoClu) if (vEgoClu > 3. and ret.vEgo > 3.) else 1.0
- return ret, ret_iq
+ if self.CP.extFlags & HyundaiExtFlags.NAVI_CLUSTER.value:
+ speedLimit = cp.vl["Navi_HU"]["SpeedLim_Nav_Clu"]
+ speedLimitCam = cp.vl["Navi_HU"]["SpeedLim_Nav_Cam"]
+ ret.speedLimit = speedLimit if speedLimit < 255 and speedLimitCam == 1 else 0
+ speed_limit_cam = speedLimitCam == 1
+ else:
+ ret.speedLimit = 0
+ ret.speedLimitDistance = 0
+ speed_limit_cam = False
- def update_canfd(self, can_parsers) -> tuple[structs.CarState, structs.IQCarState]:
+ self.update_speed_limit(ret, speed_limit_cam)
+
+ if prev_main_buttons == 0 and self.main_buttons[-1] != 0:
+ self.main_enabled = not self.main_enabled
+
+ return ret, self.out_iq
+
+ def update_speed_limit(self, ret, speed_limit_cam):
+ self.totalDistance += ret.vEgo * DT_CTRL
+ if ret.speedLimit > 0 and not ret.gasPressed and speed_limit_cam:
+ if self.speedLimitDistance <= self.totalDistance:
+ self.speedLimitDistance = self.totalDistance + ret.speedLimit * 6
+ self.speedLimitDistance = max(self.totalDistance + 1, self.speedLimitDistance)
+ else:
+ self.speedLimitDistance = self.totalDistance
+ ret.speedLimitDistance = self.speedLimitDistance - self.totalDistance
+
+ def update_canfd(self, can_parsers) -> structs.CarState:
cp = can_parsers[Bus.pt]
cp_cam = can_parsers[Bus.cam]
+ cp_alt = can_parsers[Bus.alt] if Bus.alt in can_parsers else None
ret = structs.CarState()
- ret_iq = structs.IQCarState()
+
+ if self.CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230:
+ ret.evModeActive, ret.evModeValid = _get_ev_mode_state(cp)
self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1
speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
if self.CP.flags & (HyundaiFlags.EV | HyundaiFlags.HYBRID):
- ret.gasPressed = cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL"] > 1e-5
+ offset = 255. if self.CP.flags & HyundaiFlags.EV else 1023.
+ ret.gas = cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL"] / offset if not self.use_accelerator else 0 if self.accelerator is None else self.accelerator["ACCELERATOR_PEDAL"] / offset
+ ret.gasPressed = ret.gas > 1e-5
else:
- ret.gasPressed = bool(cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL_PRESSED"])
+ ret.gasPressed = bool(cp.vl[self.accelerator_msg_canfd]["ACCELERATOR_PEDAL_PRESSED"]) if not self.use_accelerator else False if self.accelerator is None else bool(self.accelerator["ACCELERATOR_PEDAL_PRESSED"])
ret.brakePressed = cp.vl["TCS"]["DriverBraking"] == 1
+ #print(cp.vl["TCS"], cp.vl_all["TCS"]["DriverBraking"][-10:])
- ret.doorOpen = cp.vl["DOORS_SEATBELTS"]["DRIVER_DOOR"] == 1
- ret.seatbeltUnlatched = cp.vl["DOORS_SEATBELTS"]["DRIVER_SEATBELT"] == 0
+ if self.doors_seatbelts is not None:
+ ret.doorOpen = self.doors_seatbelts["DRIVER_DOOR"] == 1
+ ret.seatbeltUnlatched = self.doors_seatbelts["DRIVER_SEATBELT"] == 0
- gear = cp.vl[self.gear_msg_canfd]["GEAR"]
+ gear = cp.vl[self.gear_msg_canfd]["GEAR"] if not self.use_accelerator else 0 if self.accelerator is None else self.accelerator["GEAR"]
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear))
+ if self.TPMS:
+ tpms_unit = cp.vl["TPMS"]["UNIT"] * 0.725 if int(cp.vl["TPMS"]["UNIT"]) > 0 else 1.
+ ret.tpms.fl = tpms_unit * cp.vl["TPMS"]["PRESSURE_FL"]
+ ret.tpms.fr = tpms_unit * cp.vl["TPMS"]["PRESSURE_FR"]
+ ret.tpms.rl = tpms_unit * cp.vl["TPMS"]["PRESSURE_RL"]
+ ret.tpms.rr = tpms_unit * cp.vl["TPMS"]["PRESSURE_RR"]
+
# TODO: figure out positions
- self.parse_wheel_speeds(ret,
- cp.vl["WHEEL_SPEEDS"]["WHL_SpdFLVal"],
- cp.vl["WHEEL_SPEEDS"]["WHL_SpdFRVal"],
- cp.vl["WHEEL_SPEEDS"]["WHL_SpdRLVal"],
- cp.vl["WHEEL_SPEEDS"]["WHL_SpdRRVal"],
+ ret.wheelSpeeds = self.get_wheel_speeds(
+ cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_1"],
+ cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_2"],
+ cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_3"],
+ cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_4"],
)
- ret.standstill = cp.vl["WHEEL_SPEEDS"]["WHL_SpdFLVal"] <= STANDSTILL_THRESHOLD and cp.vl["WHEEL_SPEEDS"]["WHL_SpdFRVal"] <= STANDSTILL_THRESHOLD and \
- cp.vl["WHEEL_SPEEDS"]["WHL_SpdRLVal"] <= STANDSTILL_THRESHOLD and cp.vl["WHEEL_SPEEDS"]["WHL_SpdRRVal"] <= STANDSTILL_THRESHOLD
+ ret.vEgoRaw = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.
+ ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
+ ret.standstill = ret.wheelSpeeds.fl <= STANDSTILL_THRESHOLD and ret.wheelSpeeds.rr <= STANDSTILL_THRESHOLD
+
+ ret.brakeLights = ret.brakePressed or cp.vl["TCS"]["BrakeLight"] == 1 or ret.aEgo < -0.5
ret.steeringRateDeg = cp.vl["STEERING_SENSORS"]["STEERING_RATE"]
- ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEERING_ANGLE"]
+
+ # steering angle deg값이 이상함. mdps값이 더 신뢰가 가는듯.. torque steering 차량도 확인해야함.
+ #ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEERING_ANGLE"] * -1
+ #ret.steeringAngleDeg = cp.vl["MDPS"]["STEERING_ANGLE"] * -1
+ if self.CP.flags & HyundaiFlags.ANGLE_CONTROL:
+ ret.steeringAngleDeg = cp.vl["MDPS"]["STEERING_ANGLE_2"] * -1
+ else:
+ ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEERING_ANGLE"] * -1
+
+ trailer_signal = self.trailer_status is not None and self.trailer_status["TRAILER_CONNECTED"] != 0
+ if trailer_signal:
+ # Rising edge is immediate so trailer-specific behavior is preserved.
+ self.trailer_timeout_cnt = 0
+ self.trailer_connected = True
+ elif self.trailer_connected:
+ # During ignition-off, the trailer bit can clear before the cluster shuts down.
+ # Keep suppression active through that transient, while still detecting a real
+ # disconnect after 5 seconds at the 100 Hz CarState update rate.
+ self.trailer_timeout_cnt += 1
+ if self.trailer_timeout_cnt > TRAILER_DISCONNECT_GRACE_FRAMES:
+ self.trailer_connected = False
+ else:
+ self.trailer_timeout_cnt = 0
+
+ ret.trailerConnected = self.trailer_connected
+
+ if self.trailer_connected != self.trailer_connected_prev:
+ print(f"[TRAILER_DEBUG] connected={self.trailer_connected} timeout={self.trailer_timeout_cnt}")
+ self.trailer_connected_prev = self.trailer_connected
+
ret.steeringTorque = cp.vl["MDPS"]["STEERING_COL_TORQUE"]
ret.steeringTorqueEps = cp.vl["MDPS"]["STEERING_OUT_TORQUE"]
ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorque) > self.params.STEER_THRESHOLD, 5)
- steer_fault_raw = cp.vl["MDPS"]["LKA_FAULT"] != 0
- self.steer_fault_counter = self.steer_fault_counter + 1 if steer_fault_raw else 0
- ret.steerFaultTemporary = self.steer_fault_counter > 5
+ ret.steerFaultTemporary = cp.vl["MDPS"]["LKA_FAULT"] != 0 or cp.vl["MDPS"]["LFA2_FAULT"] != 0
+ #ret.steerFaultTemporary = False
+
+ blinkers_info = self.blinkers if self.blinkers is not None else self.blinkers_alt if self.blinkers_alt is not None else None
+ if blinkers_info is not None:
+ left_blinker_lamp = blinkers_info["LEFT_LAMP"] or blinkers_info["LEFT_LAMP_ALT"]
+ right_blinker_lamp = blinkers_info["RIGHT_LAMP"] or blinkers_info["RIGHT_LAMP_ALT"]
+ ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, left_blinker_lamp, right_blinker_lamp)
- # TODO: alt signal usage may be described by cp.vl['BLINKERS']['USE_ALT_LAMP']
- left_blinker_sig, right_blinker_sig = "LEFT_LAMP", "RIGHT_LAMP"
- if self.CP.carFingerprint == CAR.HYUNDAI_KONA_EV_2ND_GEN:
- left_blinker_sig, right_blinker_sig = "LEFT_LAMP_ALT", "RIGHT_LAMP_ALT"
- ret.leftBlinker, ret.rightBlinker = self.update_blinker_from_lamp(50, cp.vl["BLINKERS"][left_blinker_sig],
- cp.vl["BLINKERS"][right_blinker_sig])
if self.CP.enableBsm:
- ret.leftBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FL_INDICATOR"] != 0
- ret.rightBlindspot = cp.vl["BLINDSPOTS_REAR_CORNERS"]["FR_INDICATOR"] != 0
+ if self.cp_bsm is None:
+ if 442 in cp.seen_addresses:
+ self.cp_bsm = cp
+ print("######## BSM in ECAN")
+ elif 442 in cp_cam.seen_addresses:
+ self.cp_bsm = cp_cam
+ print("######## BSM in CAM")
+ else:
+ bsm_info = self.cp_bsm.vl["BLINDSPOTS_REAR_CORNERS"]
+ ret.leftBlindspot = (bsm_info["FL_INDICATOR"] + bsm_info["INDICATOR_LEFT_TWO"] + bsm_info["INDICATOR_LEFT_FOUR"]) > 0
+ ret.rightBlindspot = (bsm_info["FR_INDICATOR"] + bsm_info["INDICATOR_RIGHT_TWO"] + bsm_info["INDICATOR_RIGHT_FOUR"]) > 0
# cruise state
+ if self.cruise_buttons_alt2 is not None:
+ cruise_button = self.cruise_buttons_alt2["CRUISE_BUTTONS"]
+ else:
+ cruise_button = cp.vl[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"]
+ if cruise_button in [Buttons.RES_ACCEL, Buttons.SET_DECEL] and self.CP.openpilotLongitudinalControl:
+ self.main_enabled = True
# CAN FD cars enable on main button press, set available if no TCS faults preventing engagement
- ret.cruiseState.available = cp.vl["TCS"]["ACCEnable"] == 0
+ ret.cruiseState.available = self.main_enabled and self.controls_ready_count >= READY_COUNT_OK #cp.vl["TCS"]["ACCEnable"] == 0
+ if self.CP.flags & HyundaiFlags.CAMERA_SCC.value:
+ self.MainMode_ACC = cp_cam.vl["SCC_CONTROL"]["MainMode_ACC"] == 1
+ self.ACCMode = cp_cam.vl["SCC_CONTROL"]["ACCMode"]
+ self.LFA_ICON = cp_cam.vl["LFAHDA_CLUSTER"]["HDA_LFA_SymSta"]
+
if self.CP.openpilotLongitudinalControl:
# These are not used for engage/disengage since openpilot keeps track of state using the buttons
ret.cruiseState.enabled = cp.vl["TCS"]["ACC_REQ"] == 1
ret.cruiseState.standstill = False
+ if self.MainMode_ACC or self.main_enabled:
+ self.main_enabled = True
else:
cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
ret.cruiseState.enabled = cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] in (1, 2)
- ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["CRUISE_STANDSTILL"] == 1
+ if cp_cruise_info.vl["SCC_CONTROL"]["MainMode_ACC"] == 1: # carrot
+ ret.cruiseState.available = self.main_enabled = True
+ ret.pcmCruiseGap = int(np.clip(cp_cruise_info.vl["SCC_CONTROL"]["DISTANCE_SETTING"], 1, 4))
+ ret.cruiseState.standstill = cp_cruise_info.vl["SCC_CONTROL"]["InfoDisplay"] >= 4
ret.cruiseState.speed = cp_cruise_info.vl["SCC_CONTROL"]["VSetDis"] * speed_factor
- self.cruise_info = copy.copy(cp_cruise_info.vl["SCC_CONTROL"])
+ ret.brakeHoldActive = cp.vl["ESP_STATUS"]["AUTO_HOLD"] == 1 and cp_cruise_info.vl["SCC_CONTROL"]["ACCMode"] not in (1, 2)
+
+ speed_limit_cam = False
+ corner = False
+ corner_infos = [info for info in (self.adrv_0x1ea, self.ccnc_0x162) if info is not None]
+ if corner_infos:
+ def corner_max(signal):
+ return max(info[signal] for info in corner_infos)
+
+ ret.leftLongDist = self.lf_distance = corner_max("LF_DETECT_DISTANCE")
+ ret.rightLongDist = self.rf_distance = corner_max("RF_DETECT_DISTANCE")
+ self.lr_distance = corner_max("LR_DETECT_DISTANCE")
+ self.rr_distance = corner_max("RR_DETECT_DISTANCE")
+ ret.leftLatDist = corner_max("LF_DETECT_LATERAL")
+ ret.rightLatDist = corner_max("RF_DETECT_LATERAL")
+ ret.leftRearLongDist = self.lr_distance
+ ret.rightRearLongDist = self.rr_distance
+ ret.leftRearLatDist = corner_max("LR_DETECT_LATERAL")
+ ret.rightRearLatDist = corner_max("RR_DETECT_LATERAL")
+ corner = True
+ if corner:
+ raw_corner_radar_enabled = (
+ self.op_params.get_int("EnableCornerRadar") > 0 and
+ bool(self.CP.extFlags & (HyundaiExtFlags.CORNER_RADAR_OBJECTS_235.value |
+ HyundaiExtFlags.CORNER_RADAR_OBJECTS_180.value))
+ )
+ left_front_block = (not raw_corner_radar_enabled) and 0 < ret.leftLongDist < 7.0
+ right_front_block = (not raw_corner_radar_enabled) and 0 < ret.rightLongDist < 7.0
+ rear_block_dist = 5.0 if raw_corner_radar_enabled else 7.0
+ left_rear_block = 0 < self.lr_distance < rear_block_dist
+ right_rear_block = 0 < self.rr_distance < rear_block_dist
+ left_block = left_front_block or left_rear_block
+ right_block = right_front_block or right_rear_block
+ if left_block:
+ ret.leftBlindspot = True
+ if right_block:
+ ret.rightBlindspot = True
+
+ if self.hda_info_4a3 is not None:
+ speedLimit = self.hda_info_4a3["SPEED_LIMIT"]
+ if not self.is_metric:
+ speedLimit *= CV.MPH_TO_KPH
+ ret.speedLimit = speedLimit if speedLimit < 255 else 0
+ if int(self.hda_info_4a3["MapSource"]) == 2:
+ speed_limit_cam = True
+
+ if self.time_zone == "UTC":
+ country_code = int(self.hda_info_4a3["CountryCode"])
+ self.time_zone = ZoneInfo(NUMERIC_TO_TZ.get(country_code, "UTC"))
+
+ ret.gearStep = cp.vl["GEAR"]["GEAR_STEP"] if self.GEAR else 0
+ if 1 <= ret.gearStep <= 8 and ret.gearShifter == GearShifter.unknown:
+ ret.gearShifter = GearShifter.drive
+ ret.gearStep = cp.vl["GEAR_ALT"]["GEAR_STEP"] if self.GEAR_ALT else ret.gearStep
+
+ lane_info = self.cam_0x2a4 if self.cam_0x2a4 is not None else self.cam_0x362
+
+ if lane_info is not None:
+ left_lane_prob = lane_info["LEFT_LANE_PROB"]
+ right_lane_prob = lane_info["RIGHT_LANE_PROB"]
+ left_lane_type = lane_info["LEFT_LANE_TYPE"] # 0: dashed, 1: solid, 2: undecided, 3: road edge, 4: DLM Inner Solid, 5: DLM InnerDashed, 6:DLM Inner Undecided, 7: Botts Dots, 8: Barrier
+ right_lane_type = lane_info["RIGHT_LANE_TYPE"]
+ left_lane_color = lane_info["LEFT_LANE_COLOR"] # 0: none, 1: white, 2: yellow, 3: blue
+ right_lane_color = lane_info["RIGHT_LANE_COLOR"]
+ left_lane_info = left_lane_color * 10 + left_lane_type
+ right_lane_info = right_lane_color * 10 + right_lane_type
+ ret.leftLaneLine = left_lane_info
+ ret.rightLaneLine = right_lane_info
# Manual Speed Limit Assist is a feature that replaces non-adaptive cruise control on EV CAN FD platforms.
# It limits the vehicle speed, overridable by pressing the accelerator past a certain point.
# The car will brake, but does not respect positive acceleration commands in this mode
# TODO: find this message on ICE & HYBRID cars + cruise control signals (if exists)
if self.CP.flags & HyundaiFlags.EV:
- ret.cruiseState.nonAdaptive = cp.vl["MANUAL_SPEED_LIMIT_ASSIST"]["MSLA_ENABLED"] == 1
+ if self.manual_speed_limit_assist is not None:
+ #ret.cruiseState.nonAdaptive = cp.vl["MANUAL_SPEED_LIMIT_ASSIST"]["MSLA_ENABLED"] == 1
+ ret.cruiseState.nonAdaptive = self.manual_speed_limit_assist["MSLA_ENABLED"] == 1
+
+ if self.LOCAL_TIME and self.time_zone != "UTC":
+ lt = cp.vl["LOCAL_TIME"]
+ y, m, d, H, M, S = int(lt["YEAR"]) + 2000, int(lt["MONTH"]), int(lt["DATE"]), int(lt["HOURS"]), int(lt["MINUTES"]), int(lt["SECONDS"])
+ try:
+ dt_local = datetime(y, m, d, H, M, S, tzinfo=self.time_zone)
+ ret.datetime = int(dt_local.timestamp() * 1000)
+ except:
+ #print(f"Error parsing local time: {y}-{m}-{d} {H}:{M}:{S} in {self.time_zone}")
+ pass
prev_cruise_buttons = self.cruise_buttons[-1]
+ #self.cruise_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"])
+ #carrot {{
+
+ if self.cruise_buttons_alt2 is not None:
+ if int(self.cruise_buttons_alt2.get("LFA_BTN", 0)) == 1:
+ cruise_button = [Buttons.LFA_BUTTON]
+ else:
+ v = int(self.cruise_buttons_alt2.get("CRUISE_BUTTONS", 0))
+ cruise_button = [v if v < 5 else Buttons.NONE]
+ elif cp.vl[self.cruise_btns_msg_canfd]["LFA_BTN"]:
+ cruise_button = [Buttons.LFA_BUTTON]
+ else:
+ cruise_button = cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"]
+
+ self.cruise_buttons.extend(cruise_button)
+ # }} carrot
+
+
+ #if self.cruise_btns_msg_canfd in cp.vl:
+ # self.cruise_buttons_msg = copy.copy(cp.vl[self.cruise_btns_msg_canfd])
+ """
+ if self.cruise_btns_msg_canfd in cp.vl: #carrot
+ if not cp.vl[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"]:
+ pass
+ #print("empty cruise btns...")
+ else:
+ self.cruise_buttons_msg = copy.copy(cp.vl[self.cruise_btns_msg_canfd])
+ """
prev_main_buttons = self.main_buttons[-1]
- prev_lda_button = self.lda_button
- self.cruise_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"])
- self.main_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"])
- self.lda_button = cp.vl[self.cruise_btns_msg_canfd]["LDA_BTN"]
+ #self.cruise_buttons.extend(cp.vl_all[self.cruise_btns_msg_canfd]["CRUISE_BUTTONS"])
+ if self.cruise_buttons_alt2 is not None:
+ self.main_buttons.extend([1 if int(self.cruise_buttons_alt2.get("CRUISE_BUTTONS", 0)) == 8 else 0])
+ else:
+ adaptive_main = cp.vl_all[self.cruise_btns_msg_canfd]["ADAPTIVE_CRUISE_MAIN_BTN"]
+ normal_main = cp.vl_all[self.cruise_btns_msg_canfd]["NORMAL_CRUISE_MAIN_BTN"]
+ self.main_buttons.extend(int(adaptive or normal) for adaptive, normal in zip(adaptive_main, normal_main, strict=True))
+ if self.main_buttons[-1] != prev_main_buttons and not self.main_buttons[-1]: # and self.CP.openpilotLongitudinalControl: #carrot
+ self.main_enabled = not self.main_enabled
+ print("main_enabled = {}".format(self.main_enabled))
self.buttons_counter = cp.vl[self.cruise_btns_msg_canfd]["COUNTER"]
ret.accFaulted = cp.vl["TCS"]["ACCEnable"] != 0 # 0 ACC CONTROL ENABLED, 1-3 ACC CONTROL DISABLED
- if self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
- self.lfa_block_msg = copy.copy(cp_cam.vl["CAM_0x362"] if self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT
- else cp_cam.vl["CAM_0x2a4"])
+ speed_conv = CV.KPH_TO_MS # if self.is_metric else CV.MPH_TO_MS
+ cluSpeed = cp.vl["CRUISE_BUTTONS_ALT"]["CLU_SPEED"]
+ ret.vEgoCluster = cluSpeed * speed_conv # MPH단위에서도 KPH로 나오는듯..
+ vEgoClu, aEgoClu = self.update_clu_speed_kf(ret.vEgoCluster)
+ ret.vCluRatio = (ret.vEgo / vEgoClu) if (vEgoClu > 3. and ret.vEgo > 3.) else 1.0
- AolCarState.update_aol_canfd(self, ret, can_parsers)
+ self.update_speed_limit(ret, speed_limit_cam)
+
+ paddle_button = self.paddle_button_prev
+ if self.cruise_btns_msg_canfd == "CRUISE_BUTTONS":
+ paddle_button = 1 if cp.vl["CRUISE_BUTTONS"]["LEFT_PADDLE"] == 1 else 2 if cp.vl["CRUISE_BUTTONS"]["RIGHT_PADDLE"] == 1 else 0
+ elif self.gear_msg_canfd == "GEAR":
+ paddle_button = 1 if cp.vl["GEAR"]["LEFT_PADDLE"] == 1 else 2 if cp.vl["GEAR"]["RIGHT_PADDLE"] == 1 else 0
ret.buttonEvents = [*create_button_events(self.cruise_buttons[-1], prev_cruise_buttons, BUTTONS_DICT),
- *create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise}),
- *create_button_events(self.lda_button, prev_lda_button, {1: ButtonType.lkas})]
+ *create_button_events(paddle_button, self.paddle_button_prev, {1: ButtonType.paddleLeft, 2: ButtonType.paddleRight}),
+ *create_button_events(self.main_buttons[-1], prev_main_buttons, {1: ButtonType.mainCruise})]
- if self.CP.openpilotLongitudinalControl:
- ret.cruiseState.available = self.get_main_cruise(ret)
+ self.paddle_button_prev = paddle_button
- CarStateExt.update_canfd_ext(self, ret, ret_iq, can_parsers, speed_factor)
+ return ret
- ret.blockPcmEnable = not self.recent_button_interaction()
-
- return ret, ret_iq
-
- def get_can_parsers_canfd(self, CP):
+ def get_can_parsers_canfd(self, CP, CP_IQ=None):
msgs = []
if not (CP.flags & HyundaiFlags.CANFD_ALT_BUTTONS):
# TODO: this can be removed once we add dynamic support to vl_all
msgs += [
- # this message is 50Hz but the ECU frequently stops transmitting for ~0.5s
- ("CRUISE_BUTTONS", 1)
+ ("CRUISE_BUTTONS", 50)
]
+
+ CAN = CanBus(CP)
+ pt_parser = CANParser(DBC[CP.carFingerprint][Bus.pt], msgs, CAN.ECAN)
+ if CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230:
+ # Display-only while the signal is fleet-validated: checksum and freshness
+ # gate the value without making a counter/alive fault disable controls.
+ pt_parser._add_message(EV_MODE_STATUS_MSG, math.nan, ignore_counter=True)
+
return {
- Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], msgs, CanBus(CP).ECAN),
- Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).CAM),
+ Bus.pt: pt_parser,
+ Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CAN.CAM),
+ Bus.alt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CAN.ACAN),
}
- def get_can_parsers(self, CP, CP_IQ):
+ def get_can_parsers(self, CP, CP_IQ=None):
if CP.flags & HyundaiFlags.CANFD:
return self.get_can_parsers_canfd(CP)
return {
- Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 0),
+ # EMS21 carries SCR_UREA_LEVEL on diesel platforms. NaN frequency makes
+ # it optional, so gasoline/EV platforms do not fail CAN validity.
+ Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [("EMS21", math.nan)], 0),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 2),
}
diff --git a/iqdbc_repo/iqdbc/car/hyundai/fingerprints.py b/iqdbc_repo/iqdbc/car/hyundai/fingerprints.py
index e526389..6024002 100644
--- a/iqdbc_repo/iqdbc/car/hyundai/fingerprints.py
+++ b/iqdbc_repo/iqdbc/car/hyundai/fingerprints.py
@@ -1,10 +1,6 @@
-""" AUTO-FORMATTED USING iqdbc/car/debug/format_fingerprints.py, EDIT STRUCTURE THERE."""
from iqdbc.car.structs import CarParams
from iqdbc.car.hyundai.values import CAR
-from iqdbc.lvbs.car.fingerprints_ext import extend_fw_versions
-from iqdbc.lvbs.car.hyundai.fingerprints_ext import FW_VERSIONS_EXT
-
Ecu = CarParams.Ecu
# The existence of SCC or RDR in the fwdRadar FW usually determines the radar's function,
@@ -12,6 +8,14 @@ Ecu = CarParams.Ecu
FW_VERSIONS = {
+ CAR.HYUNDAI_AZERA_7TH_GEN: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00GN7_ RDR ----- 1.00 1.03 99110-N1000 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00GN7 MFC AT KOR LHD 1.00 1.03 99211-N1000 230322',
+ ],
+ },
CAR.HYUNDAI_AZERA_6TH_GEN: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00IG__ SCC F-CU- 1.00 1.00 99110-G8100 ',
@@ -21,7 +25,6 @@ FW_VERSIONS = {
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00IG MFC AT MES LHD 1.00 1.04 99211-G8100 200511',
- b'\xf1\x00IG MFC AT MES LHD 1.00 1.05 99211-G8100 210409',
],
},
CAR.HYUNDAI_AZERA_HEV_6TH_GEN: {
@@ -55,20 +58,13 @@ FW_VERSIONS = {
],
(Ecu.eps, 0x7d4, None): [
b'\xf1\x00AE MDPS C 1.00 1.03 56310/G2300 4AEHC103',
- b'\xf1\x00AE MDPS C 1.00 1.03 56310G2300\x00 4AEHC103',
- b'\xf1\x00AE MDPS C 1.00 1.04 56310G2550\x00 4AEHC104',
- b'\xf1\x00AE MDPS C 1.00 1.05 56310/G2500 4AEHC105',
b'\xf1\x00AE MDPS C 1.00 1.05 56310/G2501 4AEHC105',
b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2301 4AEHC107',
b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2501 4AEHC107',
- b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2551 4AEHC107',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00AEH MFC AT EUR LHD 1.00 1.00 95740-G2400 180222',
b'\xf1\x00AEH MFC AT EUR LHD 1.00 1.00 95740-G7200 160418',
- b'\xf1\x00AEH MFC AT EUR RHD 1.00 1.00 95740-G2200 161014',
- b'\xf1\x00AEH MFC AT EUR RHD 1.00 1.00 95740-G2400 180222',
- b'\xf1\x00AEH MFC AT USA LHD 1.00 1.00 95740-G2300 170703',
b'\xf1\x00AEH MFC AT USA LHD 1.00 1.00 95740-G2400 180222',
],
},
@@ -78,13 +74,11 @@ FW_VERSIONS = {
b'\xf1\x00AEhe SCC H-CUP 1.01 1.01 96400-G2100 ',
],
(Ecu.eps, 0x7d4, None): [
- b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2201 4AEHC107',
b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2501 4AEHC107',
b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2551 4AEHC107',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00AEP MFC AT AUS RHD 1.00 1.00 95740-G2400 180222',
- b'\xf1\x00AEP MFC AT EUR LHD 1.00 1.00 95740-G2400 180222',
b'\xf1\x00AEP MFC AT USA LHD 1.00 1.00 95740-G2400 180222',
],
},
@@ -154,12 +148,10 @@ FW_VERSIONS = {
CAR.HYUNDAI_IONIQ_HEV_2022: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00AEhe SCC F-CUP 1.00 1.00 99110-G2600 ',
- b'\xf1\x00AEhe SCC F-CUP 1.00 1.02 99110-G2100 ',
b'\xf1\x00AEhe SCC FHCUP 1.00 1.00 99110-G2600 ',
b'\xf1\x00AEhe SCC FHCUP 1.00 1.02 99110-G2100 ',
],
(Ecu.eps, 0x7d4, None): [
- b'\xf1\x00AE MDPS C 1.00 1.01 56310-XX000 4APHC101',
b'\xf1\x00AE MDPS C 1.00 1.01 56310/G2510 4APHC101',
b'\xf1\x00AE MDPS C 1.00 1.01 56310G2510\x00 4APHC101',
],
@@ -173,7 +165,6 @@ FW_VERSIONS = {
b'\xf1\x00DN8_ SCC F-CU- 1.00 1.00 99110-L0000 ',
b'\xf1\x00DN8_ SCC F-CUP 1.00 1.00 99110-L0000 ',
b'\xf1\x00DN8_ SCC F-CUP 1.00 1.02 99110-L1000 ',
- b'\xf1\x00DN8_ SCC FHCU- 1.00 1.00 99110-L0000 ',
b'\xf1\x00DN8_ SCC FHCUP 1.00 1.00 99110-L0000 ',
b'\xf1\x00DN8_ SCC FHCUP 1.00 1.01 99110-L1000 ',
b'\xf1\x00DN8_ SCC FHCUP 1.00 1.02 99110-L1000 ',
@@ -232,6 +223,15 @@ FW_VERSIONS = {
b'\xf1\x00LFF LKAS AT USA LHD 1.01 1.02 95740-C1000 E52',
],
},
+ CAR.HYUNDAI_SONATA_2024: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00DN8_ RDR ----- 1.00 1.00 99110-L1800 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00DN8 MFC AT KOR LHD 1.00 1.01 99211-L1800 230512',
+ b'\xf1\x00DN8 MFC AT USA LHD 1.00 1.01 99211-L1800 230512',
+ ],
+ },
CAR.HYUNDAI_TUCSON: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00TL__ FCA F-CUP 1.00 1.01 99110-D3500 ',
@@ -293,7 +293,6 @@ FW_VERSIONS = {
b'\xf1\x00TM ESC \x04 101 \x08\x04 58910-S2GA0',
b'\xf1\x00TM ESC \x04 102!\x04\x05 58910-S2GA0',
b'\xf1\x00TM ESC \x04 103"\x07\x08 58910-S2GA0',
- b'\xf1\x00TM ESC \x1b 102 \x08\x08 58910-S1DA0',
b'\xf1\x00TM ESC \x1e 102 \x08\x08 58910-S1DA0',
b'\xf1\x00TM ESC 103!\x030 58910-S1MA0',
],
@@ -301,7 +300,6 @@ FW_VERSIONS = {
b'\xf1\x00TM MDPS C 1.00 1.01 56310-S1AB0 4TSDC101',
b'\xf1\x00TM MDPS C 1.00 1.01 56310-S1EB0 4TSDC101',
b'\xf1\x00TM MDPS C 1.00 1.02 56370-S2AA0 0B19',
- b'\xf1\x00TM MDPS R 1.00 1.05 57700-S1500 4TSDP105',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00TM MFC AT EUR LHD 1.00 1.03 99211-S1500 210224',
@@ -367,7 +365,6 @@ FW_VERSIONS = {
},
CAR.KIA_STINGER: {
(Ecu.fwdRadar, 0x7d0, None): [
- b'\xf1\x00CK__ SCC FHCUP 1.00 1.02 96400-J5000 ',
b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5000 ',
b'\xf1\x00CK__ SCC F_CUP 1.00 1.01 96400-J5100 ',
b'\xf1\x00CK__ SCC F_CUP 1.00 1.02 96400-J5100 ',
@@ -383,7 +380,6 @@ FW_VERSIONS = {
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00CK MFC AT EUR LHD 1.00 1.03 95740-J5000 170822',
- b'\xf1\x00CK MFC AT KOR LHD 1.00 1.04 95740-J5000 180504',
b'\xf1\x00CK MFC AT USA LHD 1.00 1.03 95740-J5000 170822',
b'\xf1\x00CK MFC AT USA LHD 1.00 1.04 95740-J5000 180504',
],
@@ -400,7 +396,6 @@ FW_VERSIONS = {
b'\xf1\x00CK MDPS R 1.00 5.03 57700-J5320 4C2VL503',
b'\xf1\x00CK MDPS R 1.00 5.03 57700-J5380 4C2VR503',
b'\xf1\x00CK MDPS R 1.00 5.03 57700-J5520 4C4VL503',
- b'\xf1\x00CK MDPS R 1.00 5.04 57700-J5320 4C2VL504',
b'\xf1\x00CK MDPS R 1.00 5.04 57700-J5520 4C4VL504',
],
(Ecu.fwdCamera, 0x7c4, None): [
@@ -442,7 +437,6 @@ FW_VERSIONS = {
b'\xf1\x00LX ESC \x0b 104 \x10\x13 58910-S8330',
b'\xf1\x00LX ESC \x0b 104 \x10\x16 58910-S8360',
b'\xf1\x00ON ESC \x01 101\x19\t\x08 58910-S9360',
- b'\xf1\x00ON ESC \x01 103$\x04\x08 58910-S9360',
b'\xf1\x00ON ESC \x0b 100\x18\x12\x18 58910-S9360',
b'\xf1\x00ON ESC \x0b 101\x19\t\x05 58910-S9320',
b'\xf1\x00ON ESC \x0b 101\x19\t\x08 58910-S9360',
@@ -648,6 +642,14 @@ FW_VERSIONS = {
b'\xf1\x00DL3HMFC AT KOR LHD 1.00 1.04 99210-L2000 210527',
],
},
+ CAR.KIA_K5_DL3_24_HEV: { # (DL3)
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00DL3HMFC AT KOR LHD 1.00 1.02 99210-L2500 230911'
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00DL3_ RDR ----- 1.00 1.01 99110-L2500 ',
+ ],
+ },
CAR.HYUNDAI_KONA_EV: {
(Ecu.abs, 0x7d1, None): [
b'\xf1\x00OS IEB \x01 212 \x11\x13 58520-K4000',
@@ -703,7 +705,6 @@ FW_VERSIONS = {
b'\xf1\x00OSP MDPS C 1.00 1.02 56310-K4271 4OEPC102',
b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4271 4OEPC102',
b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4970 4OEPC102',
- b'\xf1\x00OSP MDPS C 1.00 1.02 56310/K4971 4OEPC102',
b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4260\x00 4OEPC102',
b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4261\x00 4OEPC102',
b'\xf1\x00OSP MDPS C 1.00 1.02 56310K4971\x00 4OEPC102',
@@ -720,6 +721,14 @@ FW_VERSIONS = {
b'\xf1\x00SX2EMFC AT KOR LHD 1.00 1.00 99211-BF000 230410',
],
},
+ CAR.HYUNDAI_KONA_HEV_2ND_GEN: {
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00SX2HMFC AT EUR RHD 1.00 1.04 99211-BE000 231010',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00SX2_ RDR ----- 1.00 1.02 99110-BE500 ',
+ ],
+ },
CAR.KIA_NIRO_EV: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00DEev SCC F-CUP 1.00 1.00 99110-Q4000 ',
@@ -737,14 +746,11 @@ FW_VERSIONS = {
b'\xf1\x00DE MDPS C 1.00 1.04 56310Q4100\x00 4DEEC104',
b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4000\x00 4DEEC105',
b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4100\x00 4DEEC105',
- b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4150\x00 4DEEC105',
- b'\xf1\x00DE MDPS C 1.00 1.05 56310Q4200\x00 4DEEC105',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00DEE MFC AT EUR LHD 1.00 1.00 99211-Q4000 191211',
b'\xf1\x00DEE MFC AT EUR LHD 1.00 1.00 99211-Q4100 200706',
b'\xf1\x00DEE MFC AT EUR LHD 1.00 1.03 95740-Q4000 180821',
- b'\xf1\x00DEE MFC AT EUR RHD 1.00 1.00 99211-Q4000 191211',
b'\xf1\x00DEE MFC AT KOR LHD 1.00 1.02 95740-Q4000 180705',
b'\xf1\x00DEE MFC AT KOR LHD 1.00 1.03 95740-Q4000 180821',
b'\xf1\x00DEE MFC AT USA LHD 1.00 1.00 99211-Q4000 191211',
@@ -756,13 +762,9 @@ FW_VERSIONS = {
CAR.KIA_NIRO_EV_2ND_GEN: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ',
- b'\xf1\x00SG__ RDR ----- 1.00 1.00 99110-AT200 ',
],
(Ecu.fwdCamera, 0x7c4, None): [
- b'\xf1\x00SG2EMFC AT EUR LHD 1.00 1.00 99211-AT200 240315',
b'\xf1\x00SG2EMFC AT EUR LHD 1.01 1.09 99211-AT000 220801',
- b'\xf1\x00SG2EMFC AT USA LHD 1.00 1.00 99211-AT100 230216',
- b'\xf1\x00SG2EMFC AT USA LHD 1.00 1.00 99211-AT200 240401',
b'\xf1\x00SG2EMFC AT USA LHD 1.01 1.09 99211-AT000 220801',
],
},
@@ -866,11 +868,9 @@ FW_VERSIONS = {
CAR.KIA_OPTIMA_H_G4_FL: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00JFhe SCC FHCUP 1.00 1.01 99110-A8500 ',
- b'\xf1\x00JFhe SCC FHCUP 1.00 1.03 99110-A8500 ',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00JFH MFC AT KOR LHD 1.00 1.01 95895-A8200 180323',
- b'\xf1\x00JFH MFC AT KOR LHD 1.00 1.04 95895-A8200 181217',
],
},
CAR.HYUNDAI_ELANTRA: {
@@ -930,7 +930,6 @@ FW_VERSIONS = {
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.06 99210-AA000 220111',
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.07 99210-AA000 220426',
b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.08 99210-AA000 220728',
- b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.09 99210-AA000 221108',
],
(Ecu.abs, 0x7d1, None): [
b'\xf1\x00CN ESC \t 101 \x10\x03 58910-AB800',
@@ -998,7 +997,6 @@ FW_VERSIONS = {
},
CAR.KIA_SORENTO: {
(Ecu.fwdCamera, 0x7c4, None): [
- b'\xf1\x00UMP LKAS AT AUS RHD 1.00 1.00 96400-C6550 S30',
b'\xf1\x00UMP LKAS AT KOR LHD 1.00 1.00 95740-C5550 S30',
b'\xf1\x00UMP LKAS AT USA LHD 1.00 1.00 95740-C6550 d00',
b'\xf1\x00UMP LKAS AT USA LHD 1.01 1.01 95740-C6550 d01',
@@ -1032,6 +1030,14 @@ FW_VERSIONS = {
b'\xf1\x00CV1 MFC AT USA LHD 1.00 1.06 99210-CV000 220328',
],
},
+ CAR.KIA_EV6_PE: { # (CV1)
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00CV__ RDR ----- 1.00 1.01 99110-CV500 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00CV MFC AT KOR LHD 1.00 1.01 99210-CV500 240405',
+ ],
+ },
CAR.HYUNDAI_IONIQ_5: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NE1_ RDR ----- 1.00 1.00 99110-GI000 ',
@@ -1042,7 +1048,6 @@ FW_VERSIONS = {
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.00 99211-GI100 230915',
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.01 99211-GI010 211007',
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.01 99211-GI100 240110',
- b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.02 99211-GI010 211206',
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.03 99211-GI010 220401',
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.06 99211-GI000 210813',
b'\xf1\x00NE1 MFC AT EUR LHD 1.00 1.06 99211-GI010 230110',
@@ -1056,13 +1061,29 @@ FW_VERSIONS = {
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.00 99211-GI020 230719',
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.00 99211-GI100 230915',
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.01 99211-GI010 211007',
- b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.01 99211-GI100 240110',
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.02 99211-GI010 211206',
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.03 99211-GI010 220401',
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.05 99211-GI010 220614',
b'\xf1\x00NE1 MFC AT USA LHD 1.00 1.06 99211-GI010 230110',
],
},
+ CAR.HYUNDAI_IONIQ_5_PE: { # (NE1)
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00NE__ RDR ----- 1.00 1.00 99110-GI500 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00NE MFC AT KOR LHD 1.00 1.02 99211-GI500 240221',
+ ],
+ },
+ CAR.HYUNDAI_IONIQ_5_N: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00NE1N RDR ----- 1.00 1.00 99110-NI000 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00NE1NMFC AT KOR LHD 1.00 1.04 99211-NI000 231219',
+ b'\xf1\x00NE1NMFC AT USA LHD 1.00 1.04 99211-NI000 231219',
+ ],
+ },
CAR.HYUNDAI_IONIQ_6: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00CE__ RDR ----- 1.00 1.01 99110-KL000 ',
@@ -1076,9 +1097,16 @@ FW_VERSIONS = {
b'\xf1\x00CE MFC AT USA LHD 1.00 1.06 99211-KL000 230915',
],
},
+ CAR.HYUNDAI_IONIQ_9: {
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00MEev RDR ----- 1.00 1.00 99110-GO000 ',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00ME MFC AT KOR LHD 1.00 1.00 99211-GO000 241007',
+ ],
+ },
CAR.HYUNDAI_TUCSON_4TH_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
- b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.00 99211-N9220 14K',
b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.00 99211-N9260 14Y',
b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.01 99211-N9100 14A',
b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 1.00 99211-N9220 14K',
@@ -1090,14 +1118,12 @@ FW_VERSIONS = {
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9260 14Y',
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9100 14A',
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.01 99211-N9240 14T',
- b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 1.00 99211-N9240 14Q',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NX4__ 1.00 1.00 99110-N9100 ',
b'\xf1\x00NX4__ 1.00 1.01 99110-N9000 ',
b'\xf1\x00NX4__ 1.00 1.02 99110-N9000 ',
b'\xf1\x00NX4__ 1.01 1.00 99110-N9100 ',
- b'\xf1\x00NX4__ 1.01 1.02 99110-N9000 ',
],
},
CAR.HYUNDAI_SANTA_CRUZ_1ST_GEN: {
@@ -1115,13 +1141,11 @@ FW_VERSIONS = {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NQ5 FR_CMR AT AUS RHD 1.00 1.00 99211-P1040 663',
b'\xf1\x00NQ5 FR_CMR AT EUR LHD 1.00 1.00 99211-P1040 663',
- b'\xf1\x00NQ5 FR_CMR AT GEN LHD 1.00 1.00 99211-P1040 663',
b'\xf1\x00NQ5 FR_CMR AT GEN LHD 1.00 1.00 99211-P1060 665',
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1030 662',
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1040 663',
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1060 665',
b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.00 99211-P1070 690',
- b'\xf1\x00NQ5 FR_CMR AT USA LHD 1.00 1.01 99211-P1060 680',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00NQ5__ 1.00 1.02 99110-P1000 ',
@@ -1134,14 +1158,11 @@ FW_VERSIONS = {
CAR.GENESIS_GV70_1ST_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00JK1 MFC AT CAN LHD 1.00 1.02 99211-IY000 230627',
- b'\xf1\x00JK1 MFC AT CAN LHD 1.00 1.04 99211-AR100 210204',
b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.01 99211-AR200 220125',
b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.01 99211-AR300 220125',
- b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.02 99211-IY000 230627',
b'\xf1\x00JK1 MFC AT USA LHD 1.00 1.04 99211-AR000 210204',
],
(Ecu.fwdRadar, 0x7d0, None): [
- b'\xf1\x00JK1_ SCC ----- 1.00 1.02 99110-AR100 ',
b'\xf1\x00JK1_ SCC FHCUP 1.00 1.00 99110-AR200 ',
b'\xf1\x00JK1_ SCC FHCUP 1.00 1.00 99110-AR300 ',
b'\xf1\x00JK1_ SCC FHCUP 1.00 1.00 99110-IY000 ',
@@ -1158,6 +1179,24 @@ FW_VERSIONS = {
b'\xf1\x00JKev SCC ----- 1.00 1.01 99110-DS000 ',
],
},
+
+ CAR.HYUNDAI_NEXO_1ST_GEN: {
+ (Ecu.abs, 0x7d1, None): [
+ b'\xf1\x00FE IEB \x01 312 \x11\x13 58520-M5000',
+ ],
+ (Ecu.fwdCamera, 0x7c4, None): [
+ b'\xf1\x00FE MFC AT KOR LHD 1.00 1.00 99211-M5100 201218',
+ b'\xf1\x00FE MFC AT KOR LHD 1.00 1.02 99211-M5100 220405',
+ ],
+ (Ecu.eps, 0x7d4, None): [
+ b'\xf1\x00FE MDPS C 1.00 1.05 56340-M5000 9903',
+ b'\xf1\x00FE MDPS C 1.00 1.06 56340-M5000 1625',
+ ],
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00FE__ SCC FHCUP 1.00 1.05 99110-M5000 ',
+ ],
+ },
+
CAR.GENESIS_GV60_EV_1ST_GEN: {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00JW1 MFC AT AUS RHD 1.00 1.03 99211-CU100 221118',
@@ -1189,7 +1228,6 @@ FW_VERSIONS = {
b'\xf1\x00MQ4HMFC AT KOR LHD 1.00 1.12 99210-P2000 230331',
b'\xf1\x00MQ4HMFC AT USA LHD 1.00 1.10 99210-P2000 210406',
b'\xf1\x00MQ4HMFC AT USA LHD 1.00 1.11 99210-P2000 211217',
- b'\xf1\x00MQ4HMFC AT USA LHD 1.00 1.12 99210-P2000 230331',
],
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00MQhe SCC FHCUP 1.00 1.04 99110-P4000 ',
@@ -1250,40 +1288,15 @@ FW_VERSIONS = {
b'\xf1\x00US4_ RDR ----- 1.00 1.00 99110-CG000 ',
],
},
- CAR.HYUNDAI_NEXO_1ST_GEN: {
- (Ecu.abs, 0x7d1, None): [
- b'\xf1\x00FE IEB \x01 312 \x11\x13 58520-M5000',
+ CAR.KIA_EV9: { # (MV)
+ (Ecu.fwdRadar, 0x7d0, None): [
+ b'\xf1\x00MV__ RDR ----- 1.00 1.02 99110-DO700 ',
+ b'\xf1\x00MV__ RDR ----- 1.00 1.02 99110-DO000 '
],
(Ecu.fwdCamera, 0x7c4, None): [
- b'\xf1\x00FE MFC AT KOR LHD 1.00 1.00 99211-M5100 201218',
- ],
- (Ecu.eps, 0x7d4, None): [
- b'\xf1\x00FE MDPS C 1.00 1.05 56340-M5000 9903',
- ],
- (Ecu.fwdRadar, 0x7d0, None): [
- b'\xf1\x00FE__ SCC FHCUP 1.00 1.05 99110-M5000 ',
- ],
- },
- CAR.HYUNDAI_KONA_2022: {
- (Ecu.fwdCamera, 0x7c4, None): [
- b'\xf1\x00OSP LKA AT CND LHD 1.00 1.04 99211-J9200 904',
- b'\xf1\x00OSP LKA AT USA LHD 1.00 1.04 99211-J9200 904',
- ],
- (Ecu.eps, 0x7d4, None): [
- b'\xf1\x00OSP MDPS C 1.00 1.04 56310/J9290 4OPCC104',
- b'\xf1\x00OSP MDPS C 1.00 1.04 56310/J9291 4OPCC104',
- b'\xf1\x00OSP MDPS C 1.00 1.04 56310J9291\x00 4OPCC104',
- ],
- (Ecu.fwdRadar, 0x7d0, None): [
- b'\xf1\x00YB__ FCA ----- 1.00 1.01 99110-J9000 \x00\x00\x00',
- ],
- (Ecu.transmission, 0x7e1, None): [
- b'\xf1\x00HT6WA280BLHT6VA650A1COS4N20NS1\x00\x00\x00\x00\x00\x00\x15\xf5\x87~',
- b'\xf1\x00T01960BL T01E60A1 DOS2T16X4XE60NS4N\x90\xe6\xcb',
- b'\xf1\x00T01G00BL T01I00A1 DOS2T16X2XI00NS0\x8c`\xff\xe7',
- b'\xf1\x00T01G00BL T01I00A1 DOS2T16X4XI00NS0\x99L\xeeq',
+ b'\xf1\x00MV MFC AT KOR LHD 1.00 1.01 99211-DO000 230419',
+ b'\xf1\x00MV MFC AT USA LHD 1.00 1.02 99211-DO000 230616',
+ b'\xf1\x00MV MFC AT EUR LHD 1.00 1.02 99211-DO000 230616',
],
},
}
-
-FW_VERSIONS = extend_fw_versions(FW_VERSIONS, FW_VERSIONS_EXT)
diff --git a/iqdbc_repo/iqdbc/car/hyundai/hyundaican.py b/iqdbc_repo/iqdbc/car/hyundai/hyundaican.py
index 70d6f34..f021118 100644
--- a/iqdbc_repo/iqdbc/car/hyundai/hyundaican.py
+++ b/iqdbc_repo/iqdbc/car/hyundai/hyundaican.py
@@ -1,17 +1,33 @@
+import copy
import crcmod
from iqdbc.car.hyundai.values import CAR, HyundaiFlags
-from iqdbc.lvbs.car.hyundai.escc import EnhancedSmartCruiseControl
-from iqdbc.lvbs.car.hyundai.lead_data_ext import CanLeadData
-
hyundai_checksum = crcmod.mkCrcFun(0x11D, initCrc=0xFD, rev=False, xorOut=0xdf)
+def suppress_casper_ev_fca11_fault(values):
+ # CASPER EV can report transient FCA faults during camera-SCC handoff.
+ # Keep the copied FCA11 frame non-faulting without changing other cars.
+ fca_fault = values["FCA_Failinfo"] != 0 or values["FCA_Status"] == 3
+ values["FCA_Failinfo"] = 0
+
+ if fca_fault:
+ values["FCA_Status"] = 2
+ values["CF_VSM_Prefill"] = 0
+ values["CF_VSM_HBACmd"] = 0
+ values["CF_VSM_Warn"] = 0
+ values["CF_VSM_BeltCmd"] = 0
+ values["CR_VSM_DecCmd"] = 0
+ values["FCA_CmdAct"] = 0
+ values["FCA_StopReq"] = 0
+ values["CF_VSM_DecCmdAct"] = 0
+
+ return values
def create_lkas11(packer, frame, CP, apply_torque, steer_req,
torque_fault, lkas11, sys_warning, sys_state, enabled,
left_lane, right_lane,
- left_lane_depart, right_lane_depart,
- lkas_icon):
+ left_lane_depart, right_lane_depart, is_ldws_car):
+
values = {s: lkas11[s] for s in [
"CF_Lkas_LdwsActivemode",
"CF_Lkas_LdwsSysState",
@@ -30,7 +46,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
"CF_Lkas_LdwsOpt_USM",
]}
values["CF_Lkas_LdwsSysState"] = sys_state
- values["CF_Lkas_SysWarning"] = 3 if sys_warning else 0
+ values["CF_Lkas_SysWarning"] = 0 # 3 if sys_warning else 0
values["CF_Lkas_LdwsLHWarning"] = left_lane_depart
values["CF_Lkas_LdwsRHWarning"] = right_lane_depart
values["CR_Lkas_StrToqReq"] = apply_torque
@@ -38,16 +54,10 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
values["CF_Lkas_ToiFlt"] = torque_fault # seems to allow actuation on CR_Lkas_StrToqReq
values["CF_Lkas_MsgCount"] = frame % 0x10
- if CP.carFingerprint in (CAR.HYUNDAI_SONATA, CAR.HYUNDAI_PALISADE, CAR.KIA_NIRO_EV, CAR.KIA_NIRO_HEV_2021, CAR.KIA_NIRO_PHEV_2022, CAR.HYUNDAI_SANTA_FE,
- CAR.HYUNDAI_IONIQ_EV_2020, CAR.HYUNDAI_IONIQ_PHEV, CAR.KIA_SELTOS, CAR.HYUNDAI_ELANTRA_2021, CAR.GENESIS_G70_2020,
- CAR.HYUNDAI_ELANTRA_HEV_2021, CAR.HYUNDAI_SONATA_HYBRID, CAR.HYUNDAI_KONA_EV, CAR.HYUNDAI_KONA_HEV, CAR.HYUNDAI_KONA_EV_2022,
- CAR.HYUNDAI_SANTA_FE_2022, CAR.KIA_K5_2021, CAR.HYUNDAI_IONIQ_HEV_2022, CAR.HYUNDAI_SANTA_FE_HEV_2022,
- CAR.HYUNDAI_SANTA_FE_PHEV_2022, CAR.KIA_STINGER_2022, CAR.KIA_K5_HEV_2020, CAR.KIA_CEED,
- CAR.HYUNDAI_AZERA_6TH_GEN, CAR.HYUNDAI_AZERA_HEV_6TH_GEN, CAR.HYUNDAI_CUSTIN_1ST_GEN, CAR.HYUNDAI_KONA_2022,
- CAR.KIA_CEED_PHEV_2022_NON_SCC, CAR.HYUNDAI_KONA_EV_NON_SCC, CAR.HYUNDAI_ELANTRA_2022_NON_SCC,
- CAR.GENESIS_G70_2021_NON_SCC, CAR.KIA_SELTOS_2023_NON_SCC, CAR.HYUNDAI_BAYON_1ST_GEN_NON_SCC):
+
+ if CP.flags & HyundaiFlags.SEND_LFA.value or CP.carFingerprint in (CAR.HYUNDAI_SANTA_FE):
values["CF_Lkas_LdwsActivemode"] = int(left_lane) + (int(right_lane) << 1)
- values["CF_Lkas_LdwsOpt_USM"] = 2
+ values["CF_Lkas_LdwsOpt_USM"] = 0 if CP.carFingerprint in (CAR.KIA_RAY_EV) else 2
# FcwOpt_USM 5 = Orange blinking car + lanes
# FcwOpt_USM 4 = Orange car + lanes
@@ -55,16 +65,16 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
# FcwOpt_USM 2 = Green car + lanes
# FcwOpt_USM 1 = White car + lanes
# FcwOpt_USM 0 = No car + lanes
- values["CF_Lkas_FcwOpt_USM"] = lkas_icon
+ values["CF_Lkas_FcwOpt_USM"] = 2 if enabled else 1
# SysWarning 4 = keep hands on wheel
# SysWarning 5 = keep hands on wheel (red)
# SysWarning 6 = keep hands on wheel (red) + beep
# Note: the warning is hidden while the blinkers are on
- values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
+ values["CF_Lkas_SysWarning"] = 0 #4 if sys_warning else 0
# Likely cars lacking the ability to show individual lane lines in the dash
- elif CP.carFingerprint in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL, CAR.HYUNDAI_KONA_NON_SCC):
+ elif CP.carFingerprint in (CAR.KIA_OPTIMA_G4, CAR.KIA_OPTIMA_G4_FL):
# SysWarning 4 = keep hands on wheel + beep
values["CF_Lkas_SysWarning"] = 4 if sys_warning else 0
@@ -72,7 +82,7 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
# SysState 1-2 = white car + lanes
# SysState 3 = green car + lanes, green steering wheel
# SysState 4 = green car + lanes
- values["CF_Lkas_LdwsSysState"] = lkas_icon
+ values["CF_Lkas_LdwsSysState"] = 3 if enabled else 1
values["CF_Lkas_LdwsOpt_USM"] = 2 # non-2 changes above SysState definition
# these have no effect
@@ -84,6 +94,11 @@ def create_lkas11(packer, frame, CP, apply_torque, steer_req,
# Genesis and Optima fault when forwarding while engaged
values["CF_Lkas_LdwsActivemode"] = 2
+ if is_ldws_car:
+ values["CF_Lkas_LdwsOpt_USM"] = 3
+
+ values["CF_Lkas_Chksum"] = 0
+
dat = packer.make_can_msg("LKAS11", 0, values)[1]
if CP.flags & HyundaiFlags.CHECKSUM_CRC8:
@@ -124,145 +139,265 @@ def create_clu11(packer, frame, clu11, button, CP):
return packer.make_can_msg("CLU11", bus, values)
-def create_lfahda_mfc(packer, enabled, lfa_icon):
+def create_lfahda_mfc(packer, CC, blinking_signal):
+ activeCarrot = CC.hudControl.activeCarrot
values = {
- "LFA_Icon_State": lfa_icon,
+ "LFA_Icon_State": 2 if CC.latActive else 1 if CC.enabled else 0,
+ #"HDA_Active": 1 if activeCarrot >= 2 else 0,
+ #"HDA_Icon_State": 2 if activeCarrot == 3 and blinking_signal else 2 if activeCarrot >= 2 else 0,
+ "HDA_Icon_State": 0 if activeCarrot == 3 and blinking_signal else 2 if activeCarrot >= 1 else 0,
+ "HDA_VSetReq": 0, #set_speed_in_units if activeCarrot >= 2 else 0,
+ "HDA_USM" : 2,
+ "HDA_Icon_Wheel" : 1 if CC.latActive else 0,
+ #"HDA_Chime" : 1 if CC.latActive else 0, # comment for K9 chime,
}
return packer.make_can_msg("LFAHDA_MFC", 0, values)
+def create_acc_commands_scc(packer, enabled, accel, jerk, idx, hud_control, set_speed, stopping, long_override, suppress_casper_ev_fca, CS, soft_hold_mode):
+ from iqdbc.car.hyundai.carcontroller import HyundaiJerk
+ cruise_available = CS.out.cruiseState.available
+ if CS.paddle_button_prev > 0:
+ cruise_available = False
+ soft_hold_active = CS.softHoldActive
+ soft_hold_info = soft_hold_active > 1 and enabled
+ #soft_hold_mode = 2 ## some cars can't enable while braking
+ long_enabled = enabled or (soft_hold_active > 0 and soft_hold_mode == 2)
+ stop_req = 1 if stopping or (soft_hold_active > 0 and soft_hold_mode == 2) else 0
+ d = hud_control.leadDistance
+ objGap = 0 if d == 0 else 2 if d < 25 else 3 if d < 40 else 4 if d < 70 else 5
+ objGap2 = 0 if objGap == 0 else 2 if hud_control.leadRelSpeed < -0.2 else 1
+
+ if long_enabled:
+ if jerk.carrot_cruise == 1:
+ long_enabled = False
+ accel = -0.5
+ elif jerk.carrot_cruise == 2:
+ accel = jerk.carrot_cruise_accel
+
+ if long_enabled:
+ scc12_acc_mode = 2 if long_override else 1
+ scc14_acc_mode = 2 if long_override else 1
+ if CS.out.brakeHoldActive:
+ scc12_acc_mode = 0
+ scc14_acc_mode = 4
+ elif CS.out.brakePressed:
+ scc12_acc_mode = 1
+ scc14_acc_mode = 1
+ else:
+ scc12_acc_mode = 0
+ scc14_acc_mode = 4
+
+ warning_front = False
-def create_acc_commands(packer, enabled, accel, upper_jerk, idx, lead_data: CanLeadData,
- hud_control, set_speed, stopping, long_override, use_fca, CP,
- main_cruise_enabled, tuning, ESCC: EnhancedSmartCruiseControl | None = None):
commands = []
+ if CS.scc11 is not None:
+ values = copy.copy(CS.scc11)
+ values["MainMode_ACC"] = 1 if cruise_available else 0
+ values["TauGapSet"] = hud_control.leadDistanceBars
+ values["VSetDis"] = set_speed if enabled else 0
+ values["AliveCounterACC"] = idx % 0x10
+ values["SCCInfoDisplay"] = 3 if warning_front else 4 if soft_hold_info else 0 if enabled else 0 #2: 크루즈 선택, 3: 전방상황주의, 4: 출발준비
+ values["ObjValid"] = 1 if hud_control.leadVisible else 0
+ values["ACC_ObjStatus"] = 1 if hud_control.leadVisible else 0
+ values["ACC_ObjLatPos"] = 0
+ values["ACC_ObjRelSpd"] = hud_control.leadRelSpeed
+ values["ACC_ObjDist"] = int(hud_control.leadDistance)
+ values["DriverAlertDisplay"] = 0
+ commands.append(packer.make_can_msg("SCC11", 0, values))
- def get_scc11_values():
- return {
- "MainMode_ACC": 1 if main_cruise_enabled else 0,
- "TauGapSet": hud_control.leadDistanceBars,
- "VSetDis": set_speed if enabled else 0,
- "AliveCounterACC": idx % 0x10,
- "ObjValid": int(lead_data.lead_visible), # close lead makes controls tighter
- "ACC_ObjStatus": int(lead_data.lead_visible), # close lead makes controls tighter
- "ACC_ObjLatPos": 0,
- "ACC_ObjRelSpd": lead_data.lead_rel_speed,
- "ACC_ObjDist": int(lead_data.lead_distance), # close lead makes controls tighter
- }
+ if CS.scc12 is not None:
+ values = copy.copy(CS.scc12)
+ values["ACCMode"] = scc12_acc_mode #2 if enabled and long_override else 1 if long_enabled else 0
+ values["StopReq"] = stop_req
+ values["aReqRaw"] = accel
+ values["aReqValue"] = accel
+ values["ACCFailInfo"] = 0
- def get_scc12_values():
- scc12_values = {
- "ACCMode": 2 if enabled and long_override else 1 if enabled else 0,
- "StopReq": 1 if tuning.stopping else 0,
- "aReqRaw": tuning.desired_accel,
- "aReqValue": tuning.actual_accel, # stock ramps up and down respecting jerk limit until it reaches aReqRaw
- "CR_VSM_Alive": idx % 0xF,
- }
+ #values["DESIRED_DIST"] = CS.out.vEgo * 1.0 + 4.0 # TF: 1.0 + STOPDISTANCE 4.0 m로 가정함.
- # show AEB disabled indicator on dash with SCC12 if not sending FCA messages.
- # these signals also prevent a TCS fault on non-FCA cars with alpha longitudinal
- if not use_fca:
- scc12_values["CF_VSM_ConfMode"] = 1
- scc12_values["AEB_Status"] = 1 # AEB disabled
-
- # Since we have ESCC available, we can update SCC12 with ESCC values.
- if ESCC and ESCC.enabled:
- ESCC.update_scc12(scc12_values)
-
- return scc12_values
-
- def calculate_scc12_checksum(values):
+ values["CR_VSM_ChkSum"] = 0
+ values["CR_VSM_Alive"] = idx % 0xF
scc12_dat = packer.make_can_msg("SCC12", 0, values)[1]
values["CR_VSM_ChkSum"] = 0x10 - sum(sum(divmod(i, 16)) for i in scc12_dat) % 0x10
- return values
- def get_scc14_values():
- return {
- "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,
- }
+ commands.append(packer.make_can_msg("SCC12", 0, values))
- def get_fca11_values():
- return {
+ if CS.scc14 is not None:
+ values = copy.copy(CS.scc14)
+ values["ComfortBandUpper"] = jerk.cb_upper
+ values["ComfortBandLower"] = jerk.cb_lower
+ values["JerkUpperLimit"] = jerk.jerk_u
+ values["JerkLowerLimit"] = jerk.jerk_l if long_enabled else 0 # for KONA test
+ values["ACCMode"] = scc14_acc_mode #2 if enabled and long_override else 1 if long_enabled else 4 # stock will always be 4 instead of 0 after first disengage
+ values["ObjGap"] = objGap #2 if hud_control.leadVisible else 0 # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead
+ values["ObjDistStat"] = objGap2
+ commands.append(packer.make_can_msg("SCC14", 0, values))
+
+ if CS.fca11 is not None and suppress_casper_ev_fca: # CASPER_EV의 경우 FCA11에서 fail이 간헐적 발생함.. 그냥막자.. 원인불명..
+ values = suppress_casper_ev_fca11_fault(copy.copy(CS.fca11))
+ fca11_dat = packer.make_can_msg("FCA11", 0, values)[1]
+ values["CR_FCA_ChkSum"] = hyundai_checksum(fca11_dat[:7])
+ commands.append(packer.make_can_msg("FCA11", 0, values))
+ # Only send FCA11 on cars where it exists on the bus
+ if False: #use_fca:
+ # note that some vehicles most likely have an alternate checksum/counter definition
+ # https://github.com/commaai/iqdbc/commit/9ddcdb22c4929baf310295e832668e6e7fcfa602
+ fca11_values = {
"CR_FCA_Alive": idx % 0xF,
"PAINT1_Status": 1,
"FCA_DrvSetStatus": 1,
- "FCA_Status": 1,
+ "FCA_Status": 1, # AEB disabled
}
-
- def calculate_fca11_checksum(values):
- fca11_dat = packer.make_can_msg("FCA11", 0, values)[1]
- values["CR_FCA_ChkSum"] = hyundai_checksum(fca11_dat[:7])
- return values
-
- scc11_values = get_scc11_values()
- commands.append(packer.make_can_msg("SCC11", 0, scc11_values))
-
- scc12_values = get_scc12_values()
- scc12_values = calculate_scc12_checksum(scc12_values)
- commands.append(packer.make_can_msg("SCC12", 0, scc12_values))
-
- scc14_values = get_scc14_values()
- commands.append(packer.make_can_msg("SCC14", 0, scc14_values))
-
- # Only send FCA11 on cars where it exists on the bus
- # On Camera SCC cars, FCA11 is not disabled, so we forward stock FCA11 back to the car forward hooks
- # If we don't use ESCC since ESCC does not block FCA11 from stock radar
- if use_fca and not ((CP.flags & HyundaiFlags.CAMERA_SCC) or (ESCC and ESCC.enabled)):
- # note that some vehicles most likely have an alternate checksum/counter definition
- # https://github.com/commaai/iqdbc/commit/9ddcdb22c4929baf310295e832668e6e7fcfa602
- fca11_values = get_fca11_values()
- fca11_values = calculate_fca11_checksum(fca11_values)
+ fca11_dat = packer.make_can_msg("FCA11", 0, fca11_values)[1]
+ fca11_values["CR_FCA_ChkSum"] = hyundai_checksum(fca11_dat[:7])
commands.append(packer.make_can_msg("FCA11", 0, fca11_values))
return commands
+def create_acc_opt_copy(CS, packer):
+ values = copy.copy(CS.scc13)
+ if values["NEW_SIGNAL_1"] == 255:
+ values["NEW_SIGNAL_1"] = 218
+ values["NEW_SIGNAL_2"] = 0
+ return packer.make_can_msg("SCC13", 0, CS.scc13)
-def create_acc_opt(packer, CP, ESCC: EnhancedSmartCruiseControl | None = None):
- """
- Creates SCC13 and FCA12. If ESCC is enabled, it will only create SCC13 since ESCC does not block FCA12.
- :param packer:
- :param ESCC:
- :return:
- """
+def create_acc_commands(packer, enabled, accel, jerk, idx, hud_control, set_speed, stopping, long_override, use_fca, CP, CS, soft_hold_mode):
+ from iqdbc.car.hyundai.carcontroller import HyundaiJerk
+ cruise_available = CS.out.cruiseState.available
+ soft_hold_active = CS.softHoldActive
+ soft_hold_info = soft_hold_active > 1 and enabled
+ #soft_hold_mode = 2 ## some cars can't enable while braking
+ long_enabled = enabled or (soft_hold_active > 0 and soft_hold_mode == 2)
+ stop_req = 1 if stopping or (soft_hold_active > 0 and soft_hold_mode == 2) else 0
+ d = hud_control.leadDistance
+ objGap = 0 if d == 0 else 2 if d < 25 else 3 if d < 40 else 4 if d < 70 else 5
+ objGap2 = 0 if objGap == 0 else 2 if hud_control.leadRelSpeed < -0.2 else 1
- def get_scc13_values():
- return {
- "SCCDrvModeRValue": 2,
- "SCC_Equip": 1,
- "Lead_Veh_Dep_Alert_USM": 2,
- }
+ if long_enabled:
+ scc12_acc_mode = 2 if long_override else 1
+ scc14_acc_mode = 2 if long_override else 1
+ if CS.out.brakeHoldActive:
+ scc12_acc_mode = 0
+ scc14_acc_mode = 4
+ elif CS.out.brakePressed:
+ scc12_acc_mode = 1
+ scc14_acc_mode = 1
+ else:
+ scc12_acc_mode = 0
+ scc14_acc_mode = 4
- def get_fca12_values():
- return {
- "FCA_DrvSetState": 2,
- "FCA_USM": 1, # AEB disabled
- }
+ warning_front = False
commands = []
- scc13_values = get_scc13_values()
- commands.append(packer.make_can_msg("SCC13", 0, scc13_values))
+ scc11_values = {
+ "MainMode_ACC": 1 if cruise_available else 0,
+ "TauGapSet": hud_control.leadDistanceBars,
+ "VSetDis": set_speed if enabled else 0,
+ "AliveCounterACC": idx % 0x10,
+ "SCCInfoDisplay": 3 if warning_front else 4 if soft_hold_info else 0 if enabled else 0,
+ "ObjValid": 1 if hud_control.leadVisible else 0, # close lead makes controls tighter
+ "ACC_ObjStatus": 1 if hud_control.leadVisible else 0, # close lead makes controls tighter
+ "ACC_ObjLatPos": 0,
+ "ACC_ObjRelSpd": hud_control.leadRelSpeed,
+ "ACC_ObjDist": int(hud_control.leadDistance), # close lead makes controls tighter
+ "DriverAlertDisplay": 0,
+ }
+ commands.append(packer.make_can_msg("SCC11", 0, scc11_values))
- # If ESCC is available and enabled, we skip FCA12, since ESCC does not block FCA12
- if ESCC and ESCC.enabled:
- return commands
+ scc12_values = {
+ "ACCMode": scc12_acc_mode,
+ "StopReq": stop_req,
+ "aReqRaw": 0 if stop_req > 0 else accel,
+ "aReqValue": accel, # stock ramps up and down respecting jerk limit until it reaches aReqRaw
+ #"DESIRED_DIST": CS.out.vEgo * 1.0 + 4.0,
+ "CR_VSM_Alive": idx % 0xF,
+ }
+
+ # show AEB disabled indicator on dash with SCC12 if not sending FCA messages.
+ # these signals also prevent a TCS fault on non-FCA cars with alpha longitudinal
+ if not use_fca:
+ scc12_values["CF_VSM_ConfMode"] = 1
+ scc12_values["AEB_Status"] = 1 # AEB disabled
+
+ scc12_dat = packer.make_can_msg("SCC12", 0, scc12_values)[1]
+ scc12_values["CR_VSM_ChkSum"] = 0x10 - sum(sum(divmod(i, 16)) for i in scc12_dat) % 0x10
+
+ commands.append(packer.make_can_msg("SCC12", 0, scc12_values))
+
+ scc14_values = {
+ "ComfortBandUpper": jerk.cb_upper, # stock usually is 0 but sometimes uses higher values
+ "ComfortBandLower": jerk.cb_lower, # stock usually is 0 but sometimes uses higher values
+ "JerkUpperLimit": jerk.jerk_u, # stock usually is 1.0 but sometimes uses higher values
+ "JerkLowerLimit": jerk.jerk_l, # stock usually is 0.5 but sometimes uses higher values
+ "ACCMode": scc14_acc_mode, # if enabled and long_override else 1 if enabled else 4, # stock will always be 4 instead of 0 after first disengage
+ "ObjGap": objGap, #2 if hud_control.leadVisible else 0, # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead
+ "ObjDistStat": objGap2,
+ }
+ commands.append(packer.make_can_msg("SCC14", 0, scc14_values))
+
+ # Only send FCA11 on cars where it exists on the bus
+ # On Camera SCC cars, FCA11 is not disabled, so we forward stock FCA11 back to the car forward hooks
+ if use_fca and not (CP.flags & HyundaiFlags.CAMERA_SCC):
+ # note that some vehicles most likely have an alternate checksum/counter definition
+ # https://github.com/commaai/iqdbc/commit/9ddcdb22c4929baf310295e832668e6e7fcfa602
+ fca11_values = {
+ "CR_FCA_Alive": idx % 0xF,
+ "PAINT1_Status": 1,
+ "FCA_DrvSetStatus": 1,
+ "FCA_Status": 1, # AEB disabled
+ }
+ fca11_dat = packer.make_can_msg("FCA11", 0, fca11_values)[1]
+ fca11_values["CR_FCA_ChkSum"] = hyundai_checksum(fca11_dat[:7])
+ commands.append(packer.make_can_msg("FCA11", 0, fca11_values))
+
+ return commands
+
+def create_acc_opt(packer, CP):
+ commands = []
+
+ scc13_values = {
+ "SCCDrvModeRValue": 2,
+ "SCC_Equip": 1,
+ "Lead_Veh_Dep_Alert_USM": 2,
+ }
+ commands.append(packer.make_can_msg("SCC13", 0, scc13_values))
# TODO: this needs to be detected and conditionally sent on unsupported long cars
# On Camera SCC cars, FCA12 is not disabled, so we forward stock FCA12 back to the car forward hooks
if not (CP.flags & HyundaiFlags.CAMERA_SCC):
- fca12_values = get_fca12_values()
+ fca12_values = {
+ "FCA_DrvSetState": 2,
+ "FCA_USM": 1, # AEB disabled
+ }
commands.append(packer.make_can_msg("FCA12", 0, fca12_values))
return commands
-
def create_frt_radar_opt(packer):
frt_radar11_values = {
"CF_FCA_Equip_Front_Radar": 1,
}
return packer.make_can_msg("FRT_RADAR11", 0, frt_radar11_values)
+
+def create_clu11_button(packer, frame, clu11, button, CP):
+ values = clu11.copy()
+ values["CF_Clu_CruiseSwState"] = button
+ #values["CF_Clu_AliveCnt1"] = frame % 0x10
+ values["CF_Clu_AliveCnt1"] = (values["CF_Clu_AliveCnt1"] + 1) % 0x10
+ # send buttons to camera on camera-scc based cars
+ bus = 2 if CP.flags & HyundaiFlags.CAMERA_SCC else 0
+ return packer.make_can_msg("CLU11", bus, values)
+
+def create_mdps12(packer, frame, mdps12):
+ values = mdps12
+ values["CF_Mdps_ToiActive"] = 0
+ values["CF_Mdps_ToiUnavail"] = 1
+ values["CF_Mdps_MsgCount2"] = frame % 0x100
+ values["CF_Mdps_Chksum2"] = 0
+
+ dat = packer.make_can_msg("MDPS12", 2, values)[1]
+ checksum = sum(dat) % 256
+ values["CF_Mdps_Chksum2"] = checksum
+
+ return packer.make_can_msg("MDPS12", 2, values)
diff --git a/iqdbc_repo/iqdbc/car/hyundai/hyundaicanfd.py b/iqdbc_repo/iqdbc/car/hyundai/hyundaicanfd.py
index a018a03..3d210f0 100644
--- a/iqdbc_repo/iqdbc/car/hyundai/hyundaicanfd.py
+++ b/iqdbc_repo/iqdbc/car/hyundai/hyundaicanfd.py
@@ -2,22 +2,42 @@ import copy
import numpy as np
from iqdbc.car import CanBusBase
from iqdbc.car.crc import CRC16_XMODEM
-from iqdbc.car.hyundai.values import HyundaiFlags
-from iqdbc.lvbs.car.hyundai.lead_data_ext import CanFdLeadData
+from iqdbc.car.hyundai.values import HyundaiFlags, HyundaiExtFlags
+from openpilot.common.params import Params
+from iqdbc.car.common.conversions import Conversions as CV
+from cereal import log
+LaneChangeState = log.LaneChangeState
+LaneChangeDirection = log.LaneChangeDirection
+TurnDirection = log.Desire
+
+
+def hyundai_crc8(data: bytes) -> int:
+ poly = 0x2F
+ crc = 0xFF
+
+ for byte in data:
+ crc ^= byte
+ for _ in range(8):
+ if crc & 0x80:
+ crc = ((crc << 1) ^ poly) & 0xFF
+ else:
+ crc = (crc << 1) & 0xFF
+
+ return crc ^ 0xFF
class CanBus(CanBusBase):
def __init__(self, CP, fingerprint=None, lka_steering=None) -> None:
super().__init__(CP, fingerprint)
if lka_steering is None:
- lka_steering = CP.flags & HyundaiFlags.CANFD_LKA_STEERING.value if CP is not None else False
+ lka_steering = CP.flags & HyundaiFlags.CANFD_HDA2.value if CP is not None else False
# On the CAN-FD platforms, the LKAS camera is on both A-CAN and E-CAN. LKA steering cars
# have a different harness than the LFA steering variants in order to split
# a different bus, since the steering is done by different ECUs.
self._a, self._e = 1, 0
- if lka_steering:
+ if lka_steering and Params().get_int("HyundaiCameraSCC") == 0: #배선개조는 무조건 Bus0가 ECAN임.
self._a, self._e = 0, 1
self._a += self.offset
@@ -36,50 +56,190 @@ class CanBus(CanBusBase):
def CAM(self):
return self._cam
+# CAN LIST (CAM) - 롱컨개조시... ADAS + CAM
+# 160: ADRV_0x160
+# 1da: ADRV_0x1da
+# 1ea: ADRV_0x1ea
+# 200: ADRV_0x200
+# 345: ADRV_0x345
+# 1fa: CLUSTER_SPEED_LIMIT
+# 12a: LFA
+# 1e0: LFAHDA_CLUSTER
+# 11a:
+# 1b5:
+# 1a0: SCC_CONTROL
-def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_torque, lkas_icon):
- common_values = {
- "LKA_MODE": 2,
- "LKA_ICON": lkas_icon,
- "TORQUE_REQUEST": apply_torque,
- "LKA_ASSIST": 0,
- "STEER_REQ": 1 if lat_active else 0,
- "STEER_MODE": 0,
- "HAS_LANE_SAFETY": 0, # hide LKAS settings
- "NEW_SIGNAL_2": 0,
- "DAMP_FACTOR": 100, # can potentially tuned for better perf [3, 200]
- }
+# CAN LIST (ACAN)
+# 160: ADRV_0x160
+# 51: ADRV_0x51
+# 180: CAM_0x180
+# ...
+# 185: CAM_0x185
+# 1b6: CAM_0x1b6
+# ...
+# 1b9: CAM_0x1b9
+# 1fb: CAM_0x1fb
+# 2a2 - 2a4
+# 2bb - 2be
+# LKAS
+# 201 - 2a0
- lkas_values = copy.copy(common_values)
- lkas_values["LKA_AVAILABLE"] = 0
- lfa_values = copy.copy(common_values)
- lfa_values["NEW_SIGNAL_1"] = 0
+
+def create_steering_messages_camera_scc(frame, packer, CP, CAN, CC, lat_active, apply_steer, CS, apply_angle, max_torque, angle_control):
+
+ emergency_steering = False
+ if CS.adrv_0x161 is not None:
+ values = CS.adrv_0x161
+ emergency_steering = values["ALERTS_1"] in [11, 12, 13, 14, 15, 21, 22, 23, 24, 25, 26]
+
ret = []
- if CP.flags & HyundaiFlags.CANFD_LKA_STEERING:
- lkas_msg = "LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT else "LKAS"
- if CP.openpilotLongitudinalControl:
- ret.append(packer.make_can_msg("LFA", CAN.ECAN, lfa_values))
- ret.append(packer.make_can_msg(lkas_msg, CAN.ACAN, lkas_values))
- else:
- ret.append(packer.make_can_msg("LFA", CAN.ECAN, lfa_values))
+ if CS.mdps is not None:
+ values = copy.copy(CS.mdps)
+ #rx_counter = values.pop("COUNTER", None)
+ if angle_control:
+ if CS.lfa_alt is not None:
+ values["LFA2_ACTIVE"] = CS.lfa_alt["LKAS_ANGLE_ACTIVE"]
+ else:
+ if CS.lfa is not None:
+ values["LKA_ACTIVE"] = 1 if CS.lfa["STEER_REQ"] == 1 else 0
+
+ if frame % 1000 < 40:
+ values["STEERING_COL_TORQUE"] += 220
+ #ret.append(packer.make_can_msg("MDPS", CAN.CAM, values, rx_counter = rx_counter))
+ ret.append(packer.make_can_msg("MDPS", CAN.CAM, values))
+
+ if frame % 10 == 0:
+ if CS.steer_touch_2af is not None:
+ values = copy.copy(CS.steer_touch_2af)
+ if frame % 1000 < 40:
+ values["TOUCH_DETECT"] = 3
+ values["TOUCH1"] = 50
+ values["TOUCH2"] = 50
+ values["CHECKSUM_"] = 0
+ dat = packer.make_can_msg("STEER_TOUCH_2AF", 0, values)[1]
+ values["CHECKSUM_"] = hyundai_crc8(dat[1:8])
+
+ ret.append(packer.make_can_msg("STEER_TOUCH_2AF", CAN.CAM, values))
+
+ if angle_control:
+ if CS.lfa_alt is not None:
+ values = copy.copy(CS.lfa_alt)
+ rx_counter = values.pop("COUNTER", None)
+ if emergency_steering:
+ pass
+ else:
+ #values = {} #CS.lfa_alt
+ values["LKAS_ANGLE_ACTIVE"] = 2 if CC.latActive else 1
+ values["LKAS_ANGLE_CMD"] = -apply_angle
+ values["LKAS_ANGLE_MAX_TORQUE"] = max_torque if CC.latActive else 0
+ ret.append(packer.make_can_msg("LFA_ALT", CAN.ECAN, values, rx_counter = rx_counter))
+
+ if CS.lfa is not None:
+ values = copy.copy(CS.lfa)
+ rx_counter = values.pop("COUNTER", None)
+ if not emergency_steering:
+ values["LKA_MODE"] = 0
+ values["LKA_ICON"] = 2 if CC.latActive else 1
+ values["TORQUE_REQUEST"] = -1024 # apply_steer,
+ values["VALUE63"] = 0 # LKA_ASSIST
+ values["STEER_REQ"] = 0 # 1 if lat_active else 0,
+ values["HAS_LANE_SAFETY"] = 0 # hide LKAS settings
+ values["LKA_ACTIVE"] = 3 if CC.latActive else 0 # this changes sometimes, 3 seems to indicate engaged
+ values["VALUE64"] = 0 #STEER_MODE, NEW_SIGNAL_2
+ values["LKAS_ANGLE_CMD"] = -25.6 #-apply_angle,
+ values["LKAS_ANGLE_ACTIVE"] = 0 #2 if lat_active else 1,
+ values["LKAS_ANGLE_MAX_TORQUE"] = 0 #max_torque if lat_active else 0,
+ values["NEW_SIGNAL_1"] = 10
+ ret.append(packer.make_can_msg("LFA", CAN.ECAN, values, rx_counter = rx_counter))
+
+ elif CS.lfa is not None:
+ values = {}
+ values["LKA_MODE"] = 2
+ values["LKA_ICON"] = 2 if lat_active else 1
+ values["TORQUE_REQUEST"] = apply_steer
+ values["STEER_REQ"] = 1 if lat_active else 0
+ values["VALUE64"] = 0 # STEER_MODE, NEW_SIGNAL_2
+ values["HAS_LANE_SAFETY"] = 0
+ values["LKA_ACTIVE"] = 0 # NEW_SIGNAL_1
+
+ values["DampingGain"] = 0 if lat_active else 100
+ #values["VALUE63"] = 0
+
+ #values["VALUE82_SET256"] = 0
+
+ ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
return ret
+def create_steering_messages(packer, CP, CAN, enabled, lat_active, apply_steer, apply_angle, max_torque, angle_control):
-def create_suppress_lfa(packer, CAN, lfa_block_msg, lka_steering_alt):
- suppress_msg = "CAM_0x362" if lka_steering_alt else "CAM_0x2a4"
- msg_bytes = 32 if lka_steering_alt else 24
+ ret = []
+ if angle_control:
+ values = {
+ "LKA_MODE": 0,
+ "LKA_ICON": 2 if enabled else 1,
+ "TORQUE_REQUEST": 0, # apply_steer,
+ "VALUE63": 0, # LKA_ASSIST
+ "STEER_REQ": 0, # 1 if lat_active else 0,
+ "HAS_LANE_SAFETY": 0, # hide LKAS settings
+ "LKA_ACTIVE": 3 if lat_active else 0, # this changes sometimes, 3 seems to indicate engaged
+ "VALUE64": 0, #STEER_MODE, NEW_SIGNAL_2
+ "LKAS_ANGLE_CMD": -apply_angle,
+ "LKAS_ANGLE_ACTIVE": 2 if lat_active else 1,
+ "LKAS_ANGLE_MAX_TORQUE": max_torque if lat_active else 0,
- values = {f"BYTE{i}": lfa_block_msg[f"BYTE{i}"] for i in range(3, msg_bytes) if i != 7}
+ # test for EV6PE
+ "NEW_SIGNAL_1": 10, #2,
+ "DampingGain": 9,
+ "VALUE231": 146,
+ "VALUE239": 1,
+ "VALUE247": 255,
+ "VALUE255": 255,
+ }
+ else:
+ values = {
+ "LKA_MODE": 2,
+ "LKA_ICON": 2 if enabled else 1,
+ "TORQUE_REQUEST": apply_steer,
+ "DampingGain": 100, #3 if enabled else 100,
+ "STEER_REQ": 1 if lat_active else 0,
+ #"STEER_MODE": 0,
+ "HAS_LANE_SAFETY": 0, # hide LKAS settings
+ "VALUE63": 0,
+ "VALUE64": 100,
+ }
+
+ if CP.flags & HyundaiFlags.CANFD_HDA2:
+ lkas_msg = "LKAS_ALT" if CP.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING else "LKAS"
+ if CP.openpilotLongitudinalControl:
+ ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
+ if not (CP.flags & HyundaiFlags.CAMERA_SCC.value):
+ ret.append(packer.make_can_msg(lkas_msg, CAN.ACAN, values))
+ else:
+ ret.append(packer.make_can_msg("LFA", CAN.ECAN, values))
+
+ return ret
+
+def create_suppress_lfa(packer, CAN, CS):
+ if CS.cam_0x362 is not None:
+ suppress_msg = "CAM_0x362"
+ lfa_block_msg = CS.cam_0x362
+ elif CS.cam_0x2a4 is not None:
+ suppress_msg = "CAM_0x2a4"
+ lfa_block_msg = CS.cam_0x2a4
+ else:
+ return []
+
+ #values = {f"BYTE{i}": lfa_block_msg[f"BYTE{i}"] for i in range(3, msg_bytes) if i != 7}
+ values = copy.copy(lfa_block_msg)
values["COUNTER"] = lfa_block_msg["COUNTER"]
values["SET_ME_0"] = 0
values["SET_ME_0_2"] = 0
values["LEFT_LANE_LINE"] = 0
values["RIGHT_LANE_LINE"] = 0
- return packer.make_can_msg(suppress_msg, CAN.ACAN, values)
-
+ return [packer.make_can_msg(suppress_msg, CAN.ACAN, values)]
def create_buttons(packer, CP, CAN, cnt, btn):
values = {
@@ -88,14 +248,12 @@ def create_buttons(packer, CP, CAN, cnt, btn):
"CRUISE_BUTTONS": btn,
}
- bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_LKA_STEERING else CAN.CAM
+ #bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_HDA2 else CAN.CAM
+ bus = CAN.ECAN
return packer.make_can_msg("CRUISE_BUTTONS", bus, values)
-
def create_acc_cancel(packer, CP, CAN, cruise_info_copy):
- # CAN FD camera-based SCC requires additional signals to be preserved
- # verbatim from the previous SCC_CONTROL frame to avoid checksum or
- # state validation faults. Classic CAN SCC only validates a subset.
+ # TODO: why do we copy different values here?
if CP.flags & HyundaiFlags.CANFD_CAMERA_SCC.value:
values = {s: cruise_info_copy[s] for s in [
"COUNTER",
@@ -124,49 +282,169 @@ def create_acc_cancel(packer, CP, CAN, cruise_info_copy):
})
return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
-
-def create_lfahda_cluster(packer, CAN, enabled, lfa_icon):
- values = {
- "HDA_ICON": 1 if enabled else 0,
- "LFA_ICON": lfa_icon,
- }
- return packer.make_can_msg("LFAHDA_CLUSTER", CAN.ECAN, values)
+def create_lfahda_cluster(packer, CS, CAN, long_active, lat_active):
-def create_acc_control(packer, CAN, enabled, accel_last, accel, stopping, gas_override, set_speed, hud_control,
- lead_data: CanFdLeadData, main_cruise_enabled, tuning):
+ if CS.lfahda_cluster is not None:
+ values = copy.copy(CS.lfahda_cluster)
+ rx_counter = values.pop("COUNTER", None)
+ else:
+ return []
+ values = {}
+ rx_counter = None
+ values["LFA_OptUsmSta"] = 2
+ values["HDA_OptUsmSta"] = 2
+ values["HDA_CntrlModSta"] = 2 if long_active else 0
+ values["HDA_LFA_SymSta"] = 2 if lat_active else 0
+ return [packer.make_can_msg("LFAHDA_CLUSTER", CAN.ECAN, values, rx_counter=rx_counter)]
+
+def create_lfa_icon_non_camera_scc(packer, CS, CAN, CC):
+ ret = []
+ if CS.adrv_0x161 is not None:
+ values = copy.copy(CS.adrv_0x161)
+ rx_counter = values.pop("COUNTER", None)
+
+ lat_active = CC.latActive
+ lat_enabled = CS.out.latEnabled
+
+ values["LFA_ICON"] = 2 if lat_active else 1 if lat_enabled else 0
+ values["LKA_ICON"] = 4 if lat_active else 3 if lat_enabled else 0
+
+ if values["ALERTS_2"] in [1, 2, 5, 6, 10, 21, 22]:
+ values["ALERTS_2"] = 0
+ values["DAW_ICON"] = 0
+
+ if values["ALERTS_1"] == 0:
+ values["SOUNDS_1"] = 0
+ values["SOUNDS_2"] = 0
+ values["SOUNDS_4"] = 0
+
+ if values["ALERTS_3"] in [3, 4, 11, 12, 13, 14, 17, 19, 26, 7, 8, 9, 10]:
+ values["ALERTS_3"] = 0
+ values["SOUNDS_3"] = 0
+
+ if values["ALERTS_5"] in [1, 2, 3, 4, 5]:
+ values["ALERTS_5"] = 0
+
+ ret.append(packer.make_can_msg("ADRV_0x161", CAN.ECAN, values, rx_counter=rx_counter))
+ return ret
+
+def create_acc_control_scc2(packer, CAN, enabled, accel_last, accel, stopping, gas_override, set_speed, hud_control, hyundai_jerk, CS):
+
+ if CS.scc_control is None:
+ return None
+ enabled = (enabled or CS.softHoldActive > 0) and CS.paddle_button_prev == 0
+
+ acc_mode = 0 if not enabled else (2 if gas_override else 1)
+
+ if hyundai_jerk.carrot_cruise == 1:
+ acc_mode = 4 if enabled else 0
+ enabled = False
+ accel = accel_last = 0.5
+
+ elif hyundai_jerk.carrot_cruise == 2:
+ accel = accel_last = hyundai_jerk.carrot_cruise_accel
+
+ jerk_u = hyundai_jerk.jerk_u
+ jerk_l = hyundai_jerk.jerk_l
jerk = 5
jn = jerk / 50
if not enabled or gas_override:
a_val, a_raw = 0, 0
else:
- a_raw = accel # noqa: F841
- a_val = np.clip(accel, accel_last - jn, accel_last + jn) # noqa: F841
+ a_raw = accel
+ a_val = accel #np.clip(accel, accel_last - jn, accel_last + jn)
+
+ values = copy.copy(CS.scc_control)
+ rx_counter = values.pop("COUNTER", None)
+ values["ACCMode"] = acc_mode
+ values["MainMode_ACC"] = 1
+ values["StopReq"] = 1 if stopping or CS.softHoldActive > 0 else 0 # 1: Stop control is required, 2: Not used, 3: Error Indicator
+ values["aReqValue"] = a_val
+ values["aReqRaw"] = a_raw
+ values["VSetDis"] = set_speed
+ #values["JerkLowerLimit"] = jerk if enabled else 1
+ #values["JerkUpperLimit"] = 3.0
+ values["JerkLowerLimit"] = jerk_l if enabled else 1
+ values["JerkUpperLimit"] = 2.0 if stopping or CS.softHoldActive else jerk_u
+ values["DISTANCE_SETTING"] = hud_control.leadDistanceBars # + 5
+ #values["DISTANCE_SETTING"] = hud_control.leadDistanceBars + 5
+
+ #values["ACC_ObjDist"] = 1
+ #values["ObjValid"] = 0
+ #values["OBJ_STATUS"] = 2
+ #values["NSCCOper"] = 1 if enabled else 0 # 0: off, 1: Ready, 2: Act, 3: Error Indicator
+ #values["NSCCOnOff"] = 2 # 0: Default, 1: Off, 2: On, 3: Invalid
+ #values["SET_ME_3"] = 0x3 # objRelsped와 충돌
+ #values["ACC_ObjLatPos"] = - hud_control.leadDPath
+ values["DriveMode"] = 0 # 0: Default, 1: Comfort Mode, 2:Normal mode, 3:Dynamic mode, reserved
+
+ hud_lead_info = 0
+ if hud_control.leadVisible:
+ hud_lead_info = 1 if values["ACC_ObjRelSpd"] > 0 else 2
+ values["HUD_LEAD_INFO"] = hud_lead_info #1: in-path object detected(uncontrollable), 2: controllable long, 3: controllable long & lat, ... reserved
+
+ values["DriverAlert"] = 0 # 1: SCC Disengaged, 2: No SCC Engage condition, 3: SCC Disenganed when the vehicle stops
+
+ values["TARGET_DISTANCE"] = CS.out.vEgo * 1.0 + 4.0
+
+ soft_hold_info = 1 if CS.softHoldActive > 1 and enabled else 0
+
+ # 이거안하면 정지중 뒤로 밀리는 현상 발생하는듯.. (신호정지중에 뒤로 밀리는 경험함.. 시험해봐야)
+ if values["InfoDisplay"] != 5: #5: Front Car Departure Notice
+ values["InfoDisplay"] = 4 if stopping and CS.out.aEgo > -0.3 else 0 # 1: SCC Mode, 2: Convention Cruise Mode, 3: Object disappered at low speed, 4: Available to resume acceleration control, 5: Front vehicle departure notice, 6: Reserved, 7: Invalid
+
+ values["TakeOverReq"] = 0 # 1: Takeover request, 2: Not used, 3: Error indicator , 이것이 켜지면 가속을 안하는듯함.
+ #values["NEW_SIGNAL_4"] = 9 if hud_control.leadVisible else 0
+ # AccelLimitBandUpper, Lower
+ values["SysFailState"] = 0 # 1: Performance degredation, 2: system temporairy unavailble, 3: SCC Service required , 눈이 묻어 레이더오류시... 2가 됨. 이때 가속을 안함...
+
+ values["AccelLimitBandUpper"] = 0.0 # 이값이 1.26일때 가속을 안하는 증상이 보임..
+ values["AccelLimitBandLower"] = 0.0
+
+ values["ZEROS_7"] = 1
+
+ return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
+
+def create_acc_control(packer, CAN, enabled, accel_last, accel, stopping, gas_override, set_speed, hud_control, jerk_u, jerk_l, CS):
+
+ enabled = enabled or CS.softHoldActive > 0
+ jerk = 5
+ jn = jerk / 50
+ if not enabled or gas_override:
+ a_val, a_raw = 0, 0
+ else:
+ a_raw = accel
+ a_val = np.clip(accel, accel_last - jn, accel_last + jn)
values = {
"ACCMode": 0 if not enabled else (2 if gas_override else 1),
- "MainMode_ACC": 1 if main_cruise_enabled else 0,
- "StopReq": 1 if tuning.stopping else 0,
- "aReqValue": tuning.actual_accel,
- "aReqRaw": tuning.actual_accel,
+ "MainMode_ACC": 1,
+ "StopReq": 1 if stopping or CS.softHoldActive > 0 else 0,
+ "aReqValue": a_val,
+ "aReqRaw": a_raw,
"VSetDis": set_speed,
- "JerkLowerLimit": tuning.jerk_lower,
- "JerkUpperLimit": tuning.jerk_upper,
+ #"JerkLowerLimit": jerk if enabled else 1,
+ #"JerkUpperLimit": 3.0,
+ "JerkLowerLimit": jerk_l if enabled else 1,
+ "JerkUpperLimit": jerk_u,
- "ACC_ObjDist": int(lead_data.lead_distance),
- "ACC_ObjRelSpd": lead_data.lead_rel_speed,
- "ObjValid": int(not lead_data.lead_visible),
- "SCC_ObjSta": 0 if not (enabled and lead_data.lead_visible) else (1 if gas_override else 2),
- "SET_ME_2": 0x4,
- "SET_ME_3": 0x3,
- "SET_ME_TMP_64": 0x64,
- "DISTANCE_SETTING": hud_control.leadDistanceBars,
+ "ACC_ObjDist": 1,
+ #"ObjValid": 0,
+ #"OBJ_STATUS": 2,
+ "NSCCOper": 0,
+ "NSCCOnOff": 2,
+ "DriveMode": 0,
+ #"SET_ME_3": 0x3,
+ "ACC_ObjLatPos": 0x64,
+ "DISTANCE_SETTING": hud_control.leadDistanceBars, # + 5,
+ "InfoDisplay": 4 if stopping and CS.out.cruiseState.standstill else 0,
}
return packer.make_can_msg("SCC_CONTROL", CAN.ECAN, values)
-def create_spas_messages(packer, CAN, left_blink, right_blink):
+def create_spas_messages(packer, CAN, frame, left_blink, right_blink):
ret = []
values = {
@@ -186,8 +464,10 @@ def create_spas_messages(packer, CAN, left_blink, right_blink):
return ret
-def create_fca_warning_light(packer, CAN, frame):
+def create_fca_warning_light(CP, packer, CAN, frame):
ret = []
+ if CP.flags & HyundaiFlags.CAMERA_SCC.value:
+ return ret
if frame % 2 == 0:
values = {
@@ -196,53 +476,100 @@ def create_fca_warning_light(packer, CAN, frame):
'SET_ME_FF': 0xff,
'SET_ME_FC': 0xfc,
'SET_ME_9': 0x9,
+ #'DATA102': 1,
}
ret.append(packer.make_can_msg("ADRV_0x160", CAN.ECAN, values))
return ret
+def create_tcs_messages(packer, CAN, CS):
+ ret = []
+ if CS.tcs is not None:
+ values = copy.copy(CS.tcs)
+ #rx_counter = values.pop("COUNTER", None)
+ values["DriverBraking"] = 0
+ values["NEW_SIGNAL_20"] = 0
+ values["NEW_SIGNAL_11"] = 0
+ values["DriverBrakingLowSens"] = 0
+ #values["NEW_SIGNAL_1"] = 0 # accel과 관련.. 옆두부 꺼지는것과 관련? 확인필요
+ #values["ACC_REQ"] = 1 # 옆두부 꺼지는것과 관련? 확인필요.. 항상 켜지게함..
+ values["NEW_SIGNAL_1"] = 0 if values["ACC_REQ"] == 1 else 1 # 옆두부..
+ #ret.append(packer.make_can_msg("TCS", CAN.CAM, values, rx_counter = rx_counter))
+ ret.append(packer.make_can_msg("TCS", CAN.CAM, values))
+ return ret
-def create_adrv_messages(packer, CAN, frame):
+def forward_button_message(packer, CAN, frame, CS, cruise_button, MainMode_ACC_trigger, LFA_trigger):
+ ret = []
+ if frame % 2 == 0:
+ if CS.cruise_buttons_msg is not None:
+ values = copy.copy(CS.cruise_buttons_msg)
+ # A held MAIN is reported on this bit and switches some clusters to LIMIT mode.
+ values["NORMAL_CRUISE_MAIN_BTN"] = 0
+ #rx_counter = values.pop("COUNTER", None)
+ cruise_button_driver = values["CRUISE_BUTTONS"]
+ if cruise_button_driver == 0:
+ values["CRUISE_BUTTONS"] = cruise_button
+ if MainMode_ACC_trigger > 0:
+ #values["ADAPTIVE_CRUISE_MAIN_BTN"] = 1
+ pass
+ elif LFA_trigger > 0:
+ values["LFA_BTN"] = 1
+
+ #ret.append(packer.make_can_msg(CS.cruise_btns_msg_canfd, CAN.CAM, values, rx_counter = rx_counter))
+ ret.append(packer.make_can_msg(CS.cruise_btns_msg_canfd, CAN.CAM, values))
+ return ret
+
+def create_adrv_messages(CP, packer, CAN, frame):
# messages needed to car happy after disabling
# the ADAS Driving ECU to do longitudinal control
ret = []
- values = {
- }
- ret.append(packer.make_can_msg("ADRV_0x51", CAN.ACAN, values))
+ if not CP.flags & HyundaiFlags.CAMERA_SCC.value:
+ values = {}
- ret.extend(create_fca_warning_light(packer, CAN, frame))
+ ret.extend(create_fca_warning_light(CP, packer, CAN, frame))
+ if frame % 5 == 0:
+ values = {
+ #'HDA_MODE1': 0x8,
+ 'HDA_MODE2': 0x1,
+ #'SET_ME_1C': 0x1c,
+ 'SET_ME_FF': 0xff,
+ #'SET_ME_TMP_F': 0xf,
+ #'SET_ME_TMP_F_2': 0xf,
+ #'DATA26': 1, #1
+ #'DATA32': 5, #5
+ }
+ ret.append(packer.make_can_msg("ADRV_0x1ea", CAN.ECAN, values))
- if frame % 5 == 0:
- values = {
- 'SET_ME_1C': 0x1c,
- 'SET_ME_FF': 0xff,
- 'SET_ME_TMP_F': 0xf,
- 'SET_ME_TMP_F_2': 0xf,
- }
- ret.append(packer.make_can_msg("ADRV_0x1ea", CAN.ECAN, values))
+ values = {
+ 'SET_ME_E1': 0xe1,
+ #'SET_ME_3A': 0x3a,
+ 'TauGapSet' : 1,
+ 'NEW_SIGNAL_2': 3,
+ }
+ ret.append(packer.make_can_msg("ADRV_0x200", CAN.ECAN, values))
- values = {
- 'SET_ME_E1': 0xe1,
- 'SET_ME_3A': 0x3a,
- }
- ret.append(packer.make_can_msg("ADRV_0x200", CAN.ECAN, values))
+ if frame % 20 == 0:
+ values = {
+ 'SET_ME_15': 0x15,
+ }
+ ret.append(packer.make_can_msg("ADRV_0x345", CAN.ECAN, values))
- if frame % 20 == 0:
- values = {
- 'SET_ME_15': 0x15,
- }
- ret.append(packer.make_can_msg("ADRV_0x345", CAN.ECAN, values))
-
- if frame % 100 == 0:
- values = {
- 'SET_ME_22': 0x22,
- 'SET_ME_41': 0x41,
- }
- ret.append(packer.make_can_msg("ADRV_0x1da", CAN.ECAN, values))
+ if frame % 100 == 0:
+ values = {
+ 'SET_ME_22': 0x22,
+ 'SET_ME_41': 0x41,
+ }
+ ret.append(packer.make_can_msg("ADRV_0x1da", CAN.ECAN, values))
return ret
+## carrot
+def alt_cruise_buttons(packer, CP, CAN, buttons, cruise_btns_msg, cnt):
+ cruise_btns_msg["CRUISE_BUTTONS"] = buttons
+ cruise_btns_msg["COUNTER"] = (cruise_btns_msg["COUNTER"] + 1 + cnt) % 256
+ bus = CAN.ECAN if CP.flags & HyundaiFlags.CANFD_HDA2 else CAN.CAM
+ return packer.make_can_msg("CRUISE_BUTTONS_ALT", bus, cruise_btns_msg)
def hkg_can_fd_checksum(address: int, sig, d: bytearray) -> int:
crc = 0
@@ -259,3 +586,348 @@ def hkg_can_fd_checksum(address: int, sig, d: bytearray) -> int:
elif len(d) == 32:
crc ^= 0x9F5B
return crc
+
+
+
+
+def _clip_int(x, lo, hi):
+ return lo if x < lo else hi if x > hi else int(x)
+
+def _get_desire_and_lane_changing(md):
+ desire = 0
+ lane_changing = 0
+ if md is not None:
+ desire = md.meta.desire.raw
+ ds = md.meta.desireState
+ if len(ds) > 4:
+ if ds[1] > 0.9: lane_changing = 1
+ if ds[2] > 0.9: lane_changing = 2
+ if ds[3] > 0.9: lane_changing = 3
+ if ds[4] > 0.9: lane_changing = 4
+ return desire, lane_changing
+
+def _apply_lane_desire(values, desire):
+ #values['LANE_CHANGING'] = 0
+
+ if desire == 1: # 좌회전
+ values['LANE_CHANGING'] = 1
+ values["LANELINE_CURVATURE"] = 15
+ values["LANELINE_CURVATURE_DIRECTION"] = 0
+
+ elif desire == 2: # 우회전
+ values['LANE_CHANGING'] = 2
+ values["LANELINE_CURVATURE"] = 15
+ values["LANELINE_CURVATURE_DIRECTION"] = 1
+
+ elif desire == 3: # 좌차선변경
+ values['LANE_CHANGING'] = 3
+
+ elif desire == 4: # 우차선변경
+ values['LANE_CHANGING'] = 4
+
+def _apply_radar_blink(values, radar_pairs, frame, *,
+ disp_dist=30.0, min_dist=14.0,
+ max_interval=100, t=1.0):
+ """
+ 거리 > min_dist 일 때만 깜빡임.
+ 거리 멀수록 interval 커짐(느리게).
+ """
+ for det_key, dist_key in radar_pairs:
+ dist = values[dist_key]
+ if dist <= min_dist:
+ continue
+
+ d = min(dist, disp_dist)
+ interval = int((1 + (max_interval - 1) * (d / disp_dist)) * t)
+ interval = _clip_int(interval, 1, max_interval)
+
+ blink = (frame // interval) & 1
+ values[det_key] = 2 - blink
+ values[dist_key] = min_dist
+
+def _suppress_trailer_mode_warning(values, CS):
+ # Logs from IONIQ 9 show ALERTS_5=6 is the periodic
+ # "driver assistance limited in trailer mode" popup.
+ if CS.trailer_connected and values.get("ALERTS_5") == 6:
+ values["ALERTS_5"] = 0
+
+def _make_ccnc_values(values, CS, lat_active, frame, hud_control,
+ lane_line=True, corner_radar=True,
+ desire=0,
+ blink_pairs=None,
+ blink_t=1.0):
+ if lane_line:
+ curvature = round(CS.out.steeringAngleDeg / 3)
+ mag = min(abs(curvature), 15)
+ curv = mag + (-1 if curvature < 0 else 0)
+ direction = 1 if curvature < 0 else 0
+ values["LANELINE_CURVATURE"] = curv if lat_active else 0
+ values["LANELINE_CURVATURE_DIRECTION"] = direction if lat_active else 0
+ if desire:
+ _apply_lane_desire(values, desire)
+
+ if corner_radar:
+ radar_all = [
+ ('LF_DETECT', 'LF_DETECT_DISTANCE'),
+ ('RF_DETECT', 'RF_DETECT_DISTANCE'),
+ ('LR_DETECT', 'LR_DETECT_DISTANCE'),
+ ('RR_DETECT', 'RR_DETECT_DISTANCE'),
+ ]
+ for det_key, dist_key in radar_all:
+ if values[det_key] >= 4 and values[dist_key] != 0:
+ values[det_key] = 1
+
+ if blink_pairs:
+ _apply_radar_blink(values, blink_pairs, frame, t=blink_t)
+
+def create_ccnc_messages(CP, packer, CAN, frame, CC, CS, hud_control,
+ disp_angle, left_lane_warning, right_lane_warning,
+ enable_corner_radar, stopping, canfd_debug):
+ ret = []
+
+ md = CS.modelV2
+ if not hasattr(create_ccnc_messages, '_lane_line_check') or frame % 100 == 0:
+ create_ccnc_messages._lane_line_check = Params().get_int("LaneLineCheck")
+ lane_line_check = create_ccnc_messages._lane_line_check
+ desire, lane_changing = _get_desire_and_lane_changing(md)
+
+ if CP.flags & HyundaiFlags.CAMERA_SCC.value:
+ HDA_CntrlModSta = 0
+ HDA_LFA_SymSta = 0
+ if CS.lfahda_cluster is not None:
+ HDA_CntrlModSta = CS.lfahda_cluster["HDA_CntrlModSta"]
+ HDA_LFA_SymSta = CS.lfahda_cluster["HDA_LFA_SymSta"]
+
+ if frame % 2 == 0:
+ #if CS.adrv_0x160 is not None:
+ # values = copy.copy(CS.adrv_0x160)
+ # ret.append(packer.make_can_msg("ADRV_0x160", CAN.ECAN, values))
+
+ if CS.cruise_buttons_msg is not None:
+ values = copy.copy(CS.cruise_buttons_msg)
+ # Keep the physical long press on ECAN for CarState, but don't forward it to CAM.
+ values["NORMAL_CRUISE_MAIN_BTN"] = 0
+
+ if HDA_LFA_SymSta == 0 and 0 < frame % 200 < 12:
+ values["LFA_BTN"] = 1
+
+ if CC.enabled:
+ if not CS.MainMode_ACC:
+ if 10 < frame % 200 <= 16 and CS.out.vEgo > 3.:
+ values["ADAPTIVE_CRUISE_MAIN_BTN"] = 1
+ elif CS.ACCMode in [0, 4]:
+ if 10 < frame % 200 <= 16 and CS.out.vEgo > 3.:
+ values["CRUISE_BUTTONS"] = 2
+ elif CS.scc_control is not None and CS.scc_control["InfoDisplay"] == 4:
+ if 10 < frame % 30 <= 16 and not stopping:
+ values["CRUISE_BUTTONS"] = 2
+ else:
+ if CS.adrv_0x1ea is not None and CS.adrv_0x1ea["HDA_MODE2"] == 0: # if corner radar is disabled, send main btn
+ if 10 < frame % 1000 <= 16 and CS.out.vEgo > 3:
+ values["ADAPTIVE_CRUISE_MAIN_BTN"] = 1
+
+ ret.append(packer.make_can_msg(CS.cruise_btns_msg_canfd, CAN.CAM, values))
+
+ # --- 0x161/0x200/0x1ea/0x162 (frame%5) ---
+ if frame % 5 == 0:
+ lat_active = CC.latActive
+
+ if CS.adrv_0x161 is not None:
+ main_enabled = CS.out.cruiseState.available
+ cruise_enabled = CC.enabled
+ lat_enabled = CS.out.latEnabled
+ nav_active = hud_control.activeCarrot > 1
+
+ # hdpuse carrot
+ hdp_use = int(Params().get("HDPuse"))
+ hdp_active = False
+ if hdp_use == 1:
+ hdp_active = cruise_enabled and nav_active
+ elif hdp_use == 2:
+ hdp_active = cruise_enabled
+ # hdpuse carrot
+
+ values = copy.copy(CS.adrv_0x161)
+ rx_counter = values.pop("COUNTER", None)
+ values["SETSPEED"] = (6 if hdp_active else 3 if cruise_enabled else 1) if main_enabled else 0
+ values["SETSPEED_HUD"] = (5 if hdp_active else 3 if cruise_enabled else 1) if main_enabled else 0
+
+ set_speed_in_units = hud_control.setSpeed * (CV.MS_TO_KPH if CS.is_metric else CV.MS_TO_MPH)
+ values["vSetDis"] = int(set_speed_in_units + 0.5)
+
+ values["DISTANCE"] = 4 if hdp_active else hud_control.leadDistanceBars
+ values["DISTANCE_LEAD"] = 2 if cruise_enabled and hud_control.leadVisible else 1 if main_enabled and hud_control.leadVisible else 0
+ values["DISTANCE_CAR"] = 3 if hdp_active else 2 if cruise_enabled else 1 if main_enabled else 0
+ values["DISTANCE_SPACING"] = 5 if hdp_active else 1 if cruise_enabled else 0
+
+ values["TARGET"] = 1 if hud_control.leadVisible and cruise_enabled else 0
+ values["TARGET_DISTANCE"] = int(hud_control.leadDistance)
+
+ values["BACKGROUND"] = 6 if CS.paddle_button_prev > 0 else 1 if cruise_enabled else 3 if lat_active else 7
+ values["CENTERLINE"] = 1 if HDA_CntrlModSta > 0 else 0
+ values["CAR_CIRCLE"] = 2 if hdp_active else 1 if cruise_enabled else 0
+
+ values["NAV_ICON"] = 2 if nav_active and cruise_enabled else 1 if main_enabled and nav_active else 0
+ values["HDA_ICON"] = 5 if hdp_active else 2 if cruise_enabled else 1 if main_enabled else 0
+ values["LFA_ICON"] = 5 if hdp_active else 2 if lat_active else 1 if lat_enabled else 0
+ values["LKA_ICON"] = 4 if lat_active else 3 if lat_enabled else 0
+ values["FCA_ALT_ICON"] = 0
+
+ if values["ALERTS_2"] in [1, 2, 5, 6, 10, 21, 22]:
+ values["ALERTS_2"] = 0
+ values["DAW_ICON"] = 0
+
+ if values["ALERTS_1"] == 0: # alerts가 있으면 사운드도 같이 나옴
+ values["SOUNDS_1"] = 0
+ values["SOUNDS_2"] = 0
+ values["SOUNDS_4"] = 0
+
+ if values["ALERTS_3"] in [3, 4, 11, 12, 13, 14, 17, 19, 20, 26, 27, 28, 7, 8, 9, 10]: # hide gap distance msg.(11,12,13,14), lanechange(19,20,27, 28)
+ values["ALERTS_3"] = 0
+ values["SOUNDS_3"] = 0
+
+ if values["ALERTS_5"] in [1, 2, 3, 4, 5]:
+ values["ALERTS_5"] = 0
+
+ if values["ALERTS_5"] in [11] and CS.softHoldActive == 0:
+ values["ALERTS_5"] = 0
+
+ # curvature 표시(0x161쪽 기존 로직 유지)
+ _suppress_trailer_mode_warning(values, CS)
+
+ curvature = round(CS.out.steeringAngleDeg / 3)
+ values["LANELINE_CURVATURE"] = (min(abs(curvature), 15) + (-1 if curvature < 0 else 0)) if lat_active else 0
+ values["LANELINE_CURVATURE_DIRECTION"] = 1 if curvature < 0 and lat_active else 0
+
+ trailer_lane_change_blocked = CS.trailer_connected
+ if trailer_lane_change_blocked:
+ values["LANELINE_LEFT"] = 2 if hud_control.leftLaneVisible else 0
+ values["LANELINE_RIGHT"] = 2 if hud_control.rightLaneVisible else 0
+ else:
+ lane_color = 6 if md is not None and md.meta.laneChangeAvailableLeft else 2
+ if lane_line_check >= 1:
+ lane_line_warn_left = CS.out.leftLaneLine % 10 not in (0, 5)
+ else:
+ lane_line_warn_left = CS.out.leftLaneLine // 10 == 2
+ lane_color = 4 if lane_line_warn_left or CS.out.leftBlindspot else lane_color
+ if hud_control.leftLaneDepart:
+ values["LANELINE_LEFT"] = 4 if (frame // 50) % 2 == 0 else 1
+ else:
+ values["LANELINE_LEFT"] = lane_color if hud_control.leftLaneVisible else 0
+
+ lane_color = 6 if md is not None and md.meta.laneChangeAvailableRight else 2
+ if lane_line_check >= 1:
+ lane_line_warn_right = CS.out.rightLaneLine % 10 not in (0, 5)
+ else:
+ lane_line_warn_right = CS.out.rightLaneLine // 10 == 2
+ lane_color = 4 if lane_line_warn_right or CS.out.rightBlindspot else lane_color
+ if hud_control.rightLaneDepart:
+ values["LANELINE_RIGHT"] = 4 if (frame // 50) % 2 == 0 else 1
+ else:
+ values["LANELINE_RIGHT"] = lane_color if hud_control.rightLaneVisible else 0
+
+ values["LCA_LEFT_ARROW"] = 2 if CS.out.leftBlinker else 0
+ values["LCA_RIGHT_ARROW"] = 2 if CS.out.rightBlinker else 0
+
+ if trailer_lane_change_blocked:
+ values["LCA_LEFT_ICON"] = 1 if lat_active else 0
+ values["LCA_RIGHT_ICON"] = 1 if lat_active else 0
+ else:
+ values["LCA_LEFT_ICON"] = (1 if CS.out.leftBlindspot else 2) if lat_active else 0
+ values["LCA_RIGHT_ICON"] = (1 if CS.out.rightBlindspot else 2) if lat_active else 0
+
+ values["LANE_LEFT"] = 0 if trailer_lane_change_blocked else 1 if desire in (1, 3) else 0
+ values["LANE_RIGHT"] = 0 if trailer_lane_change_blocked else 1 if desire in (2, 4) else 0
+
+ ret.append(packer.make_can_msg("ADRV_0x161", CAN.ECAN, values, rx_counter = rx_counter))
+
+ if CS.adrv_0x200 is not None:
+ values = copy.copy(CS.adrv_0x200)
+ rx_counter = values.pop("COUNTER", None)
+ values["TauGapSet"] = hud_control.leadDistanceBars
+ ret.append(packer.make_can_msg("ADRV_0x200", CAN.ECAN, values, rx_counter = rx_counter))
+
+ if CS.adrv_0x1ea is not None:
+ values = copy.copy(CS.adrv_0x1ea)
+ rx_counter = values.pop("COUNTER", None)
+ # blinker hold
+ values['LEFT_BLINK_HOLD'] = 1 if lane_changing == 3 else 0
+ values['RIGHT_BLINK_HOLD'] = 1 if lane_changing == 4 else 0
+
+ _make_ccnc_values(
+ values, CS, lat_active, frame, hud_control,
+ lane_line=True,
+ corner_radar=True,
+ desire=desire,
+ # 기존대로 LR/RR만 깜빡임
+ blink_pairs=[('LR_DETECT', 'LR_DETECT_DISTANCE'),
+ ('RR_DETECT', 'RR_DETECT_DISTANCE')],
+ blink_t=1.0
+ )
+
+ ret.append(packer.make_can_msg("ADRV_0x1ea", CAN.ECAN, values, rx_counter = rx_counter))
+
+ if CS.ccnc_0x162 is not None:
+ values = copy.copy(CS.ccnc_0x162)
+
+ if hud_control.leadDistance > 0:
+ values["FF_DISTANCE"] = hud_control.leadDistance
+ ff_type = 3 if hud_control.leadRadar == 1 else 13
+ values["FF_DETECT"] = ff_type if hud_control.leadRelSpeed > -0.1 else ff_type + 1
+
+ _make_ccnc_values(
+ values, CS, lat_active, frame, hud_control,
+ lane_line=False,
+ corner_radar=True,
+ desire=0,
+ # 필요하면 162도 깜빡임 적용(원래 코드처럼 LR/RR만)
+ blink_pairs=[('LR_DETECT', 'LR_DETECT_DISTANCE'),
+ ('RR_DETECT', 'RR_DETECT_DISTANCE')],
+ blink_t=1.0
+ )
+
+ if (left_lane_warning and not CS.out.leftBlinker) or (right_lane_warning and not CS.out.rightBlinker):
+ values["VIBRATE"] = 1
+
+ if canfd_debug > 0:
+ values["FAULT_LSS"] = 0
+ values["FAULT_DAS"] = 0
+
+ ret.append(packer.make_can_msg("CCNC_0x162", CAN.ECAN, values))
+
+ # --- NEW_MSG_4B9 (corner radar keep-alive?) ---
+ if enable_corner_radar > 0:
+ if HDA_CntrlModSta == 0:
+ if frame % 500 in [10, 20, 30]:
+ values = {
+ 'BYTE_1': 0,
+ 'BYTE_2': 0,
+ 'BYTE_3': 0x80,
+ 'BYTE_4': 0x8A,
+ 'BYTE_5': 0x32,
+ 'BYTE_6': 0x30,
+ 'BYTE_7': 0x01,
+ 'BYTE_8': 0x00,
+ }
+ ret.append(packer.make_can_msg("NEW_MSG_4B9", CAN.CAM, values))
+ elif frame % 500 in [40, 50, 60]:
+ values = {
+ 'BYTE_1': 0xff,
+ 'BYTE_2': 0xff,
+ 'BYTE_3': 0xff,
+ 'BYTE_4': 0xff,
+ 'BYTE_5': 0xff,
+ 'BYTE_6': 0xff,
+ 'BYTE_7': 0xff,
+ 'BYTE_8': 0xff,
+ }
+ ret.append(packer.make_can_msg("NEW_MSG_4B9", CAN.CAM, values))
+
+ if False: # canfd_debug > 1 and frame % 20 == 0:
+ if CS.hda_info_4a3 is not None:
+ values = copy.copy(CS.hda_info_4a3)
+ values["LinkClass"] = 1
+ values["SPEED_LIMIT"] = 100
+ ret.append(packer.make_can_msg("HDA_INFO_4A3", CAN.CAM, values))
+
+ return ret
diff --git a/iqdbc_repo/iqdbc/car/hyundai/interface.py b/iqdbc_repo/iqdbc/car/hyundai/interface.py
index fbc20a4..8dc5b9a 100644
--- a/iqdbc_repo/iqdbc/car/hyundai/interface.py
+++ b/iqdbc_repo/iqdbc/car/hyundai/interface.py
@@ -1,8 +1,10 @@
-from iqdbc.car import Bus, get_safety_config, structs, uds
+from iqdbc.car import Bus, get_safety_config, structs
from iqdbc.car.hyundai.hyundaicanfd import CanBus
-from iqdbc.car.hyundai.values import HyundaiFlags, CAR, DBC, \
+from iqdbc.car.hyundai.values import HyundaiFlags, HyundaiFlagsIQ, CAR, DBC, CANFD_RADAR_SCC_CAR, \
CANFD_UNSUPPORTED_LONGITUDINAL_CAR, \
- UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags
+ UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags, HyundaiSafetyFlagsIQ, HyundaiExtFlags, \
+ CANFD_HYBRID_STATUS_ADDR, CANFD_HYBRID_STATUS_DLC, \
+ EV_MODE_STATUS_ADDR, EV_MODE_STATUS_DLC
from iqdbc.car.hyundai.radar_interface import RADAR_START_ADDR
from iqdbc.car.interfaces import CarInterfaceBase
from iqdbc.car.disable_ecu import disable_ecu
@@ -10,9 +12,7 @@ from iqdbc.car.hyundai.carcontroller import CarController
from iqdbc.car.hyundai.carstate import CarState
from iqdbc.car.hyundai.radar_interface import RadarInterface
-from iqdbc.lvbs.car.hyundai.escc import ESCC_MSG
-from iqdbc.lvbs.car.hyundai.longitudinal.helpers import get_longitudinal_tune
-from iqdbc.lvbs.car.hyundai.values import HyundaiFlagsIQ, HyundaiSafetyFlagsIQ
+from openpilot.common.params import Params
ButtonType = structs.CarState.ButtonEvent.Type
Ecu = structs.CarParams.Ecu
@@ -20,67 +20,125 @@ Ecu = structs.CarParams.Ecu
# Cancel button can sometimes be ACC pause/resume button, main button can also enable on some cars
ENABLE_BUTTONS = (ButtonType.accelCruise, ButtonType.decelCruise, ButtonType.cancel, ButtonType.mainCruise)
+SteerControlType = structs.CarParams.SteerControlType
+
class CarInterface(CarInterfaceBase):
CarState = CarState
CarController = CarController
RadarInterface = RadarInterface
- DRIVABLE_GEARS = (structs.CarState.GearShifter.sport, structs.CarState.GearShifter.manumatic)
-
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams:
+
+ params = Params()
+ camera_scc = params.get_int("HyundaiCameraSCC")
+ if camera_scc > 0:
+ ret.flags |= HyundaiFlags.CAMERA_SCC.value
+ print("$$$CAMERA_SCC toggled...")
+
ret.brand = "hyundai"
- # "LKA steering" if LKAS or LKAS_ALT messages are seen coming from the camera.
- # Generally means our LKAS message is forwarded to another ECU (commonly ADAS ECU)
- # that finally retransmits our steering command in LFA or LFA_ALT to the MDPS.
- # "LFA steering" if camera directly sends LFA to the MDPS
- cam_can = CanBus(None, fingerprint).CAM
- lka_steering = 0x50 in fingerprint[cam_can] or 0x110 in fingerprint[cam_can]
- CAN = CanBus(None, fingerprint, lka_steering)
+ if candidate == CAR.KIA_SORENTO:
+ ret.extFlags |= HyundaiExtFlags.RADAR_GROUP4.value
+
+ cam_can = CanBus(None, fingerprint).CAM if camera_scc == 0 else 1
+ hda2 = False #0x50 in fingerprint[cam_can] or 0x110 in fingerprint[cam_can]
+ hda2 = hda2 or params.get_int("CanfdHDA2") > 0
+ CAN = CanBus(None, fingerprint, hda2)
if ret.flags & HyundaiFlags.CANFD:
# Shared configuration for CAN-FD cars
- ret.alphaLongitudinalAvailable = candidate not in CANFD_UNSUPPORTED_LONGITUDINAL_CAR
- if lka_steering and Ecu.adas not in [fw.ecu for fw in car_fw]:
- # this needs to be figured out for cars without an ADAS ECU
- ret.alphaLongitudinalAvailable = False
+ ret.alphaLongitudinalAvailable = True #candidate not in (CANFD_UNSUPPORTED_LONGITUDINAL_CAR | CANFD_RADAR_SCC_CAR)
+ #ret.enableBsm = 0x1e5 in fingerprint[CAN.ECAN]
+ ret.enableBsm = 0x1ba in fingerprint[CAN.ECAN] # BLINDSPOTS_REAR_CORNERS 0x1ba(442)
- ret.enableBsm = 0x1e5 in fingerprint[CAN.ECAN]
-
- # Check if the car is hybrid. Only HEV/PHEV cars have 0xFA on E-CAN.
- if 0xFA in fingerprint[CAN.ECAN]:
+ if 0x105 in fingerprint[CAN.ECAN]:
ret.flags |= HyundaiFlags.HYBRID.value
- if lka_steering:
- # detect LKA steering
- ret.flags |= HyundaiFlags.CANFD_LKA_STEERING.value
- if 0x110 in fingerprint[CAN.CAM]:
- ret.flags |= HyundaiFlags.CANFD_LKA_STEERING_ALT.value
+ # Keep drivetrain/safety classification unchanged: this capability is display-only and requires both exact ECAN frames.
+ has_ev_mode_status = fingerprint[CAN.ECAN].get(CANFD_HYBRID_STATUS_ADDR) == CANFD_HYBRID_STATUS_DLC and \
+ fingerprint[CAN.ECAN].get(EV_MODE_STATUS_ADDR) == EV_MODE_STATUS_DLC
+ if has_ev_mode_status:
+ ret.extFlags |= HyundaiExtFlags.EV_MODE_STATUS_230.value
+
+ if 203 in fingerprint[CAN.CAM]: # LFA_ALT
+ print("##### Anglecontrol detected (LFA_ALT)")
+ ret.flags |= HyundaiFlags.ANGLE_CONTROL.value
+
+ print("ACAN=", fingerprint[CAN.ACAN])
+
+ if 0x210 in fingerprint[CAN.ACAN]:
+ print("##### Radar Group 1 detected (0x210)")
+ ret.extFlags |= HyundaiExtFlags.RADAR_GROUP1.value
+ elif 0x400 in fingerprint[CAN.ACAN] and 0x41D in fingerprint[CAN.ACAN]:
+ print("##### Radar Group 3 detected (0x400-0x41D)")
+ ret.extFlags |= HyundaiExtFlags.RADAR_GROUP3.value
+ if all(fingerprint[CAN.ACAN].get(addr) == 32 for addr in range(0x235, 0x249)):
+ ret.extFlags |= HyundaiExtFlags.CORNER_RADAR_OBJECTS_235.value
+ print("##### Corner radar objects 0x235 group detected")
+ if all(fingerprint[CAN.ACAN].get(addr) == 32 for addr in range(0x180, 0x185)):
+ ret.extFlags |= HyundaiExtFlags.CORNER_RADAR_OBJECTS_180.value
+ print("##### Corner radar objects 0x180 group detected")
+ if all(fingerprint[CAN.ACAN].get(addr) == 32 for addr in tuple(range(0x430, 0x438)) + tuple(range(0x440, 0x448))):
+ ret.extFlags |= HyundaiExtFlags.CORNER_RADAR_OBJECTS_430.value
+ print("##### Corner radar objects 0x430/0x440 group detected")
+
+ # detect HDA2 with ADAS Driving ECU
+ if hda2:
+ print("$$$CANFD HDA2")
+ ret.flags |= HyundaiFlags.CANFD_HDA2.value
+ if camera_scc > 0:
+ if 0x110 in fingerprint[CAN.ACAN]:
+ ret.flags |= HyundaiFlags.CANFD_HDA2_ALT_STEERING.value
+ print("$$$CANFD ALT_STEERING1")
+ else:
+ if 0x110 in fingerprint[CAN.CAM]: # 0x110(272): LKAS_ALT
+ ret.flags |= HyundaiFlags.CANFD_HDA2_ALT_STEERING.value
+ print("$$$CANFD ALT_STEERING1")
+ ## carrot_todo: sorento:
+ if 0x2a4 not in fingerprint[CAN.CAM]: # 0x2a4(676): CAM_0x2a4
+ ret.flags |= HyundaiFlags.CANFD_HDA2_ALT_STEERING.value
+ print("$$$CANFD ALT_STEERING2")
+
+ ## carrot: canival 4th, no 0x1cf
+ if 0x1cf not in fingerprint[CAN.ECAN]: # 0x1cf(463): CRUISE_BUTTONS
+ ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value
+ print("$$$CANFD ALT_BUTTONS")
else:
- # no LKA steering
+ # non-HDA2
+ print("$$$CANFD non HDA2")
if 0x1cf not in fingerprint[CAN.ECAN]:
ret.flags |= HyundaiFlags.CANFD_ALT_BUTTONS.value
- if not ret.flags & HyundaiFlags.RADAR_SCC:
- ret.flags |= HyundaiFlags.CANFD_CAMERA_SCC.value
-
- # Some LKA steering cars have alternative messages for gear checks
+ print("$$$CANFD ALT_BUTTONS")
+ #if not ret.flags & HyundaiFlags.RADAR_SCC:
+ # ret.flags |= HyundaiFlags.CANFD_CAMERA_SCC.value
+ # print("$$$CANFD CAMERA_SCC")
+ # Some HDA2 cars have alternative messages for gear checks
# ICE cars do not have 0x130; GEARS message on 0x40 or 0x70 instead
- if 0x130 not in fingerprint[CAN.ECAN]:
- if 0x40 not in fingerprint[CAN.ECAN]:
- ret.flags |= HyundaiFlags.CANFD_ALT_GEARS_2.value
- else:
- ret.flags |= HyundaiFlags.CANFD_ALT_GEARS.value
+ if 0x40 in fingerprint[CAN.ECAN]: # 0x40(64): GEAR_ALT
+ ret.flags |= HyundaiFlags.CANFD_ALT_GEARS.value
+ print("$$$CANFD ALT_GEARS")
+ elif 69 in fingerprint[CAN.ECAN]: # Special case
+ ret.extFlags |= HyundaiExtFlags.CANFD_GEARS_69.value
+ print("$$$CANFD GEARS_69")
+ elif 112 in fingerprint[CAN.ECAN]: # carrot: eGV70
+ ret.flags |= HyundaiFlags.CANFD_ALT_GEARS_2.value
+ print("$$$CANFD ALT_GEARS_2")
+ elif 0x130 in fingerprint[CAN.ECAN]: # 0x130(304): GEAR_SHIFTER
+ print("$$$CANFD GEAR_SHIFTER present")
+ else:
+ ret.extFlags |= HyundaiExtFlags.CANFD_GEARS_NONE.value
+ print("$$$CANFD GEARS_NONE")
cfgs = [get_safety_config(structs.CarParams.SafetyModel.hyundaiCanfd), ]
if CAN.ECAN >= 4:
cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
ret.safetyConfigs = cfgs
- if ret.flags & HyundaiFlags.CANFD_LKA_STEERING:
+ if ret.flags & HyundaiFlags.CANFD_HDA2:
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CANFD_LKA_STEERING.value
- if ret.flags & HyundaiFlags.CANFD_LKA_STEERING_ALT:
+ if ret.flags & HyundaiFlags.CANFD_HDA2_ALT_STEERING:
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CANFD_LKA_STEERING_ALT.value
if ret.flags & HyundaiFlags.CANFD_ALT_BUTTONS:
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.CANFD_ALT_BUTTONS.value
@@ -89,56 +147,93 @@ class CarInterface(CarInterfaceBase):
else:
# Shared configuration for non CAN-FD cars
- ret.alphaLongitudinalAvailable = candidate not in UNSUPPORTED_LONGITUDINAL_CAR
+ ret.alphaLongitudinalAvailable = True #candidate not in (UNSUPPORTED_LONGITUDINAL_CAR | CAMERA_SCC_CAR)
ret.enableBsm = 0x58b in fingerprint[0]
+ print(f"$$$ enableBsm = {ret.enableBsm}")
# Send LFA message on cars with HDA
if 0x485 in fingerprint[2]:
ret.flags |= HyundaiFlags.SEND_LFA.value
+ print("$$$SEND_LFA")
# These cars use the FCA11 message for the AEB and FCW signals, all others use SCC12
if 0x38d in fingerprint[0] or 0x38d in fingerprint[2]:
ret.flags |= HyundaiFlags.USE_FCA.value
+ print("$$$USE_FCA")
if ret.flags & HyundaiFlags.LEGACY:
# these cars require a special panda safety mode due to missing counters and checksums in the messages
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hyundaiLegacy)]
+ print("$$$Legacy Safety Model")
else:
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hyundai, 0)]
if ret.flags & HyundaiFlags.CAMERA_SCC:
ret.safetyConfigs[0].safetyParam |= HyundaiSafetyFlags.CAMERA_SCC.value
-
- # These cars have the LFA button on the steering wheel
- if 0x391 in fingerprint[0]:
- ret.flags |= HyundaiFlags.HAS_LDA_BUTTON.value
+ print("$$$CAMERA_SCC")
# Common lateral control setup
ret.centerToFront = ret.wheelbase * 0.4
ret.steerActuatorDelay = 0.1
ret.steerLimitTimer = 0.4
- CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
+ if ret.flags & HyundaiFlags.ANGLE_CONTROL:
+ ret.steerControlType = SteerControlType.angle
+ else:
+ CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
if ret.flags & HyundaiFlags.ALT_LIMITS:
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.ALT_LIMITS.value
- if ret.flags & HyundaiFlags.ALT_LIMITS_2:
- ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.ALT_LIMITS_2.value
-
- # see https://github.com/commaai/iqdbc/pull/1137/
- ret.dashcamOnly = True
-
# Common longitudinal control setup
ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or Bus.radar not in DBC[ret.carFingerprint]
ret.openpilotLongitudinalControl = alpha_long and ret.alphaLongitudinalAvailable
+
+ # carrot, if camera_scc enabled, enable openpilotLongitudinalControl
+ enable_radar_tracks = params.get_int("EnableRadarTracks")
+ if ret.flags & HyundaiFlags.CAMERA_SCC.value or enable_radar_tracks > 0 or enable_radar_tracks == -2:
+ ret.radarUnavailable = False
+ ret.openpilotLongitudinalControl = True if camera_scc < 3 else False
+ print(f"$$$OenpilotLongitudinalControl = True, CAMERA_SCC({ret.flags & HyundaiFlags.CAMERA_SCC.value}) or RadarTracks{enable_radar_tracks}")
+ else:
+ print(f"$$$OenpilotLongitudinalControl = {alpha_long}")
+
+ #ret.radarUnavailable = False # TODO: canfd... carrot, hyundai cars have radar
+
+ ret.radarTimeStep = 0.05 #if params.get_int("EnableRadarTracks") > 0 else 0.02
+
ret.pcmCruise = not ret.openpilotLongitudinalControl
- ret.startingState = True
+ ret.startingState = False # True # carrot
ret.vEgoStarting = 0.1
ret.startAccel = 1.0
ret.longitudinalActuatorDelay = 0.5
+ ret.longitudinalTuning.kpBP = [0.]
+ ret.longitudinalTuning.kpV = [1.]
+ ret.longitudinalTuning.kf = 1.0
+
+ # *** feature detection ***
+ if ret.flags & HyundaiFlags.CANFD:
+ print(f"$$$$$ CanFD ECAN = {CAN.ECAN}")
+ if 0x1fa in fingerprint[CAN.ECAN]:
+ ret.extFlags |= HyundaiExtFlags.NAVI_CLUSTER.value
+ print("$$$$ NaviCluster = True")
+ else:
+ print("$$$$ NaviCluster = False")
+
+ else:
+ if 1348 in fingerprint[0]:
+ ret.extFlags |= HyundaiExtFlags.NAVI_CLUSTER.value
+ print("$$$$ NaviCluster = True")
+ if 1157 in fingerprint[0] or 1157 in fingerprint[2]:
+ ret.extFlags |= HyundaiExtFlags.HAS_LFAHDA.value
+ print("$$$$ HasLFAHDA")
+ if 1007 in fingerprint[0]:
+ print("#### cruiseButtonAlt")
+
+ print(f"$$$$ enableBsm = {ret.enableBsm}")
+
if ret.openpilotLongitudinalControl:
ret.safetyConfigs[-1].safetyParam |= HyundaiSafetyFlags.LONG.value
if ret.flags & HyundaiFlags.HYBRID:
@@ -155,95 +250,64 @@ class CarInterface(CarInterfaceBase):
# Dashcam cars are missing a test route, or otherwise need validation
# TODO: Optima Hybrid 2017 uses a different SCC12 checksum
- if candidate in (CAR.KIA_OPTIMA_H,):
- ret.dashcamOnly = True
+ #ret.dashcamOnly = candidate in {CAR.KIA_OPTIMA_H, }
return ret
@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:
- # identical logic used in _get_params
- # "LKA steering" if LKAS or LKAS_ALT messages are seen coming from the camera.
- # Generally means our LKAS message is forwarded to another ECU (commonly ADAS ECU)
- # that finally retransmits our steering command in LFA or LFA_ALT to the MDPS.
- # "LFA steering" if camera directly sends LFA to the MDPS
- cam_can = CanBus(None, fingerprint).CAM
- lka_steering = 0x50 in fingerprint[cam_can] or 0x110 in fingerprint[cam_can]
- CAN = CanBus(None, fingerprint, lka_steering)
-
- if not stock_cp.flags & HyundaiFlags.CANFD:
- # TODO-IQ: add route with ESCC message for process replay
- if ESCC_MSG in fingerprint[0]:
- ret.flags |= HyundaiFlagsIQ.ENHANCED_SCC.value
-
- if ret.flags & HyundaiFlagsIQ.ENHANCED_SCC:
- ret.iqSafetyFlags |= HyundaiSafetyFlagsIQ.ESCC
- stock_cp.radarUnavailable = False
-
- if stock_cp.flags & HyundaiFlags.HAS_LDA_BUTTON:
+ def _get_params_iq(stock_cp, ret, candidate, fingerprint, car_fw, alpha_long, is_release_iq, docs):
+ del candidate, car_fw, alpha_long, is_release_iq, docs
+ if not stock_cp.flags & HyundaiFlags.CANFD and 0x391 in fingerprint[0]:
+ ret.flags |= HyundaiFlagsIQ.HAS_LFA_BUTTON
ret.iqSafetyFlags |= HyundaiSafetyFlagsIQ.HAS_LDA_BUTTON
-
- if stock_cp.flags & (HyundaiFlags.CANFD_CAMERA_SCC | HyundaiFlags.CAMERA_SCC):
- stock_cp.radarUnavailable = False
-
- if stock_cp.flags & HyundaiFlags.ALT_LIMITS_2:
- stock_cp.dashcamOnly = False
-
- if ret.flags & HyundaiFlagsIQ.NON_SCC:
- stock_cp.alphaLongitudinalAvailable = False
- stock_cp.openpilotLongitudinalControl = False
- stock_cp.pcmCruise = True
- ret.iqSafetyFlags |= HyundaiSafetyFlagsIQ.NON_SCC
-
- # untested non-SCC platforms, need user validations
- if stock_cp.carFingerprint in (CAR.HYUNDAI_BAYON_1ST_GEN_NON_SCC, CAR.KIA_FORTE_2021_NON_SCC,
- CAR.KIA_SELTOS_2023_NON_SCC, CAR.GENESIS_G70_2021_NON_SCC):
- stock_cp.dashcamOnly = True
-
- if stock_cp.flags & HyundaiFlags.CANFD:
- if 0x1fa in fingerprint[CAN.ECAN]:
- ret.flags |= HyundaiFlagsIQ.SPEED_LIMIT_AVAILABLE.value
- else:
- # Detect smartMDPS, which bypasses EPS low-speed lockout, allowing iqpilot to send steering commands down to 0
- if 0x2AA in fingerprint[0]:
- stock_cp.minSteerSpeed = 0.0
- stock_cp.flags &= ~HyundaiFlags.MIN_STEER_32_MPH.value
-
- if 0x544 in fingerprint[0]:
- ret.flags |= HyundaiFlagsIQ.SPEED_LIMIT_AVAILABLE.value
-
- if 0x53E in fingerprint[2]:
- ret.flags |= HyundaiFlagsIQ.HAS_LKAS12.value
-
-
return ret
@staticmethod
- def _get_longitudinal_tuning_iq(stock_cp: structs.CarParams, ret: structs.IQCarParams) -> structs.IQCarParams:
- if ret.flags & (HyundaiFlagsIQ.LONG_TUNING_DYNAMIC | HyundaiFlagsIQ.LONG_TUNING_PREDICTIVE):
- get_longitudinal_tune(stock_cp)
+ def init(CP, can_recv, can_send):
- return ret
+ Params().put_int('LongitudinalPersonalityMax', 4)
- @staticmethod
- def init(CP, CP_IQ, can_recv, can_send, communication_control=None):
- # 0x80 silences response
- if communication_control is None:
- communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, 0x80 | uds.CONTROL_TYPE.DISABLE_RX_DISABLE_TX, uds.MESSAGE_TYPE.NORMAL])
-
- if CP.openpilotLongitudinalControl and not ((CP.flags & (HyundaiFlags.CANFD_CAMERA_SCC | HyundaiFlags.CAMERA_SCC)) or
- (CP_IQ.flags & HyundaiFlagsIQ.ENHANCED_SCC)):
- addr, bus = 0x7d0, CanBus(CP).ECAN if CP.flags & HyundaiFlags.CANFD else 0
- if CP.flags & HyundaiFlags.CANFD_LKA_STEERING.value:
+ if CP.openpilotLongitudinalControl and not (CP.flags & HyundaiFlags.CANFD_CAMERA_SCC):
+ addr, bus = 0x7d0, 0
+ if CP.flags & HyundaiFlags.CANFD_HDA2.value:
addr, bus = 0x730, CanBus(CP).ECAN
- disable_ecu(can_recv, can_send, bus=bus, addr=addr, com_cont_req=communication_control)
+ disable_ecu(can_recv, can_send, bus=bus, addr=addr, com_cont_req=b'\x28\x83\x01')
+
+ params = Params()
+ if params.get_int("EnableRadarTracks") > 0 and not CP.flags & HyundaiFlags.CANFD:
+ result = enable_radar_tracks(CP, can_recv, can_send)
+ params.put_bool("EnableRadarTracksResult", result)
# for blinkers
if CP.flags & HyundaiFlags.ENABLE_BLINKERS:
- disable_ecu(can_recv, can_send, bus=CanBus(CP).ECAN, addr=0x7B1, com_cont_req=communication_control)
+ disable_ecu(can_recv, can_send, bus=CanBus(CP).ECAN, addr=0x7B1, com_cont_req=b'\x28\x83\x01')
- @staticmethod
- def deinit(CP, can_recv, can_send):
- communication_control = bytes([uds.SERVICE_TYPE.COMMUNICATION_CONTROL, 0x80 | uds.CONTROL_TYPE.ENABLE_RX_ENABLE_TX, uds.MESSAGE_TYPE.NORMAL])
- CarInterface.init(CP, can_recv, can_send, communication_control)
+def enable_radar_tracks(CP, logcan, sendcan):
+ from iqdbc.car.isotp_parallel_query import IsoTpParallelQuery
+ print("################ Try To Enable Radar Tracks ####################")
+
+ ret = False
+ sccBus = 2 if CP.flags & HyundaiFlags.CAMERA_SCC.value else 0
+ rdr_fw = None
+ rdr_fw_address = 0x7d0 #
+ try:
+ try:
+ query = IsoTpParallelQuery(sendcan, logcan, sccBus, [rdr_fw_address], [b'\x10\x07'], [b'\x50\x07'])
+ for addr, dat in query.get_data(0.1).items(): # pylint: disable=unused-variable
+ print("ecu write data by id ...")
+ new_config = b"\x00\x00\x00\x01\x00\x01"
+ #new_config = b"\x00\x00\x00\x00\x00\x01"
+ dataId = b'\x01\x42'
+ WRITE_DAT_REQUEST = b'\x2e'
+ WRITE_DAT_RESPONSE = b'\x68'
+ query = IsoTpParallelQuery(sendcan, logcan, sccBus, [rdr_fw_address], [WRITE_DAT_REQUEST+dataId+new_config], [WRITE_DAT_RESPONSE])
+ result = query.get_data(0)
+ print("result=", result)
+ ret = True
+ break
+ except Exception as e:
+ print(f"Failed : {e}")
+ except Exception as e:
+ print("############## Failed to enable tracks" + str(e))
+ print("################ END Try to enable radar tracks")
+ return ret
diff --git a/iqdbc_repo/iqdbc/car/hyundai/radar_interface.py b/iqdbc_repo/iqdbc/car/hyundai/radar_interface.py
index 3616bcc..7aab917 100644
--- a/iqdbc_repo/iqdbc/car/hyundai/radar_interface.py
+++ b/iqdbc_repo/iqdbc/car/hyundai/radar_interface.py
@@ -1,86 +1,885 @@
import math
+import os
+from collections import deque
+from iqdbc import DBC_PATH
from iqdbc.can import CANParser
from iqdbc.car import Bus, structs
from iqdbc.car.interfaces import RadarInterfaceBase
-from iqdbc.car.hyundai.values import DBC
-
-from iqdbc.lvbs.car.hyundai.radar_interface_ext import RadarInterfaceExt
+from iqdbc.car.hyundai.values import DBC, HyundaiFlags, HyundaiExtFlags
+from openpilot.common.params import Params
+from iqdbc.car.hyundai.hyundaicanfd import CanBus
+from openpilot.common.filter_simple import MyMovingAverage
+SCC_TID = 0
RADAR_START_ADDR = 0x500
RADAR_MSG_COUNT = 32
+RADAR_MSG_COUNT4 = 8
+RADAR_GROUP4_MAX_LONG_DIST = 325.0
+RADAR_GROUP4_MAX_YREL = 6.0
+RADAR_START_ADDR_CANFD1 = 0x210
+RADAR_MSG_COUNT1 = 16
+RADAR_START_ADDR_CANFD2 = 0x3A5 # Group 2, Group 1: 0x210 2개씩?어???단 보류.
+RADAR_MSG_COUNT2 = 32
+RADAR_START_ADDR_CANFD3 = 0x400
+RADAR_MSG_COUNT3 = 30
+CORNER_OBJECT_235_START_ADDR = 0x235
+CORNER_OBJECT_235_MSG_COUNT = 20
+CORNER_OBJECT_235_TRACK_ID_OFFSET = 200
+CORNER_OBJECT_235_DBC = 'hyundai_canfd_corner_radar_235_generated'
+CORNER_OBJECT_180_START_ADDR = 0x180
+CORNER_OBJECT_180_MSG_COUNT = 5
+CORNER_OBJECT_180_SLOTS_PER_MSG = 2
+CORNER_OBJECT_180_TRACK_ID_OFFSET = 240
+CORNER_OBJECT_180_DBC = 'hyundai_canfd_corner_radar_180_generated'
+CORNER_OBJECT_430_LEFT_START_ADDR = 0x430
+CORNER_OBJECT_430_RIGHT_START_ADDR = 0x440
+CORNER_OBJECT_430_MSG_COUNT_PER_SIDE = 8
+CORNER_OBJECT_430_SLOTS_PER_MSG = 7
+CORNER_OBJECT_430_TRACK_ID_OFFSET = 300
+CORNER_OBJECT_430_DBC = 'hyundai_canfd_corner_radar_430_generated'
+CORNER_OBJECT_430_EMPTY_RAW_VALUES = (0x010d1f40, 0x00010d1f)
+CORNER_OBJECT_430_DEFAULT_DISTANCE_RAW_MIN = 2520 # 126.0 m
+CORNER_OBJECT_430_DEFAULT_DISTANCE_RAW_MAX = 2600 # 130.0 m
+CORNER_OBJECT_430_MAX_DREL = 120.0
+CORNER_OBJECT_430_MAX_TRACKS_PER_SIDE = 4
+CORNER_OBJECT_430_DT = 0.05
+CORNER_OBJECT_430_MAX_DREL_DELTA = 1.5
+CORNER_OBJECT_430_CANDIDATE_META_BYTE_3 = (2,)
+CORNER_OBJECT_430_CANDIDATE_EXCLUDED_SLOTS = (1,)
+CORNER_OBJECT_430_CANDIDATE_RAW_DELTA = 200
+CORNER_OBJECT_430_STRONG_META_BYTE_2 = (10,)
+CORNER_OBJECT_430_WEAK_META_BYTE_2 = (5, 6, 7, 8, 9)
+CORNER_OBJECT_430_STRONG_MIN_SUPPORT = 2
+CORNER_OBJECT_430_WEAK_MIN_SUPPORT = 3
+CORNER_OBJECT_430_CLUSTER_RAW_GAP = 200
+CORNER_OBJECT_430_TRACK_MATCH_MAX_DREL_DELTA = 3.0
+CORNER_OBJECT_430_MAX_ABS_VREL = 20.0
+CORNER_OBJECT_430_MAX_ABS_YVREL = 3.0
+CORNER_OBJECT_430_VREL_ALPHA = 0.35
+CORNER_OBJECT_430_YVREL_ALPHA = 0.35
+CORNER_OBJECT_430_LATERAL_CELL_MSG_WEIGHT = 0.35
+CORNER_OBJECT_430_LATERAL_CELL_SLOT_WEIGHT = 0.65
+CORNER_OBJECT_430_YREL_OFFSET = 5.8
+CORNER_OBJECT_430_YREL_SCALE = 1.1
+CORNER_OBJECT_430_RIGHT_CELL_MIRROR = 7.0
+CORNER_OBJECT_430_MIN_ABS_YREL = 0.8
+CORNER_OBJECT_430_MAX_ABS_YREL = 4.2
+CORNER_OBJECT_430_HISTORY_SIZE = 8
+CORNER_OBJECT_430_MIN_HISTORY = 5
+CORNER_OBJECT_430_MIN_INWARD_YREL_DELTA = 0.35
+CORNER_OBJECT_430_MIN_RECENT_INWARD_YREL_DELTA = 0.05
+CORNER_OBJECT_430_MIN_INWARD_RATIO = 0.65
+CORNER_OBJECT_430_INWARD_CENTER_ABS_YREL = 1.55
+CORNER_OBJECT_430_INWARD_KEEP_YVREL_ABS_YREL = 2.2
+CORNER_OBJECT_430_EARLY_INWARD_NONCENTER_FRAMES = 2
+CORNER_OBJECT_430_SIDE_KEEP_ABS_YREL = 2.0
+CORNER_OBJECT_STABLE_TRACK_ID_START = 1000
+CORNER_SIDE_OBJECT_MAX_DREL = 0.2
+CORNER_SIDE_OBJECT_MIN_ABS_YREL = 1.4
+CORNER_SIDE_OBJECT_MAX_ABS_YREL = 4.5
# POC for parsing corner radars: https://github.com/commaai/openpilot/pull/24221/
-def get_radar_can_parser(CP):
- if Bus.radar not in DBC[CP.carFingerprint]:
+class CornerObjectTrackIdManager:
+ def __init__(self):
+ self.next_track_id = CORNER_OBJECT_STABLE_TRACK_ID_START
+ self.objects: dict[tuple[str, int], tuple[int, int]] = {}
+
+ def get_track_id(self, source: str, object_id: int, age: int) -> int:
+ key = (source, object_id)
+ previous = self.objects.get(key)
+ if previous is None or age < previous[1]:
+ track_id = self.next_track_id
+ self.next_track_id += 1
+ else:
+ track_id = previous[0]
+ self.objects[key] = (track_id, age)
+ return track_id
+
+ def clear_source(self, source: str):
+ self.objects = {key: value for key, value in self.objects.items() if key[0] != source}
+
+
+def corner_object_position_valid(d_rel: float, y_rel: float) -> bool:
+ normal_object = 0.2 < d_rel < 180.0
+ clipped_side_object = (
+ 0.0 <= d_rel <= CORNER_SIDE_OBJECT_MAX_DREL and
+ CORNER_SIDE_OBJECT_MIN_ABS_YREL <= abs(y_rel) <= CORNER_SIDE_OBJECT_MAX_ABS_YREL
+ )
+ return (normal_object or clipped_side_object) and abs(y_rel) < 40.0
+
+
+def get_radar_can_parser(CP, radar_tracks, msg_start_addr, msg_count, radar_group4=False):
+ if not radar_tracks:
+ return None
+ #if Bus.radar not in DBC[CP.carFingerprint]:
+ # return None
+ print("RadarInterface: RadarTracks...")
+
+ if CP.flags & HyundaiFlags.CANFD:
+ CAN = CanBus(CP)
+ messages = [(f"RADAR_TRACK_{addr:x}", 20) for addr in range(msg_start_addr, msg_start_addr + msg_count)]
+ return CANParser('hyundai_canfd_radar_generated', messages, CAN.ACAN)
+ else:
+ messages = [(f"RADAR_TRACK_{addr:x}", 20) for addr in range(msg_start_addr, msg_start_addr + msg_count)]
+ #return CANParser(DBC[CP.carFingerprint][Bus.radar], messages, 1)
+ dbc_name = 'hyundai_kia_denso_front_radar_generated' if radar_group4 else 'hyundai_kia_mando_front_radar_generated'
+ return CANParser(dbc_name, messages, 1)
+
+def get_corner_object_can_parser(CP, enabled):
+ if not enabled or not (CP.flags & HyundaiFlags.CANFD):
return None
- messages = [(f"RADAR_TRACK_{addr:x}", 50) for addr in range(RADAR_START_ADDR, RADAR_START_ADDR + RADAR_MSG_COUNT)]
- return CANParser(DBC[CP.carFingerprint][Bus.radar], messages, 1)
+ dbc_path = os.path.join(DBC_PATH, f"{CORNER_OBJECT_235_DBC}.dbc")
+ if not os.path.exists(dbc_path):
+ print(f"RadarInterface: missing {CORNER_OBJECT_235_DBC}.dbc, 0x235 corner radar disabled")
+ return None
+ CAN = CanBus(CP)
+ messages = [(f"CORNER_RADAR_235_OBJECTS_{addr:x}", 33) for addr in range(CORNER_OBJECT_235_START_ADDR, CORNER_OBJECT_235_START_ADDR + CORNER_OBJECT_235_MSG_COUNT)]
+ return CANParser(CORNER_OBJECT_235_DBC, messages, CAN.ACAN)
-class RadarInterface(RadarInterfaceBase, RadarInterfaceExt):
- def __init__(self, CP, CP_IQ):
- RadarInterfaceBase.__init__(self, CP, CP_IQ)
- RadarInterfaceExt.__init__(self, CP, CP_IQ)
- self.updated_messages = set()
- self.trigger_msg = RADAR_START_ADDR + RADAR_MSG_COUNT - 1
+def get_corner_object_180_can_parser(CP, enabled):
+ if not enabled or not (CP.flags & HyundaiFlags.CANFD):
+ return None
+
+ dbc_path = os.path.join(DBC_PATH, f"{CORNER_OBJECT_180_DBC}.dbc")
+ if not os.path.exists(dbc_path):
+ print(f"RadarInterface: missing {CORNER_OBJECT_180_DBC}.dbc, 0x180 corner radar disabled")
+ return None
+
+ CAN = CanBus(CP)
+ messages = [(f"CORNER_RADAR_180_OBJECTS_{addr:x}", 33) for addr in range(CORNER_OBJECT_180_START_ADDR, CORNER_OBJECT_180_START_ADDR + CORNER_OBJECT_180_MSG_COUNT)]
+ return CANParser(CORNER_OBJECT_180_DBC, messages, CAN.ACAN)
+
+def get_corner_object_430_can_parser(CP, enabled):
+ if not enabled or not (CP.flags & HyundaiFlags.CANFD):
+ return None
+
+ dbc_path = os.path.join(DBC_PATH, f"{CORNER_OBJECT_430_DBC}.dbc")
+ if not os.path.exists(dbc_path):
+ print(f"RadarInterface: missing {CORNER_OBJECT_430_DBC}.dbc, 0x430/0x440 corner radar disabled")
+ return None
+
+ CAN = CanBus(CP)
+ messages = [(f"CORNER_RADAR_430_OBJECTS_{addr:x}", 33) for addr in range(CORNER_OBJECT_430_LEFT_START_ADDR, CORNER_OBJECT_430_LEFT_START_ADDR + CORNER_OBJECT_430_MSG_COUNT_PER_SIDE)]
+ messages += [(f"CORNER_RADAR_430_OBJECTS_{addr:x}", 33) for addr in range(CORNER_OBJECT_430_RIGHT_START_ADDR, CORNER_OBJECT_430_RIGHT_START_ADDR + CORNER_OBJECT_430_MSG_COUNT_PER_SIDE)]
+ return CANParser(CORNER_OBJECT_430_DBC, messages, CAN.ACAN)
+
+def get_radar_can_parser_scc(CP):
+ CAN = CanBus(CP)
+ if CP.flags & HyundaiFlags.CANFD:
+ messages = [("SCC_CONTROL", 50)]
+ bus = CAN.ECAN
+ else:
+ messages = [("SCC11", 50)]
+ bus = CAN.ECAN
+
+ print("$$$$$$$$ ECAN = ", CAN.ECAN)
+ bus = CAN.CAM if CP.flags & HyundaiFlags.CAMERA_SCC else bus
+ return CANParser(DBC[CP.carFingerprint][Bus.pt], messages, bus)
+
+class RadarInterface(RadarInterfaceBase):
+ def __init__(self, CP, CP_IQ=None):
+ super().__init__(CP, CP_IQ or structs.IQCarParams())
+ self.v_ego = 0.0
+
+ self.canfd = True if CP.flags & HyundaiFlags.CANFD else False
+ self.radar_group1 = False
+ self.radar_group3 = False
+ self.radar_group4 = not self.canfd and bool(CP.extFlags & HyundaiExtFlags.RADAR_GROUP4.value)
+ if self.canfd:
+ if CP.extFlags & HyundaiExtFlags.RADAR_GROUP1.value:
+ self.radar_start_addr = RADAR_START_ADDR_CANFD1
+ self.radar_msg_count = RADAR_MSG_COUNT1
+ self.radar_group1 = True
+ elif CP.extFlags & HyundaiExtFlags.RADAR_GROUP3.value:
+ self.radar_start_addr = RADAR_START_ADDR_CANFD3
+ self.radar_msg_count = RADAR_MSG_COUNT3
+ self.radar_group3 = True
+ else:
+ self.radar_start_addr = RADAR_START_ADDR_CANFD2
+ self.radar_msg_count = RADAR_MSG_COUNT2
+ else:
+ self.radar_start_addr = RADAR_START_ADDR
+ self.radar_msg_count = RADAR_MSG_COUNT4 if self.radar_group4 else RADAR_MSG_COUNT
+
+ self.params = Params()
+ self.radar_tracks = self.params.get_int("EnableRadarTracks") >= 1
+ self.corner_object_tracks = bool(CP.extFlags & HyundaiExtFlags.CORNER_RADAR_OBJECTS_235.value) and self.params.get_int("EnableCornerRadar") > 0
+ self.corner_object_180_tracks = bool(CP.extFlags & HyundaiExtFlags.CORNER_RADAR_OBJECTS_180.value) and self.params.get_int("EnableCornerRadar") > 0
+ self.corner_object_430_tracks = bool(CP.extFlags & HyundaiExtFlags.CORNER_RADAR_OBJECTS_430.value) and self.params.get_int("EnableCornerRadar") > 0
+ self.updated_tracks = set()
+ self.updated_scc = set()
+ self.updated_corner_objects = set()
+ self.updated_corner_objects_180 = set()
+ self.updated_corner_objects_430 = set()
+ self.corner_object_missed_updates = 0
+ self.corner_object_180_missed_updates = 0
+ self.corner_object_430_missed_updates = 0
+ self.corner_object_track_ids = CornerObjectTrackIdManager()
+ self.rcp_tracks = get_radar_can_parser(CP, self.radar_tracks, self.radar_start_addr, self.radar_msg_count, self.radar_group4)
+ self.rcp_corner_objects = get_corner_object_can_parser(CP, self.corner_object_tracks)
+ self.rcp_corner_objects_180 = get_corner_object_180_can_parser(CP, self.corner_object_180_tracks)
+ self.rcp_corner_objects_430 = get_corner_object_430_can_parser(CP, self.corner_object_430_tracks)
+ # Enabling raw radar tracks on legacy CAN disables the stock SCC11 stream on
+ # some Hyundai/Kia platforms. Camera-SCC cars may still use SCC11.
+ use_scc_parser = not (self.radar_tracks and not self.canfd and not (CP.flags & HyundaiFlags.CAMERA_SCC))
+ self.rcp_scc = get_radar_can_parser_scc(CP) if use_scc_parser else None
+ self.trigger_msg_scc = 416 if self.canfd else 0x420
+
+ self.trigger_msg_tracks = self.radar_start_addr + self.radar_msg_count - 1
+ self.trigger_msg_corner_objects = CORNER_OBJECT_235_START_ADDR + CORNER_OBJECT_235_MSG_COUNT - 1
+ self.trigger_msg_corner_objects_180 = CORNER_OBJECT_180_START_ADDR + CORNER_OBJECT_180_MSG_COUNT - 1
+ self.trigger_msg_corner_objects_430 = CORNER_OBJECT_430_RIGHT_START_ADDR + CORNER_OBJECT_430_MSG_COUNT_PER_SIDE - 1
self.track_id = 0
- self.radar_off_can = CP.radarUnavailable
- self.rcp = get_radar_can_parser(CP)
+ self.corner_objects_available = self.rcp_corner_objects is not None or self.rcp_corner_objects_180 is not None or self.rcp_corner_objects_430 is not None
+ self.radar_off_can = CP.radarUnavailable and not self.corner_objects_available
+ print(
+ "RadarInterface: "
+ f"radarUnavailable={CP.radarUnavailable} radarTracks={self.radar_tracks} "
+ f"group4={self.radar_group4} "
+ f"corner235={self.rcp_corner_objects is not None} corner180={self.rcp_corner_objects_180 is not None} "
+ f"corner430={self.rcp_corner_objects_430 is not None} "
+ f"radarOffCan={self.radar_off_can}"
+ )
+
+ self.vRel_last = 0
+ self.dRel_last = 0
+ self.corner_object_430_prev_d_rel = {}
+ self.corner_object_430_prev_v_rel = {}
+ self.corner_object_430_prev_y_rel = {}
+ self.corner_object_430_prev_yv_rel = {}
+ self.corner_object_430_prev_code = {}
+ self.corner_object_430_history = {}
+ self.corner_object_430_noncenter_inward_frames = {}
+
+ # Initialize pts
+ if self.rcp_tracks is not None:
+ total_tracks = self.radar_msg_count * (2 if self.radar_group1 else 1)
+ for track_id in range(total_tracks):
+ t_id = track_id + 32
+ self.pts[t_id] = structs.RadarData.RadarPoint()
+ self.pts[t_id].measured = False
+ self.pts[t_id].trackId = t_id
+
+ if self.rcp_scc is not None:
+ self.pts[SCC_TID] = structs.RadarData.RadarPoint()
+ self.pts[SCC_TID].trackId = SCC_TID
+ self.pts[SCC_TID].radarSource = "scc"
+ if self.rcp_corner_objects is not None:
+ for slot in range(CORNER_OBJECT_235_MSG_COUNT):
+ t_id = CORNER_OBJECT_235_TRACK_ID_OFFSET + slot
+ self.pts[t_id] = structs.RadarData.RadarPoint()
+ self.pts[t_id].measured = False
+ self.pts[t_id].trackId = t_id
+ self.pts[t_id].radarSource = "corner235"
+ if self.rcp_corner_objects_180 is not None:
+ for slot in range(CORNER_OBJECT_180_MSG_COUNT * CORNER_OBJECT_180_SLOTS_PER_MSG):
+ t_id = CORNER_OBJECT_180_TRACK_ID_OFFSET + slot
+ self.pts[t_id] = structs.RadarData.RadarPoint()
+ self.pts[t_id].measured = False
+ self.pts[t_id].trackId = t_id
+ self.pts[t_id].radarSource = "corner180"
+ if self.rcp_corner_objects_430 is not None:
+ for slot in range(CORNER_OBJECT_430_MSG_COUNT_PER_SIDE * 2 * CORNER_OBJECT_430_SLOTS_PER_MSG):
+ t_id = CORNER_OBJECT_430_TRACK_ID_OFFSET + slot
+ self.pts[t_id] = structs.RadarData.RadarPoint()
+ self.pts[t_id].measured = False
+ self.pts[t_id].trackId = t_id
+
+ self.frame = 0
- if self.rcp is None:
- self.initialize_radar_ext(self.trigger_msg)
def update(self, can_strings):
- if self.radar_off_can or (self.rcp is None):
+ self.frame += 1
+ if self.radar_off_can or (self.rcp_tracks is None and self.rcp_scc is None and self.rcp_corner_objects is None and self.rcp_corner_objects_180 is None and self.rcp_corner_objects_430 is None):
return super().update(None)
- vls = self.rcp.update(can_strings)
- self.updated_messages.update(vls)
+ if self.rcp_scc is not None:
+ vls_s = self.rcp_scc.update(can_strings)
+ self.updated_scc.update(vls_s)
- if self.trigger_msg not in self.updated_messages:
+ track_ready = False
+ if self.radar_tracks and self.rcp_tracks is not None:
+ vls_t = self.rcp_tracks.update(can_strings)
+ self.updated_tracks.update(vls_t)
+ track_ready = self.trigger_msg_tracks in self.updated_tracks
+
+ corner_ready = False
+ if self.rcp_corner_objects is not None:
+ vls_c = self.rcp_corner_objects.update(can_strings)
+ self.updated_corner_objects.update(vls_c)
+ corner_ready = self.trigger_msg_corner_objects in self.updated_corner_objects
+
+ corner_180_ready = False
+ if self.rcp_corner_objects_180 is not None:
+ vls_180 = self.rcp_corner_objects_180.update(can_strings)
+ self.updated_corner_objects_180.update(vls_180)
+ corner_180_ready = self.trigger_msg_corner_objects_180 in self.updated_corner_objects_180
+
+ corner_430_ready = False
+ if self.rcp_corner_objects_430 is not None:
+ vls_430 = self.rcp_corner_objects_430.update(can_strings)
+ self.updated_corner_objects_430.update(vls_430)
+ corner_430_ready = self.trigger_msg_corner_objects_430 in self.updated_corner_objects_430
+
+ scc_ready = not self.radar_tracks and self.frame % 5 == 0 and self.rcp_scc is not None
+
+ if track_ready:
+ self._update(self.updated_tracks)
+ self.updated_tracks.clear()
+
+ if corner_ready:
+ self._update_corner_objects(self.updated_corner_objects)
+ self.corner_object_missed_updates = 0
+ self.updated_corner_objects.clear()
+
+ if corner_180_ready:
+ self._update_corner_objects_180(self.updated_corner_objects_180)
+ self.corner_object_180_missed_updates = 0
+ self.updated_corner_objects_180.clear()
+
+ if corner_430_ready:
+ self._update_corner_objects_430(self.updated_corner_objects_430)
+ self.corner_object_430_missed_updates = 0
+ self.updated_corner_objects_430.clear()
+
+ # Corner radar runs at its own cadence. Do not let corner-only frames publish
+ # RadarData, since liveTracks uses a fixed radarTimeStep for aLead/jLead.
+ publish_ready = track_ready or scc_ready
+ if not publish_ready:
return None
- rr = self._update(self.updated_messages)
- self.updated_messages.clear()
+ if self.rcp_scc is not None:
+ self._update_scc(self.updated_scc)
+ if self.rcp_corner_objects is not None:
+ if self.updated_corner_objects:
+ self._update_corner_objects(self.updated_corner_objects)
+ self.corner_object_missed_updates = 0
+ else:
+ self.corner_object_missed_updates += 1
+ if self.corner_object_missed_updates > 10:
+ self._clear_corner_objects()
+ if self.rcp_corner_objects_180 is not None:
+ if self.updated_corner_objects_180:
+ self._update_corner_objects_180(self.updated_corner_objects_180)
+ self.corner_object_180_missed_updates = 0
+ else:
+ self.corner_object_180_missed_updates += 1
+ if self.corner_object_180_missed_updates > 10:
+ self._clear_corner_objects_180()
+ if self.rcp_corner_objects_430 is not None:
+ if self.updated_corner_objects_430:
+ self._update_corner_objects_430(self.updated_corner_objects_430)
+ self.corner_object_430_missed_updates = 0
+ else:
+ self.corner_object_430_missed_updates += 1
+ if self.corner_object_430_missed_updates > 10:
+ self._clear_corner_objects_430()
+ self.updated_scc.clear()
+ self.updated_corner_objects.clear()
+ self.updated_corner_objects_180.clear()
+ self.updated_corner_objects_430.clear()
- return rr
+ ret = structs.RadarData()
+ if ((self.rcp_tracks is not None and self.radar_tracks and not self.rcp_tracks.can_valid) or
+ (self.rcp_scc is not None and not self.corner_objects_available and not self.rcp_scc.can_valid) or
+ (self.rcp_corner_objects is not None and not self.rcp_corner_objects.can_valid) or
+ (self.rcp_corner_objects_180 is not None and not self.rcp_corner_objects_180.can_valid) or
+ (self.rcp_corner_objects_430 is not None and not self.rcp_corner_objects_430.can_valid)):
+ ret.errors.canError = True
+ ret.points = [point for point in self.pts.values() if point.measured]
+ return ret
def _update(self, updated_messages):
- ret = structs.RadarData()
- if self.rcp is None:
- return ret
- if not self.rcp.can_valid:
- ret.errors.canError = True
+ t_id = 32
+ for addr in range(self.radar_start_addr, self.radar_start_addr + self.radar_msg_count):
- if self.use_radar_interface_ext:
- return self.update_ext(ret)
-
- for addr in range(RADAR_START_ADDR, RADAR_START_ADDR + RADAR_MSG_COUNT):
- msg = self.rcp.vl[f"RADAR_TRACK_{addr:x}"]
-
- if addr not in self.pts:
- self.pts[addr] = structs.RadarData.RadarPoint()
- self.pts[addr].trackId = self.track_id
- self.track_id += 1
-
- valid = msg['STATE'] in (3, 4)
- if valid:
- azimuth = math.radians(msg['AZIMUTH'])
- self.pts[addr].measured = True
- self.pts[addr].dRel = math.cos(azimuth) * msg['LONG_DIST']
- self.pts[addr].yRel = 0.5 * -math.sin(azimuth) * msg['LONG_DIST']
- self.pts[addr].vRel = msg['REL_SPEED']
- self.pts[addr].aRel = msg['REL_ACCEL']
- self.pts[addr].yvRel = float('nan')
+ msg = self.rcp_tracks.vl[f"RADAR_TRACK_{addr:x}"]
+ if self.radar_group1:
+ valid = msg['VALID_CNT1'] > 10
+ elif self.radar_group3:
+ # Group 3 marks an empty object slot with LONG_DIST raw 0x7ff (204.7 m).
+ valid = msg['LONG_DIST'] < 204.7
+ elif self.canfd:
+ valid = msg['VALID_CNT'] > 10
+ elif self.radar_group4:
+ # EN: DNMWR006 exposes eight stable tracked-object slots at 0x500-0x507.
+ # Messages from 0x508 onward are distance-sorted raw detections without
+ # stable IDs, so they are excluded. OBJECT_STATE 3 is a confirmed track;
+ # empty slots use LONG_DIST raw 0xfff8 (409.55 m). Driving logs reached
+ # 317.80 m, so 325 m preserves every observed confirmed track while
+ # retaining margin from the empty-slot sentinel. Keep the +/-6 m
+ # ego/adjacent-lane envelope to suppress farther roadside reflections.
+ # KO: DNMWR006의 안정적인 추적 객체 슬롯은 0x500~0x507의 8개임.
+ # 0x508 이후 메시지는 고정 ID가 없는 거리순 raw detection이므로 제외함.
+ # OBJECT_STATE 3은 확정 추적 객체이며, 빈 슬롯은 LONG_DIST raw
+ # 0xfff8(409.55m)을 사용함. 주행 로그의 최대값은 317.80m였으므로
+ # 325m 상한으로 관측된 확정 트랙을 모두 보존하면서 빈 슬롯 값과 충분한
+ # 여유를 확보함. 원거리 도로변 반사를 줄이기 위해 좌우 6m 범위를 유지함.
+ valid = (msg['OBJECT_STATE'] == 3 and 0.2 < msg['LONG_DIST'] < RADAR_GROUP4_MAX_LONG_DIST and
+ abs(msg['LAT_DIST']) <= RADAR_GROUP4_MAX_YREL)
else:
- del self.pts[addr]
+ valid = msg['STATE'] in (3, 4)
- ret.points = list(self.pts.values())
- return ret
+ self.pts[t_id].measured = bool(valid)
+ if not valid:
+ self.pts[t_id].dRel = 0
+ self.pts[t_id].yRel = 0
+ self.pts[t_id].vRel = 0
+ self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
+ self.pts[t_id].aRel = float('nan')
+ self.pts[t_id].yvRel = 0
+ elif self.radar_group1:
+ self.pts[t_id].dRel = msg['LONG_DIST1']
+ self.pts[t_id].yRel = msg['LAT_DIST1']
+ self.pts[t_id].vRel = msg['REL_SPEED1']
+ self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
+ self.pts[t_id].aRel = msg['REL_ACCEL1']
+ self.pts[t_id].yvRel = msg['LAT_SPEED1']
+ elif self.canfd:
+ if self.radar_group3:
+ # Group 3 reports the object's center. Convert it to the rear surface to match SCC/vision dRel.
+ self.pts[t_id].dRel = max(0.0, msg['LONG_DIST'] - msg['OBJECT_LENGTH'] * 0.5 - 0.1)
+ else:
+ self.pts[t_id].dRel = msg['LONG_DIST']
+ self.pts[t_id].yRel = msg['LAT_DIST']
+ self.pts[t_id].vRel = msg['REL_SPEED']
+ self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
+ self.pts[t_id].aRel = float('nan') if self.radar_group3 else msg['REL_ACCEL']
+ self.pts[t_id].yvRel = 0.0 if self.radar_group3 else msg['LAT_SPEED']
+ elif self.radar_group4:
+ self.pts[t_id].dRel = msg['LONG_DIST']
+ self.pts[t_id].yRel = -msg['LAT_DIST']
+ self.pts[t_id].vRel = msg['REL_SPEED']
+ self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
+ self.pts[t_id].aRel = float('nan')
+ self.pts[t_id].yvRel = 0.0
+ else:
+ azimuth = math.radians(msg['AZIMUTH'])
+ self.pts[t_id].dRel = math.cos(azimuth) * msg['LONG_DIST']
+ self.pts[t_id].yRel = 0.5 * -math.sin(azimuth) * msg['LONG_DIST']
+ self.pts[t_id].vRel = msg['REL_SPEED']
+ self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
+ self.pts[t_id].aRel = msg['REL_ACCEL']
+ self.pts[t_id].yvRel = 0.0
+
+ t_id += 1
+ # radar group1? ?나??msg??2개의 ?이?? ?어?음.
+ if self.radar_group1:
+ for addr in range(self.radar_start_addr, self.radar_start_addr + self.radar_msg_count):
+ msg = self.rcp_tracks.vl[f"RADAR_TRACK_{addr:x}"]
+
+ valid = msg['VALID_CNT2'] > 10
+ self.pts[t_id].measured = bool(valid)
+ if not valid:
+ self.pts[t_id].dRel = 0
+ self.pts[t_id].yRel = 0
+ self.pts[t_id].vRel = 0
+ self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
+ self.pts[t_id].aRel = float('nan')
+ self.pts[t_id].yvRel = 0
+ else:
+ self.pts[t_id].dRel = msg['LONG_DIST2']
+ self.pts[t_id].yRel = msg['LAT_DIST2']
+ self.pts[t_id].vRel = msg['REL_SPEED2']
+ self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
+ self.pts[t_id].aRel = msg['REL_ACCEL2']
+ self.pts[t_id].yvRel = msg['LAT_SPEED2']
+
+ t_id += 1
+
+ def _update_corner_objects(self, updated_messages):
+ if self.rcp_corner_objects is None:
+ return
+
+ if not updated_messages:
+ self._clear_corner_objects()
+ return
+
+ candidates = []
+ for slot, addr in enumerate(range(CORNER_OBJECT_235_START_ADDR, CORNER_OBJECT_235_START_ADDR + CORNER_OBJECT_235_MSG_COUNT)):
+ t_id = CORNER_OBJECT_235_TRACK_ID_OFFSET + slot
+ msg = self.rcp_corner_objects.vl[f"CORNER_RADAR_235_OBJECTS_{addr:x}"]
+
+ d_rel = msg["OBJ_REL_POS_X"]
+ y_rel = msg["OBJ_REL_POS_Y"]
+ v_rel = msg["OBJ_REL_VEL_X"]
+ yv_rel = msg["OBJ_REL_VEL_Y"]
+ a_rel = msg["OBJ_REL_ACCEL_X"]
+ # Side objects are clipped to x=0 by the corner radar. Quality, identity,
+ # and lateral motion still describe a real object, so keep them for
+ # corner-confirmed front-radar association in radard.
+ valid = msg["OBJ_QUAL_LEVEL"] > 0 and corner_object_position_valid(d_rel, y_rel) and v_rel > -99.0
+
+ if not valid:
+ continue
+ candidates.append((t_id, int(msg["OBJ_OBJECT_ID"]), int(msg["OBJ_AGE"]), int(msg["OBJ_QUAL_LEVEL"]),
+ d_rel, y_rel, v_rel, yv_rel, a_rel))
+
+ self._apply_corner_objects("corner235", candidates,
+ range(CORNER_OBJECT_235_TRACK_ID_OFFSET,
+ CORNER_OBJECT_235_TRACK_ID_OFFSET + CORNER_OBJECT_235_MSG_COUNT))
+
+ def _update_corner_objects_180(self, updated_messages):
+ if self.rcp_corner_objects_180 is None:
+ return
+
+ if not updated_messages:
+ self._clear_corner_objects_180()
+ return
+
+ candidates = []
+ for msg_index, addr in enumerate(range(CORNER_OBJECT_180_START_ADDR, CORNER_OBJECT_180_START_ADDR + CORNER_OBJECT_180_MSG_COUNT)):
+ msg = self.rcp_corner_objects_180.vl[f"CORNER_RADAR_180_OBJECTS_{addr:x}"]
+ for slot_index in range(CORNER_OBJECT_180_SLOTS_PER_MSG):
+ t_id = CORNER_OBJECT_180_TRACK_ID_OFFSET + msg_index * CORNER_OBJECT_180_SLOTS_PER_MSG + slot_index
+ prefix = f"SLOT{slot_index + 1}_"
+ d_rel = msg[f"{prefix}REL_POS_X"]
+ y_rel = msg[f"{prefix}REL_POS_Y"]
+ v_rel = msg[f"{prefix}REL_VEL_X"]
+ yv_rel = msg[f"{prefix}REL_VEL_Y"]
+ a_rel = msg[f"{prefix}REL_ACCEL_X"]
+ valid = msg[f"{prefix}QUAL_LEVEL"] > 0 and corner_object_position_valid(d_rel, y_rel) and v_rel > -99.0
+
+ if not valid:
+ continue
+ candidates.append((t_id, int(msg[f"{prefix}OBJECT_ID"]), int(msg[f"{prefix}AGE"]), int(msg[f"{prefix}QUAL_LEVEL"]),
+ d_rel, y_rel, v_rel, yv_rel, a_rel))
+
+ self._apply_corner_objects("corner180", candidates,
+ range(CORNER_OBJECT_180_TRACK_ID_OFFSET,
+ CORNER_OBJECT_180_TRACK_ID_OFFSET + CORNER_OBJECT_180_MSG_COUNT * CORNER_OBJECT_180_SLOTS_PER_MSG))
+
+ def _apply_corner_objects(self, source, candidates, slot_ids):
+ for t_id in slot_ids:
+ self._clear_point(t_id)
+
+ # The same object can occupy two CAN slots for one cycle during a slot handoff.
+ # Publish only the newest/highest-quality copy so trackId stays unique.
+ objects = {}
+ for candidate in candidates:
+ object_id = candidate[1]
+ previous = objects.get(object_id)
+ if previous is None or (candidate[2], candidate[3]) > (previous[2], previous[3]):
+ objects[object_id] = candidate
+
+ for t_id, object_id, age, _, d_rel, y_rel, v_rel, yv_rel, a_rel in objects.values():
+ point = self.pts[t_id]
+ point.measured = True
+ point.trackId = self.corner_object_track_ids.get_track_id(source, object_id, age)
+ point.radarSource = source
+ point.dRel = d_rel
+ point.yRel = y_rel
+ point.vRel = v_rel
+ point.vLead = v_rel + self.v_ego
+ point.aRel = a_rel
+ point.yvRel = yv_rel
+
+
+ def _update_corner_objects_430(self, updated_messages):
+ if self.rcp_corner_objects_430 is None:
+ return
+
+ if not updated_messages:
+ self._clear_corner_objects_430()
+ return
+
+ bank_defs = (
+ (CORNER_OBJECT_430_LEFT_START_ADDR, 1.0, 0),
+ (CORNER_OBJECT_430_RIGHT_START_ADDR, -1.0, CORNER_OBJECT_430_MSG_COUNT_PER_SIDE * CORNER_OBJECT_430_SLOTS_PER_MSG),
+ )
+ for start_addr, side_sign, track_base in bank_defs:
+ bins = []
+ for msg_index, addr in enumerate(range(start_addr, start_addr + CORNER_OBJECT_430_MSG_COUNT_PER_SIDE)):
+ msg = self.rcp_corner_objects_430.vl[f"CORNER_RADAR_430_OBJECTS_{addr:x}"]
+ for slot_index in range(CORNER_OBJECT_430_SLOTS_PER_MSG):
+ prefix = f"SLOT{slot_index + 1}_"
+ distance_raw = int(msg[f"{prefix}DISTANCE_RAW"])
+ raw = (
+ distance_raw |
+ (int(msg[f"{prefix}META_13_15"]) << 13) |
+ (int(msg[f"{prefix}META_BYTE_2"]) << 16) |
+ (int(msg[f"{prefix}META_BYTE_3"]) << 24)
+ )
+ code = (
+ int(msg[f"{prefix}META_13_15"]),
+ int(msg[f"{prefix}META_BYTE_2"]),
+ int(msg[f"{prefix}META_BYTE_3"]),
+ )
+ d_rel = distance_raw * 0.05
+ default_distance = CORNER_OBJECT_430_DEFAULT_DISTANCE_RAW_MIN <= distance_raw <= CORNER_OBJECT_430_DEFAULT_DISTANCE_RAW_MAX
+ base_valid = (
+ raw not in CORNER_OBJECT_430_EMPTY_RAW_VALUES and
+ distance_raw not in (0, 8000, 8191) and
+ not default_distance and
+ 0.2 < d_rel < CORNER_OBJECT_430_MAX_DREL
+ )
+ candidate_valid = (
+ base_valid and
+ slot_index + 1 not in CORNER_OBJECT_430_CANDIDATE_EXCLUDED_SLOTS and
+ code[2] in CORNER_OBJECT_430_CANDIDATE_META_BYTE_3 and
+ code[1] in CORNER_OBJECT_430_STRONG_META_BYTE_2 + CORNER_OBJECT_430_WEAK_META_BYTE_2
+ )
+ bins.append({
+ "msg_index": msg_index,
+ "slot_index": slot_index,
+ "distance_raw": distance_raw,
+ "d_rel": d_rel,
+ "code": code,
+ "candidate_valid": candidate_valid,
+ })
+
+ supported_bins = []
+ candidates = [b for b in bins if b["candidate_valid"]]
+ for b in candidates:
+ support = 1
+ for other in candidates:
+ if other is b:
+ continue
+ if abs(other["msg_index"] - b["msg_index"]) > 1:
+ continue
+ if abs(other["slot_index"] - b["slot_index"]) > 2:
+ continue
+ if abs(other["distance_raw"] - b["distance_raw"]) > CORNER_OBJECT_430_CANDIDATE_RAW_DELTA:
+ continue
+ support += 1
+ min_support = (CORNER_OBJECT_430_STRONG_MIN_SUPPORT if b["code"][1] in CORNER_OBJECT_430_STRONG_META_BYTE_2
+ else CORNER_OBJECT_430_WEAK_MIN_SUPPORT)
+ if support >= min_support:
+ supported_bins.append({**b, "support": support})
+
+ clusters = []
+ for b in sorted(supported_bins, key=lambda item: item["distance_raw"]):
+ if not clusters or b["distance_raw"] - clusters[-1][-1]["distance_raw"] > CORNER_OBJECT_430_CLUSTER_RAW_GAP:
+ clusters.append([b])
+ else:
+ clusters[-1].append(b)
+ clusters = sorted(clusters, key=lambda cluster: sum(b["distance_raw"] for b in cluster) / len(cluster))[:CORNER_OBJECT_430_MAX_TRACKS_PER_SIDE]
+
+ cluster_objects = []
+ for cluster in clusters:
+ msg_index = sum(b["msg_index"] for b in cluster) / len(cluster)
+ slot = sum(b["slot_index"] + 1 for b in cluster) / len(cluster)
+ lateral_cell = (CORNER_OBJECT_430_LATERAL_CELL_MSG_WEIGHT * msg_index +
+ CORNER_OBJECT_430_LATERAL_CELL_SLOT_WEIGHT * slot)
+ mapped_cell = lateral_cell if side_sign > 0.0 else CORNER_OBJECT_430_RIGHT_CELL_MIRROR - lateral_cell
+ y_abs = max(CORNER_OBJECT_430_MIN_ABS_YREL,
+ min(CORNER_OBJECT_430_MAX_ABS_YREL,
+ CORNER_OBJECT_430_YREL_OFFSET - CORNER_OBJECT_430_YREL_SCALE * mapped_cell))
+ cluster_objects.append({
+ "d_rel": sum(b["d_rel"] for b in cluster) / len(cluster),
+ "y_rel": side_sign * y_abs,
+ "code": max((b["code"] for b in cluster), key=lambda code: sum(1 for item in cluster if item["code"] == code)),
+ })
+
+ active_t_ids = set()
+ side_track_ids = [
+ CORNER_OBJECT_430_TRACK_ID_OFFSET + track_base + slot
+ for slot in range(CORNER_OBJECT_430_MAX_TRACKS_PER_SIDE)
+ ]
+ unmatched_track_ids = {t_id for t_id in side_track_ids if t_id in self.corner_object_430_prev_d_rel}
+ unused_track_ids = [t_id for t_id in side_track_ids if t_id not in unmatched_track_ids]
+
+ for cluster in cluster_objects:
+ d_rel = cluster["d_rel"]
+ code = cluster["code"]
+ matched_t_id = None
+ if unmatched_track_ids:
+ nearest_t_id = min(unmatched_track_ids, key=lambda t_id: abs(d_rel - self.corner_object_430_prev_d_rel[t_id]))
+ if abs(d_rel - self.corner_object_430_prev_d_rel[nearest_t_id]) <= CORNER_OBJECT_430_TRACK_MATCH_MAX_DREL_DELTA:
+ matched_t_id = nearest_t_id
+ unmatched_track_ids.remove(matched_t_id)
+ if matched_t_id is None and unused_track_ids:
+ matched_t_id = unused_track_ids.pop(0)
+ if matched_t_id is None:
+ continue
+
+ t_id = matched_t_id
+ active_t_ids.add(t_id)
+ prev_d_rel = self.corner_object_430_prev_d_rel.get(t_id)
+ prev_code = self.corner_object_430_prev_code.get(t_id)
+ self.corner_object_430_prev_d_rel[t_id] = d_rel
+ self.corner_object_430_prev_y_rel[t_id] = cluster["y_rel"]
+ self.corner_object_430_prev_code[t_id] = code
+ reset_track = prev_d_rel is None or code != prev_code or abs(d_rel - prev_d_rel) > CORNER_OBJECT_430_MAX_DREL_DELTA
+ if reset_track:
+ self.corner_object_430_prev_v_rel.pop(t_id, None)
+ self.corner_object_430_prev_yv_rel.pop(t_id, None)
+ self.corner_object_430_history.pop(t_id, None)
+ self.corner_object_430_noncenter_inward_frames.pop(t_id, None)
+
+ history = self.corner_object_430_history.setdefault(t_id, deque(maxlen=CORNER_OBJECT_430_HISTORY_SIZE))
+ history.append((d_rel, cluster["y_rel"]))
+ if len(history) < CORNER_OBJECT_430_MIN_HISTORY:
+ self._clear_point(t_id)
+ continue
+
+ window_dt = CORNER_OBJECT_430_DT * (len(history) - 1)
+ first_d_rel, first_y_rel = history[0]
+ hist_v_rel = (d_rel - first_d_rel) / window_dt
+ if abs(hist_v_rel) > CORNER_OBJECT_430_MAX_ABS_VREL:
+ self.corner_object_430_prev_v_rel.pop(t_id, None)
+ self.corner_object_430_prev_yv_rel.pop(t_id, None)
+ self.corner_object_430_history.pop(t_id, None)
+ self.corner_object_430_noncenter_inward_frames.pop(t_id, None)
+ self._clear_point(t_id)
+ continue
+ prev_v_rel = self.corner_object_430_prev_v_rel.get(t_id, hist_v_rel)
+ v_rel = (1.0 - CORNER_OBJECT_430_VREL_ALPHA) * prev_v_rel + CORNER_OBJECT_430_VREL_ALPHA * hist_v_rel
+ self.corner_object_430_prev_v_rel[t_id] = v_rel
+
+ inward_steps = 0
+ usable_steps = 0
+ prev_abs_y = abs(history[0][1])
+ for _, y_rel in list(history)[1:]:
+ abs_y = abs(y_rel)
+ delta = prev_abs_y - abs_y
+ if abs(delta) > 1e-3:
+ usable_steps += 1
+ if delta > 0.0:
+ inward_steps += 1
+ prev_abs_y = abs_y
+ net_inward_y = abs(first_y_rel) - abs(cluster["y_rel"])
+ inward_ratio = inward_steps / usable_steps if usable_steps > 0 else 0.0
+ hist_yv_rel = (cluster["y_rel"] - first_y_rel) / window_dt
+ recent_inward_y = abs(history[-3][1]) - abs(cluster["y_rel"]) if len(history) >= 3 else net_inward_y
+ if (net_inward_y < CORNER_OBJECT_430_MIN_INWARD_YREL_DELTA or
+ recent_inward_y < CORNER_OBJECT_430_MIN_RECENT_INWARD_YREL_DELTA or
+ inward_ratio < CORNER_OBJECT_430_MIN_INWARD_RATIO or
+ abs(hist_yv_rel) > CORNER_OBJECT_430_MAX_ABS_YVREL):
+ hist_yv_rel = 0.0
+ inward_motion_candidate = hist_yv_rel != 0.0 and abs(cluster["y_rel"]) <= CORNER_OBJECT_430_INWARD_KEEP_YVREL_ABS_YREL
+ inward_center_candidate = inward_motion_candidate and abs(cluster["y_rel"]) <= CORNER_OBJECT_430_INWARD_CENTER_ABS_YREL
+ y_rel = cluster["y_rel"]
+ if inward_motion_candidate:
+ if inward_center_candidate:
+ self.corner_object_430_noncenter_inward_frames[t_id] = 0
+ prev_yv_rel = self.corner_object_430_prev_yv_rel.get(t_id, hist_yv_rel)
+ yv_rel = (1.0 - CORNER_OBJECT_430_YVREL_ALPHA) * prev_yv_rel + CORNER_OBJECT_430_YVREL_ALPHA * hist_yv_rel
+ else:
+ noncenter_frames = self.corner_object_430_noncenter_inward_frames.get(t_id, 0) + 1
+ self.corner_object_430_noncenter_inward_frames[t_id] = noncenter_frames
+ if noncenter_frames <= CORNER_OBJECT_430_EARLY_INWARD_NONCENTER_FRAMES:
+ prev_yv_rel = self.corner_object_430_prev_yv_rel.get(t_id, hist_yv_rel)
+ yv_rel = (1.0 - CORNER_OBJECT_430_YVREL_ALPHA) * prev_yv_rel + CORNER_OBJECT_430_YVREL_ALPHA * hist_yv_rel
+ else:
+ yv_rel = 0.0
+ if not inward_center_candidate and abs(y_rel) < CORNER_OBJECT_430_SIDE_KEEP_ABS_YREL:
+ y_rel = math.copysign(CORNER_OBJECT_430_SIDE_KEEP_ABS_YREL, y_rel)
+ else:
+ hist_yv_rel = 0.0
+ yv_rel = 0.0
+ self.corner_object_430_noncenter_inward_frames[t_id] = 0
+ if abs(y_rel) < CORNER_OBJECT_430_SIDE_KEEP_ABS_YREL:
+ y_rel = math.copysign(CORNER_OBJECT_430_SIDE_KEEP_ABS_YREL, y_rel)
+ self.corner_object_430_prev_yv_rel[t_id] = yv_rel
+
+ self.pts[t_id].measured = True
+ self.pts[t_id].trackId = t_id
+ self.pts[t_id].dRel = d_rel
+ self.pts[t_id].yRel = y_rel
+ self.pts[t_id].vRel = v_rel
+ self.pts[t_id].vLead = v_rel + self.v_ego
+ self.pts[t_id].aRel = float('nan')
+ self.pts[t_id].yvRel = yv_rel
+
+ side_track_count = CORNER_OBJECT_430_MSG_COUNT_PER_SIDE * CORNER_OBJECT_430_SLOTS_PER_MSG
+ for slot in range(side_track_count):
+ t_id = CORNER_OBJECT_430_TRACK_ID_OFFSET + track_base + slot
+ if t_id in active_t_ids:
+ continue
+ self.corner_object_430_prev_d_rel.pop(t_id, None)
+ self.corner_object_430_prev_v_rel.pop(t_id, None)
+ self.corner_object_430_prev_y_rel.pop(t_id, None)
+ self.corner_object_430_prev_yv_rel.pop(t_id, None)
+ self.corner_object_430_prev_code.pop(t_id, None)
+ self.corner_object_430_history.pop(t_id, None)
+ self.corner_object_430_noncenter_inward_frames.pop(t_id, None)
+ self._clear_point(t_id)
+
+
+ def _clear_point(self, t_id):
+ self.pts[t_id].measured = False
+ self.pts[t_id].dRel = 0
+ self.pts[t_id].yRel = 0
+ self.pts[t_id].vRel = 0
+ self.pts[t_id].vLead = self.v_ego
+ self.pts[t_id].aRel = float('nan')
+ self.pts[t_id].yvRel = 0
+
+ def _clear_corner_objects(self):
+ for slot in range(CORNER_OBJECT_235_MSG_COUNT):
+ self._clear_point(CORNER_OBJECT_235_TRACK_ID_OFFSET + slot)
+ self.corner_object_track_ids.clear_source("corner235")
+
+ def _clear_corner_objects_180(self):
+ for slot in range(CORNER_OBJECT_180_MSG_COUNT * CORNER_OBJECT_180_SLOTS_PER_MSG):
+ self._clear_point(CORNER_OBJECT_180_TRACK_ID_OFFSET + slot)
+ self.corner_object_track_ids.clear_source("corner180")
+
+ def _clear_corner_objects_430(self):
+ self.corner_object_430_prev_d_rel.clear()
+ self.corner_object_430_prev_v_rel.clear()
+ self.corner_object_430_prev_y_rel.clear()
+ self.corner_object_430_prev_yv_rel.clear()
+ self.corner_object_430_prev_code.clear()
+ self.corner_object_430_history.clear()
+ self.corner_object_430_noncenter_inward_frames.clear()
+ for slot in range(CORNER_OBJECT_430_MSG_COUNT_PER_SIDE * 2 * CORNER_OBJECT_430_SLOTS_PER_MSG):
+ self._clear_point(CORNER_OBJECT_430_TRACK_ID_OFFSET + slot)
+
+ def _update_scc(self, updated_messages):
+ cpt = self.rcp_scc.vl
+ t_id = SCC_TID
+ if self.canfd:
+ dRel = cpt["SCC_CONTROL"]['ACC_ObjDist']
+ vRel = cpt["SCC_CONTROL"]['ACC_ObjRelSpd']
+ new_pts = abs(dRel - self.dRel_last) > 3 or abs(vRel - self.vRel_last) > 1
+ vLead = vRel + self.v_ego
+ valid = 0 < dRel < 150 and not new_pts #cpt["SCC_CONTROL"]['OBJ_STATUS'] and dRel < 150
+ self.pts[t_id].measured = bool(valid)
+ if not valid:
+ self.pts[t_id].dRel = 0
+ self.pts[t_id].yRel = 0
+ self.pts[t_id].vRel = 0
+ self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
+ self.pts[t_id].aRel = float('nan')
+ self.pts[t_id].yvRel = 0
+ else:
+ self.pts[t_id].dRel = dRel
+ self.pts[t_id].yRel = 0
+ self.pts[t_id].vRel = vRel
+ self.pts[t_id].vLead = vLead
+ self.pts[t_id].aRel = float('nan')
+ self.pts[t_id].yvRel = 0 #float('nan')
+ else:
+ dRel = cpt["SCC11"]['ACC_ObjDist']
+ vRel = cpt["SCC11"]['ACC_ObjRelSpd']
+ new_pts = abs(dRel - self.dRel_last) > 3 or abs(vRel - self.vRel_last) > 1
+ vLead = vRel + self.v_ego
+ valid = cpt["SCC11"]['ACC_ObjStatus'] and dRel < 150 and not new_pts
+ self.pts[t_id].measured = bool(valid)
+ if not valid:
+ self.pts[t_id].dRel = 0
+ self.pts[t_id].yRel = 0
+ self.pts[t_id].vRel = 0
+ self.pts[t_id].vLead = self.pts[t_id].vRel + self.v_ego
+ self.pts[t_id].aRel = float('nan')
+ self.pts[t_id].yvRel = 0
+ else:
+ self.pts[t_id].dRel = dRel
+ self.pts[t_id].yRel = -cpt["SCC11"]['ACC_ObjLatPos'] # in car frame's y axis, left is negative
+ self.pts[t_id].vRel = vRel
+ self.pts[t_id].vLead = vLead
+ self.pts[t_id].aRel = float('nan')
+ self.pts[t_id].yvRel = 0 #float('nan')
+
+ self.dRel_last = dRel
+ self.vRel_last = vRel
diff --git a/iqdbc_repo/iqdbc/car/hyundai/tests/print_platform_codes.py b/iqdbc_repo/iqdbc/car/hyundai/tests/print_platform_codes.py
old mode 100755
new mode 100644
diff --git a/iqdbc_repo/iqdbc/car/hyundai/tests/test_ev_mode.py b/iqdbc_repo/iqdbc/car/hyundai/tests/test_ev_mode.py
new file mode 100644
index 0000000..7338d7e
--- /dev/null
+++ b/iqdbc_repo/iqdbc/car/hyundai/tests/test_ev_mode.py
@@ -0,0 +1,194 @@
+import math
+
+import pytest
+
+from iqdbc.can import CANPacker, CANParser
+from iqdbc.car import Bus, gen_empty_fingerprint, structs
+from iqdbc.car.hyundai.carstate import CarState, EV_MODE_STATUS_TIMEOUT_NS, _get_ev_mode_state
+from iqdbc.car.hyundai.interface import CarInterface
+from iqdbc.car.hyundai.values import CANFD_HYBRID_STATUS_ADDR, CANFD_HYBRID_STATUS_DLC, CAR, DBC, EV_MODE_ACTIVE_VALUES, \
+ EV_MODE_STATUS_ADDR, EV_MODE_STATUS_DLC, EV_MODE_STATUS_MSG, EV_MODE_STATUS_SIGNAL, \
+ HyundaiExtFlags, HyundaiFlags
+from openpilot.common.params import Params
+
+
+def get_params(candidate, *, hybrid=True, hybrid_bus=0, hybrid_status=None, hybrid_status_bus=0,
+ hybrid_status_dlc=CANFD_HYBRID_STATUS_DLC, status_bus=0, status_dlc=EV_MODE_STATUS_DLC):
+ Params().put_int("HyundaiCameraSCC", 1)
+ Params().put_int("CanfdHDA2", 1)
+
+ fingerprint = gen_empty_fingerprint()
+ if hybrid:
+ fingerprint[hybrid_bus][0x105] = 32
+ if hybrid_status is None:
+ hybrid_status = hybrid
+ if hybrid_status:
+ fingerprint[hybrid_status_bus][CANFD_HYBRID_STATUS_ADDR] = hybrid_status_dlc
+ if status_bus is not None:
+ fingerprint[status_bus][EV_MODE_STATUS_ADDR] = status_dlc
+ return CarInterface.get_params(candidate, fingerprint, [], False, False, False)
+
+
+@pytest.mark.parametrize(("candidate", "hybrid", "status_bus", "status_dlc", "expected"), (
+ (CAR.HYUNDAI_SANTAFE_MX5_HEV, True, 0, 32, True),
+ (CAR.HYUNDAI_SANTAFE_MX5_HEV, False, 0, 32, False),
+ (CAR.HYUNDAI_SANTAFE_MX5_HEV, True, None, 32, False),
+ (CAR.HYUNDAI_SANTAFE_MX5_HEV, True, 1, 32, False),
+ (CAR.HYUNDAI_SANTAFE_MX5_HEV, True, 0, 16, False),
+ (CAR.KIA_SORENTO_4TH_GEN, False, None, 32, False),
+ # Shared ICE/HEV/PHEV candidates rely on the observed ECAN capability frames, not their model name.
+ (CAR.HYUNDAI_TUCSON_4TH_GEN, True, 0, 32, True),
+ (CAR.HYUNDAI_TUCSON_4TH_GEN, False, 0, 32, False),
+ (CAR.KIA_SORENTO_HEV_4TH_GEN, True, 0, 32, True),
+ (CAR.HYUNDAI_KONA_HEV_2ND_GEN, True, 0, 32, True),
+ (CAR.HYUNDAI_KONA_HEV_2ND_GEN, False, 0, 32, False),
+ (CAR.HYUNDAI_ELANTRA_HEV_2021, True, 0, 32, False),
+))
+def test_ev_mode_capability(candidate, hybrid, status_bus, status_dlc, expected):
+ CP = get_params(candidate, hybrid=hybrid, status_bus=status_bus, status_dlc=status_dlc)
+ assert bool(CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230) == expected
+
+
+@pytest.mark.parametrize(("hybrid_status_bus", "hybrid_status_dlc"), (
+ (1, CANFD_HYBRID_STATUS_DLC),
+ (0, 16),
+))
+def test_ev_mode_capability_requires_ecan_hybrid_status_dlc32(hybrid_status_bus, hybrid_status_dlc):
+ CP = get_params(CAR.HYUNDAI_SANTAFE_MX5_HEV, hybrid_status_bus=hybrid_status_bus,
+ hybrid_status_dlc=hybrid_status_dlc)
+
+ assert not bool(CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230)
+
+
+def test_0x105_and_ev_status_without_0xfa_do_not_enable_ev_mode():
+ CP = get_params(CAR.HYUNDAI_TUCSON_4TH_GEN, hybrid=True, hybrid_status=False)
+
+ assert bool(CP.flags & HyundaiFlags.HYBRID)
+ assert not bool(CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230)
+
+
+def test_ev_mode_display_capability_does_not_change_hybrid_safety_classification():
+ CP = get_params(CAR.HYUNDAI_TUCSON_4TH_GEN, hybrid=False, hybrid_status=True)
+
+ assert not bool(CP.flags & HyundaiFlags.HYBRID)
+ assert bool(CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230)
+
+
+def test_ev_mode_capability_uses_the_detected_ecan_offset():
+ CP = get_params(CAR.KIA_SORENTO_HEV_4TH_GEN, hybrid_bus=4, hybrid_status_bus=4, status_bus=4)
+
+ assert bool(CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230)
+
+
+def test_ev_mode_parser_registration_is_capability_gated():
+ supported = get_params(CAR.HYUNDAI_SANTAFE_MX5_HEV)
+ unsupported = get_params(CAR.KIA_SORENTO_4TH_GEN, hybrid=False, status_bus=1, status_dlc=16)
+
+ supported_parser = CarState.get_can_parsers_canfd(None, supported)[Bus.pt]
+ unsupported_parser = CarState.get_can_parsers_canfd(None, unsupported)[Bus.pt]
+
+ assert EV_MODE_STATUS_ADDR in supported_parser.addresses
+ assert supported_parser.message_states[EV_MODE_STATUS_ADDR].ignore_alive
+ assert supported_parser.message_states[EV_MODE_STATUS_ADDR].ignore_counter
+ assert EV_MODE_STATUS_ADDR not in unsupported_parser.addresses
+
+
+def test_sorento_ice_corner_radar_status_does_not_enable_ev_mode():
+ Params().put_int("HyundaiCameraSCC", 1)
+ Params().put_int("CanfdHDA2", 1)
+
+ fingerprint = gen_empty_fingerprint()
+ fingerprint[1][0x230] = 16 # Actual Sorento ICE ACAN corner-radar status frame.
+ CP = CarInterface.get_params(CAR.KIA_SORENTO_4TH_GEN, fingerprint, [], False, False, False)
+ parser = CarState.get_can_parsers_canfd(None, CP)[Bus.pt]
+
+ assert not bool(CP.extFlags & HyundaiExtFlags.EV_MODE_STATUS_230)
+ assert EV_MODE_STATUS_ADDR not in parser.addresses
+
+
+def test_ev_mode_state_requires_a_fresh_dlc32_frame():
+ CP = get_params(CAR.HYUNDAI_SANTAFE_MX5_HEV)
+ parser = CarState.get_can_parsers_canfd(None, CP)[Bus.pt]
+ packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
+
+ assert _get_ev_mode_state(parser) == (False, False)
+
+ timestamp = 1_000_000_000
+ wrong_bus_short_status = (EV_MODE_STATUS_ADDR, b"\x00" * 16, 1)
+ parser.update([timestamp, [wrong_bus_short_status]])
+ assert _get_ev_mode_state(parser) == (False, False)
+
+ ev_active = packer.make_can_msg(EV_MODE_STATUS_MSG, parser.bus, {"COUNTER": 1, EV_MODE_STATUS_SIGNAL: 6})
+ parser.update([timestamp + 100_000_000, [ev_active]])
+ assert _get_ev_mode_state(parser) == (True, True)
+
+ ev_inactive = packer.make_can_msg(EV_MODE_STATUS_MSG, parser.bus, {"COUNTER": 2, EV_MODE_STATUS_SIGNAL: 3})
+ parser.update([timestamp + 200_000_000, [ev_inactive]])
+ assert _get_ev_mode_state(parser) == (False, True)
+
+ parser.dat[EV_MODE_STATUS_ADDR] = b"\x00" * 16
+ assert _get_ev_mode_state(parser) == (False, False)
+
+ parser.dat[EV_MODE_STATUS_ADDR] = ev_inactive[1]
+ parser.update([timestamp + 200_000_000 + EV_MODE_STATUS_TIMEOUT_NS + 1, []])
+ assert not parser.bus_timeout
+ assert _get_ev_mode_state(parser) == (False, False)
+
+
+@pytest.mark.parametrize("mode", range(16))
+def test_ev_mode_enum_mapping(mode):
+ CP = get_params(CAR.HYUNDAI_SANTAFE_MX5_HEV)
+ parser = CarState.get_can_parsers_canfd(None, CP)[Bus.pt]
+ packer = CANPacker(DBC[CP.carFingerprint][Bus.pt])
+ msg = packer.make_can_msg(EV_MODE_STATUS_MSG, parser.bus, {"COUNTER": mode, EV_MODE_STATUS_SIGNAL: mode})
+
+ parser.update([1_000_000_000, [msg]])
+
+ assert int(parser.vl[EV_MODE_STATUS_MSG][EV_MODE_STATUS_SIGNAL]) == mode
+ assert _get_ev_mode_state(parser) == (mode in EV_MODE_ACTIVE_VALUES, True)
+
+
+@pytest.mark.parametrize(("payload", "expected_mode", "expected_active"), (
+ ("758139048402000000000000000000000000d3009805001c24000000c05dc80f", 1, True),
+ ("4d466f048402000000000000000000000000bf007408001c24000000c05dc80f", 2, True),
+ ("32206e048402000000000000000000000000c9007418001c24000000c05dc80f", 6, True),
+ # Route 455 mode 3 was a false positive with the old single-bit 0x230 interpretation.
+ ("4f935e0484020000000000000000000000004400640d001c10000000c05dc40f", 3, False),
+ ("066558048402000000000000000000000000c4003020001c24000000c05dc80f", 8, False),
+ ("059683048402000000000000000000000000a1008425001c24000000c05dc80f", 9, False),
+ ("011305048402000000000000000000000000d600a829001c24000000c05dc80f", 10, False),
+))
+def test_ev_mode_dbc_decodes_real_mx5_frames(payload, expected_mode, expected_active):
+ parser = CANParser("hyundai_canfd_generated", [(EV_MODE_STATUS_MSG, math.nan)], 0)
+ updated = parser.update([1_000_000_000, [(EV_MODE_STATUS_ADDR, bytes.fromhex(payload), 0)]])
+
+ assert updated == {EV_MODE_STATUS_ADDR}
+ assert int(parser.vl[EV_MODE_STATUS_MSG][EV_MODE_STATUS_SIGNAL]) == expected_mode
+ assert _get_ev_mode_state(parser) == (expected_active, True)
+
+
+def test_ev_mode_rejects_checksum_corruption():
+ CP = get_params(CAR.HYUNDAI_SANTAFE_MX5_HEV)
+ parser = CarState.get_can_parsers_canfd(None, CP)[Bus.pt]
+ payload = bytearray.fromhex("32206e048402000000000000000000000000c9007418001c24000000c05dc80f")
+ payload[-1] ^= 1
+
+ parser.update([1_000_000_000, [(EV_MODE_STATUS_ADDR, bytes(payload), parser.bus)]])
+
+ assert EV_MODE_STATUS_ADDR not in parser.dat
+ assert _get_ev_mode_state(parser) == (False, False)
+
+
+def test_ev_mode_fields_default_invalid():
+ state = structs.CarState()
+ assert not state.evModeActive
+ assert not state.evModeValid
+
+
+def test_ev_mode_parser_is_optional_for_can_validity():
+ CP = get_params(CAR.HYUNDAI_SANTAFE_MX5_HEV)
+ parser = CarState.get_can_parsers_canfd(None, CP)[Bus.pt]
+ state = parser.message_states[EV_MODE_STATUS_ADDR]
+
+ assert state.ignore_alive
+ assert state.ignore_counter
diff --git a/iqdbc_repo/iqdbc/car/hyundai/tests/test_hyundai.py b/iqdbc_repo/iqdbc/car/hyundai/tests/test_hyundai.py
index fdbc357..edf1f73 100644
--- a/iqdbc_repo/iqdbc/car/hyundai/tests/test_hyundai.py
+++ b/iqdbc_repo/iqdbc/car/hyundai/tests/test_hyundai.py
@@ -6,13 +6,11 @@ from iqdbc.car import gen_empty_fingerprint
from iqdbc.car.structs import CarParams
from iqdbc.car.fw_versions import build_fw_dict
from iqdbc.car.hyundai.interface import CarInterface
-from iqdbc.car.hyundai.hyundaicanfd import CanBus
from iqdbc.car.hyundai.radar_interface import RADAR_START_ADDR
-from iqdbc.car.hyundai.values import CAMERA_SCC_CAR, CANFD_CAR, CAN_GEARS, CAR, CHECKSUM, DATE_FW_ECUS, \
- HYBRID_CAR, EV_CAR, FW_QUERY_CONFIG, LEGACY_SAFETY_MODE_CAR, CANFD_FUZZY_WHITELIST, \
- UNSUPPORTED_LONGITUDINAL_CAR, PLATFORM_CODE_ECUS, HYUNDAI_VERSION_REQUEST_LONG, \
- HyundaiFlags, get_platform_codes, HyundaiSafetyFlags, \
- NON_SCC_CAR
+from iqdbc.car.hyundai.values import CANFD_CAR, CAN_GEARS, CAR, CHECKSUM, DATE_FW_ECUS, \
+ HYBRID_CAR, EV_CAR, FW_QUERY_CONFIG, LEGACY_SAFETY_MODE_CAR, \
+ PLATFORM_CODE_ECUS, HYUNDAI_VERSION_REQUEST_LONG, \
+ HyundaiFlags, get_platform_codes, HyundaiSafetyFlags
from iqdbc.car.hyundai.fingerprints import FW_VERSIONS
Ecu = CarParams.Ecu
@@ -45,16 +43,8 @@ CANFD_EXPECTED_ECUS = {Ecu.fwdCamera, Ecu.fwdRadar}
class TestHyundaiFingerprint:
- def test_feature_detection(self):
- # LKA steering
- for lka_steering in (True, False):
- fingerprint = gen_empty_fingerprint()
- if lka_steering:
- cam_can = CanBus(None, fingerprint).CAM
- fingerprint[cam_can] = [0x50, 0x110] # LKA steering messages
- CP = CarInterface.get_params(CAR.KIA_EV6, fingerprint, [], False, False, False)
- assert bool(CP.flags & HyundaiFlags.CANFD_LKA_STEERING) == lka_steering
-
+ def test_feature_detection(self, monkeypatch, tmp_path):
+ monkeypatch.setenv("PARAMS_ROOT", str(tmp_path))
# radar available
for radar in (True, False):
fingerprint = gen_empty_fingerprint()
@@ -74,19 +64,20 @@ class TestHyundaiFingerprint:
# Test no EV/HEV in any gear lists (should all use ELECT_GEAR)
assert set.union(*CAN_GEARS.values()) & (HYBRID_CAR | EV_CAR) == set()
- # Test CAN FD car not in CAN feature lists
- can_specific_feature_list = set.union(*CAN_GEARS.values(), *CHECKSUM.values(), LEGACY_SAFETY_MODE_CAR, UNSUPPORTED_LONGITUDINAL_CAR, CAMERA_SCC_CAR)
+ # Test CAN FD cars are not classified with classic-CAN-only parsing or safety modes.
+ can_specific_feature_list = set.union(*CAN_GEARS.values(), *CHECKSUM.values(), LEGACY_SAFETY_MODE_CAR)
for car_model in CANFD_CAR:
assert car_model not in can_specific_feature_list, "CAN FD car unexpectedly found in a CAN feature list"
def test_hybrid_ev_sets(self):
assert HYBRID_CAR & EV_CAR == set(), "Shared cars between hybrid and EV"
- assert CANFD_CAR & HYBRID_CAR == set(), "Hard coding CAN FD cars as hybrid is no longer supported"
+ assert HYBRID_CAR <= set(CAR)
+ assert EV_CAR <= set(CAR)
def test_canfd_ecu_whitelist(self):
# Asserts only expected Ecus can exist in database for CAN-FD cars
for car_model in CANFD_CAR:
- ecus = {fw[0] for fw in FW_VERSIONS[car_model].keys()}
+ ecus = {fw[0] for fw in FW_VERSIONS.get(car_model, {}).keys()}
ecus_not_in_whitelist = ecus - CANFD_EXPECTED_ECUS
ecu_strings = ", ".join([f"Ecu.{ecu}" for ecu in ecus_not_in_whitelist])
assert len(ecus_not_in_whitelist) == 0, \
@@ -158,8 +149,6 @@ class TestHyundaiFingerprint:
continue
if platform_code_ecu == Ecu.eps and car_model in no_eps_platforms:
continue
- if car_model in NON_SCC_CAR:
- continue
assert platform_code_ecu in [e[0] for e in ecus]
def test_fw_format(self, subtests):
@@ -174,9 +163,6 @@ class TestHyundaiFingerprint:
if ecu[0] not in PLATFORM_CODE_ECUS:
continue
- if car_model in NON_SCC_CAR:
- continue
-
codes = set()
for fw in fws:
result = get_platform_codes([fw])
@@ -225,15 +211,6 @@ class TestHyundaiFingerprint:
(b"ON-S9100", b"190405"), (b"ON-S9100", b"190720")}
def test_fuzzy_excluded_platforms(self):
- # Asserts a list of platforms that will not fuzzy fingerprint with platform codes due to them being shared.
- # This list can be shrunk as we combine platforms and detect features
- excluded_platforms = {
- CAR.GENESIS_G70, # shared platform code, part number, and date
- CAR.GENESIS_G70_2020,
- }
- excluded_platforms |= CANFD_CAR - EV_CAR - CANFD_FUZZY_WHITELIST # shared platform codes
- excluded_platforms |= NO_DATES_PLATFORMS # date codes are required to match
-
platforms_with_shared_codes = set()
for platform, fw_by_addr in FW_VERSIONS.items():
car_fw = []
@@ -243,9 +220,6 @@ class TestHyundaiFingerprint:
car_fw.append(CarParams.CarFw(ecu=ecu_name, fwVersion=fw, address=addr,
subAddress=0 if sub_addr is None else sub_addr))
- if platform in NON_SCC_CAR:
- continue
-
CP = CarParams(carFw=car_fw)
matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw), CP.carVin, FW_VERSIONS)
if len(matches) == 1:
@@ -253,4 +227,6 @@ class TestHyundaiFingerprint:
else:
platforms_with_shared_codes.add(platform)
- assert platforms_with_shared_codes == excluded_platforms
+ # A unique fuzzy match must always resolve back to the platform that supplied the firmware.
+ # Ambiguity is expected for shared platform codes and for platforms without parseable dates.
+ assert {CAR.GENESIS_G70, CAR.GENESIS_G70_2020} <= platforms_with_shared_codes
diff --git a/iqdbc_repo/iqdbc/car/hyundai/tests/test_integration.py b/iqdbc_repo/iqdbc/car/hyundai/tests/test_integration.py
new file mode 100644
index 0000000..5dfb818
--- /dev/null
+++ b/iqdbc_repo/iqdbc/car/hyundai/tests/test_integration.py
@@ -0,0 +1,53 @@
+import pytest
+
+from iqdbc.car import gen_empty_fingerprint, structs
+from iqdbc.car.hyundai.interface import CarInterface
+from iqdbc.car.hyundai.values import CAR, HyundaiFlagsIQ, HyundaiSafetyFlagsIQ
+
+
+@pytest.mark.parametrize("candidate", list(CAR), ids=lambda candidate: candidate.value)
+@pytest.mark.parametrize("alpha_long", (False, True), ids=("stock_long", "openpilot_long"))
+def test_all_platform_state_controller_and_radar(candidate, alpha_long, monkeypatch, tmp_path):
+ """Every declared HKG platform must initialize and execute one complete interface cycle."""
+ monkeypatch.setenv("PARAMS_ROOT", str(tmp_path / candidate.value))
+ fingerprint = gen_empty_fingerprint()
+
+ cp = CarInterface.get_params(candidate, fingerprint, [], alpha_long, False, False)
+ cp_iq = CarInterface.get_params_iq(cp, candidate, fingerprint, [], alpha_long, False, False)
+ interface = CarInterface(cp, cp_iq)
+
+ state, state_iq = interface.update([])
+ actuators, can_sends = interface.apply(structs.CarControl().as_reader(), structs.IQCarControl())
+ radar = interface.RadarInterface(cp, cp_iq)
+ radar_result = radar.update([])
+
+ assert state.vEgo == 0.0
+ assert state_iq is not None
+ assert actuators is not None
+ assert isinstance(can_sends, list)
+ assert radar_result is None
+
+
+def test_parameter_defaults_do_not_require_persisted_fingerprint(monkeypatch, tmp_path):
+ """A clean installation must not crash when carrotpilot-specific Params have not been written yet."""
+ monkeypatch.setenv("PARAMS_ROOT", str(tmp_path))
+ fingerprint = gen_empty_fingerprint()
+
+ cp = CarInterface.get_params(CAR.HYUNDAI_SONATA, fingerprint, [], False, False, False)
+ cp_iq = CarInterface.get_params_iq(cp, CAR.HYUNDAI_SONATA, fingerprint, [], False, False, False)
+ interface = CarInterface(cp, cp_iq)
+
+ state, _ = interface.update([])
+ assert state.vEgo == 0.0
+
+
+def test_classic_lfa_button_capability_survives_iq_module_removal(monkeypatch, tmp_path):
+ monkeypatch.setenv("PARAMS_ROOT", str(tmp_path))
+ fingerprint = gen_empty_fingerprint()
+ fingerprint[0][0x391] = 8
+
+ cp = CarInterface.get_params(CAR.HYUNDAI_SONATA, fingerprint, [], False, False, False)
+ cp_iq = CarInterface.get_params_iq(cp, CAR.HYUNDAI_SONATA, fingerprint, [], False, False, False)
+
+ assert cp_iq.flags & HyundaiFlagsIQ.HAS_LFA_BUTTON
+ assert cp_iq.iqSafetyFlags & HyundaiSafetyFlagsIQ.HAS_LDA_BUTTON
diff --git a/iqdbc_repo/iqdbc/car/hyundai/tests/test_radar.py b/iqdbc_repo/iqdbc/car/hyundai/tests/test_radar.py
new file mode 100644
index 0000000..ceace1f
--- /dev/null
+++ b/iqdbc_repo/iqdbc/car/hyundai/tests/test_radar.py
@@ -0,0 +1,326 @@
+import math
+
+import pytest
+
+from iqdbc.can import CANParser
+from iqdbc.car import Bus, structs
+import iqdbc.car.hyundai.hyundaicanfd as hyundaicanfd
+import iqdbc.car.hyundai.radar_interface as radar_interface_module
+from iqdbc.car.hyundai.radar_interface import (
+ CORNER_OBJECT_STABLE_TRACK_ID_START,
+ RADAR_MSG_COUNT3,
+ RADAR_MSG_COUNT4,
+ RADAR_START_ADDR_CANFD3,
+ CornerObjectTrackIdManager,
+ RadarInterface,
+ corner_object_position_valid,
+)
+from iqdbc.car.hyundai.values import CAR, HyundaiExtFlags, HyundaiFlags
+
+
+class TestDensoRadar:
+ @staticmethod
+ def parse(addr, dat):
+ name = f"RADAR_TRACK_{addr:x}"
+ parser = CANParser("hyundai_kia_denso_front_radar_generated", [(name, 20)], 1)
+ parser.update([0, [(addr, bytes.fromhex(dat), 1)]])
+ return parser.vl[name]
+
+ def test_active_track_signals(self):
+ # Person walking toward the parked car, left of the camera center.
+ track = self.parse(0x503, "bc047efcc1fe8b00")
+
+ assert track["LONG_DIST"] == pytest.approx(7.1875)
+ assert track["LAT_DIST"] == pytest.approx(-1.625)
+ assert track["REL_SPEED"] == pytest.approx(-0.734375)
+ assert track["OBJECT_STATE"] == 3
+
+ def test_empty_track(self):
+ track = self.parse(0x507, "53fff80000000081")
+
+ assert track["LONG_DIST"] == pytest.approx(409.55)
+ assert track["LAT_DIST"] == 0
+ assert track["REL_SPEED"] == 0
+ assert track["OBJECT_STATE"] == 0
+
+ def test_long_range_lateral_distance(self):
+ # Real driving sample: treating the signed field as -12 degrees would put
+ # this target about 34 m sideways at 161 m. It is instead -3.0 m lateral.
+ track = self.parse(0x506, "b664eafa00cd230b")
+
+ assert track["LONG_DIST"] == pytest.approx(161.4625)
+ assert track["LAT_DIST"] == pytest.approx(-3.0)
+ assert track["OBJECT_STATE"] == 3
+
+ def test_parser_selection_and_point_conversion(self, monkeypatch):
+ class FakeParams:
+ def get_int(self, key):
+ return 1 if key == "EnableRadarTracks" else 0
+
+ monkeypatch.setattr(radar_interface_module, "Params", FakeParams)
+ cp = structs.CarParams()
+ cp.carFingerprint = CAR.KIA_SORENTO
+ cp.flags = 0
+ cp.extFlags = HyundaiExtFlags.RADAR_GROUP4.value
+ cp.radarUnavailable = False
+ cp.safetyConfigs = [structs.CarParams.SafetyConfig()]
+
+ radar_interface = RadarInterface(cp)
+
+ assert radar_interface.radar_group4
+ assert RADAR_MSG_COUNT4 == 8
+ assert radar_interface.radar_msg_count == RADAR_MSG_COUNT4
+ assert radar_interface.trigger_msg_tracks == 0x507
+
+ active_dat = bytes.fromhex("bc047efcc1fe8b00")
+ empty_dat = bytes.fromhex("bcfff80000000081")
+ packets = [(addr, active_dat if addr == 0x503 else empty_dat, 1) for addr in range(0x500, 0x508)]
+ radar_data = radar_interface.update([0, packets])
+ point = next(point for point in radar_data.points if point.trackId == 35)
+
+ assert point.measured
+ assert point.dRel == pytest.approx(7.1875)
+ assert point.yRel == pytest.approx(1.625)
+ assert point.vRel == pytest.approx(-0.734375)
+ assert math.isnan(point.aRel)
+
+ # EN: Confirm that the long-range sample survives the filter and converts
+ # radar-left-negative to openpilot-left-positive coordinates.
+ # KO: 장거리 샘플의 필터 통과와 레이더 좌측 음수 좌표가 openpilot 좌측
+ # 양수 좌표로 변환되는지 확인함.
+ long_range_dat = bytes.fromhex("b664eafa00cd230b")
+ packets = [(addr, long_range_dat if addr == 0x506 else empty_dat, 1) for addr in range(0x500, 0x508)]
+ radar_data = radar_interface.update([0, packets])
+ point = next(point for point in radar_data.points if point.trackId == 38)
+
+ assert point.dRel == pytest.approx(161.4625)
+ assert point.yRel == pytest.approx(3.0)
+
+ # EN: A state-0 raw detection must not enter a stable tracked-object slot.
+ # KO: 상태 0인 raw detection이 안정적인 추적 객체 슬롯에 들어오지 않음을 확인함.
+ raw_detection = bytes.fromhex("d702f4fc200000e4")
+ packets = [(addr, raw_detection if addr == 0x503 else empty_dat, 1) for addr in range(0x500, 0x508)]
+ radar_data = radar_interface.update([0, packets])
+ assert not radar_data.points
+
+ # EN: A real confirmed track beyond the former 205 m limit remains valid.
+ # KO: 기존 205m 상한을 넘는 실제 확정 트랙도 유효하게 유지됨.
+ confirmed_213m_track = bytes.fromhex("35854c0780f163e0")
+ packets = [(addr, confirmed_213m_track if addr == 0x503 else empty_dat, 1) for addr in range(0x500, 0x508)]
+ radar_data = radar_interface.update([0, packets])
+ point = next(point for point in radar_data.points if point.trackId == 35)
+ assert point.dRel == pytest.approx(213.275)
+ assert point.yRel == pytest.approx(-3.75)
+
+ # EN: The 325 m boundary is rejected, leaving ample separation from the
+ # 409.55 m empty-slot sentinel.
+ # KO: 325m 경계값을 제외해 409.55m 빈 슬롯 값과 충분한 간격을 확보함.
+ boundary_track = bytes.fromhex("bccb200000000300")
+ packets = [(addr, boundary_track if addr == 0x503 else empty_dat, 1) for addr in range(0x500, 0x508)]
+ radar_data = radar_interface.update([0, packets])
+ assert not radar_data.points
+
+ # EN: The wider profile keeps a real stable track at 4.875 m, covering more
+ # of the outer adjacent lane than the conservative 4.5 m profile.
+ # KO: 넓어진 필터에서 4.875m의 실제 안정 트랙을 유지해 보수적인 4.5m
+ # 설정보다 바깥쪽 인접 차선을 더 넓게 포함함.
+ outer_lane_track = bytes.fromhex("d80b66f640000300")
+ packets = [(addr, outer_lane_track if addr == 0x503 else empty_dat, 1) for addr in range(0x500, 0x508)]
+ radar_data = radar_interface.update([0, packets])
+ point = next(point for point in radar_data.points if point.trackId == 35)
+ assert point.yRel == pytest.approx(4.875)
+
+ # EN: Tracks beyond the widened envelope are rejected as roadside clutter;
+ # this payload differs only in lateral distance (-7.0 m).
+ # KO: 넓어진 범위를 벗어난 트랙은 도로변 잡음으로 제외함. 이 payload는
+ # 횡방향 거리(-7.0m)만 다름.
+ far_side_reflection = bytes.fromhex("d80b66f200000300")
+ packets = [(addr, far_side_reflection if addr == 0x503 else empty_dat, 1) for addr in range(0x500, 0x508)]
+ radar_data = radar_interface.update([0, packets])
+ assert not radar_data.points
+
+
+class TestRadarGroup3:
+ @staticmethod
+ def parse(addr, dat):
+ name = f"RADAR_TRACK_{addr:x}"
+ parser = CANParser("hyundai_canfd_radar_generated", [(name, 20)], 1)
+ parser.update([0, [(addr, bytes.fromhex(dat), 1)]])
+ return parser.vl[name]
+
+ def test_group3_active_track(self):
+ track = self.parse(0x406, "e1043b0f02590e692a227e16f80fe00f28fcc753a20a0000")
+
+ assert track["OBJECT_LENGTH"] == pytest.approx(4.4)
+ assert track["LONG_DIST"] == pytest.approx(55.4)
+ assert track["LAT_DIST"] == pytest.approx(-3.0)
+ assert track["REL_SPEED"] == pytest.approx(4.4)
+
+ def test_group3_empty_track(self):
+ track = self.parse(0x407, "c03d3b0000000000ff0700000000000000d0020000000000")
+
+ assert track["OBJECT_LENGTH"] == 0
+ assert track["LONG_DIST"] == pytest.approx(204.7)
+ assert track["LAT_DIST"] == 0
+ assert track["REL_SPEED"] == 0
+
+ def test_group3_parser_selection(self, monkeypatch):
+ class FakeParams:
+ def get_int(self, key):
+ return 1 if key == "EnableRadarTracks" else 0
+
+ monkeypatch.setattr(radar_interface_module, "Params", FakeParams)
+ monkeypatch.setattr(hyundaicanfd, "Params", FakeParams)
+ cp = structs.CarParams()
+ cp.carFingerprint = next(car for car, dbc in radar_interface_module.DBC.items() if "hyundai_canfd" in dbc[Bus.pt])
+ cp.flags = HyundaiFlags.CANFD.value
+ cp.extFlags = HyundaiExtFlags.RADAR_GROUP3.value
+ cp.radarUnavailable = False
+ cp.safetyConfigs = [structs.CarParams.SafetyConfig()]
+
+ radar_interface = RadarInterface(cp)
+
+ assert radar_interface.radar_group3
+ assert radar_interface.radar_start_addr == RADAR_START_ADDR_CANFD3
+ assert radar_interface.radar_msg_count == RADAR_MSG_COUNT3
+ assert radar_interface.trigger_msg_tracks == 0x41D
+
+ active_dat = bytes.fromhex("e1043b0f02590e692a227e16f80fe00f28fcc753a20a0000")
+ empty_dat = bytes.fromhex("c03d3b0000000000ff0700000000000000d0020000000000")
+ packets = [(addr, active_dat if addr == 0x406 else empty_dat, 1) for addr in range(0x400, 0x41E)]
+ radar_data = radar_interface.update([0, packets])
+ point = next(point for point in radar_data.points if point.trackId == 38)
+
+ assert point.measured
+ assert point.dRel == pytest.approx(53.1)
+ assert point.yRel == pytest.approx(-3.0)
+ assert point.vRel == pytest.approx(4.4)
+
+
+class TestCornerRadarObjectIdentity:
+ @staticmethod
+ def set_bits(data, start, size, value):
+ for offset in range(size):
+ bit = start + offset
+ data[bit // 8] |= ((value >> offset) & 1) << (bit % 8)
+
+ @pytest.mark.parametrize(
+ "dbc,msg_name,addr,age_signal,id_signal,age_start,id_start",
+ (
+ ("hyundai_canfd_corner_radar_180_generated", "CORNER_RADAR_180_OBJECTS_180", 0x180,
+ "SLOT1_AGE", "SLOT1_OBJECT_ID", 32, 44),
+ ("hyundai_canfd_corner_radar_235_generated", "CORNER_RADAR_235_OBJECTS_235", 0x235,
+ "OBJ_AGE", "OBJ_OBJECT_ID", 32, 44),
+ ),
+ )
+ def test_object_identity_signals(self, dbc, msg_name, addr, age_signal, id_signal, age_start, id_start):
+ data = bytearray(32)
+ self.set_bits(data, age_start, 8, 23)
+ self.set_bits(data, id_start, 7, 46)
+ parser = CANParser(dbc, [(msg_name, 33)], 1)
+ parser.update([0, [(addr, bytes(data), 1)]])
+
+ assert parser.vl[msg_name][age_signal] == 23
+ assert parser.vl[msg_name][id_signal] == 46
+
+ def test_track_id_survives_slot_move_and_resets_with_age(self):
+ manager = CornerObjectTrackIdManager()
+ first_id = manager.get_track_id("corner180", object_id=108, age=240)
+
+ assert first_id == CORNER_OBJECT_STABLE_TRACK_ID_START
+ assert manager.get_track_id("corner180", object_id=108, age=241) == first_id
+ assert manager.get_track_id("corner235", object_id=108, age=241) != first_id
+ assert manager.get_track_id("corner180", object_id=108, age=2) != first_id
+
+ def test_clipped_side_object_position_is_valid(self):
+ assert corner_object_position_valid(0.0, 2.8)
+ assert corner_object_position_valid(25.0, 0.2)
+ assert not corner_object_position_valid(0.0, 0.0)
+ assert not corner_object_position_valid(0.0, 5.0)
+
+
+class TestCornerRadar430CandidateFilter:
+ @staticmethod
+ def slot_word(distance_raw, meta13=0, b2=10, b3=2):
+ return distance_raw | (meta13 << 13) | (b2 << 16) | (b3 << 24)
+
+ @classmethod
+ def message(cls, slots):
+ words = [0x010d1f40] * 7
+ for slot, word in slots.items():
+ words[slot - 1] = word
+
+ dat = bytearray(32)
+ for idx, word in enumerate(words):
+ dat[4 + idx * 4:8 + idx * 4] = int(word).to_bytes(4, "little")
+ return bytes(dat)
+
+ @staticmethod
+ def build_interface(monkeypatch):
+ class FakeParams:
+ def get_int(self, key):
+ return 1 if key == "EnableCornerRadar" else 0
+
+ monkeypatch.setattr(radar_interface_module, "Params", FakeParams)
+ monkeypatch.setattr(hyundaicanfd, "Params", FakeParams)
+ cp = structs.CarParams()
+ cp.carFingerprint = next(car for car, dbc in radar_interface_module.DBC.items() if "hyundai_canfd" in dbc[Bus.pt])
+ cp.flags = HyundaiFlags.CANFD.value
+ cp.extFlags = HyundaiExtFlags.CORNER_RADAR_OBJECTS_430.value
+ cp.radarUnavailable = True
+ cp.safetyConfigs = [structs.CarParams.SafetyConfig()]
+ return RadarInterface(cp)
+
+ @staticmethod
+ def update_frames(radar_interface, packets, frames=5):
+ radar_data = None
+ for _ in range(frames):
+ radar_data = radar_interface.update([0, packets])
+ return radar_data
+
+ def test_430_promotes_supported_neighbor_bins(self, monkeypatch):
+ radar_interface = self.build_interface(monkeypatch)
+ empty = self.message({})
+ supported_bins = self.message({
+ 6: self.slot_word(1000),
+ 7: self.slot_word(1004),
+ })
+ packets = [(addr, supported_bins if addr == 0x436 else empty, 1) for addr in range(0x430, 0x438)]
+ packets += [(addr, empty, 1) for addr in range(0x440, 0x448)]
+
+ radar_data = self.update_frames(radar_interface, packets)
+ points = {point.trackId: point for point in radar_data.points}
+
+ assert points[300].measured
+ assert points[300].dRel == pytest.approx(50.1)
+ assert points[300].yRel == pytest.approx(2.0)
+ assert points[300].yvRel == 0.0
+
+ def test_430_expires_noncenter_inward_yvrel(self, monkeypatch):
+ radar_interface = self.build_interface(monkeypatch)
+ empty = self.message({})
+ frame_defs = (
+ (0x431, 4, 5),
+ (0x433, 3, 4),
+ (0x435, 2, 3),
+ (0x430, 5, 6),
+ (0x432, 4, 5),
+ (0x434, 3, 4),
+ (0x436, 2, 3),
+ )
+
+ radar_data = None
+ for addr, first_slot, second_slot in frame_defs:
+ msg = self.message({
+ first_slot: self.slot_word(1000),
+ second_slot: self.slot_word(1004),
+ })
+ packets = [(a, msg if a == addr else empty, 1) for a in range(0x430, 0x438)]
+ packets += [(a, empty, 1) for a in range(0x440, 0x448)]
+ radar_data = radar_interface.update([0, packets])
+ radar_data = self.update_frames(radar_interface, packets, frames=3)
+ points = {point.trackId: point for point in radar_data.points}
+
+ assert points[300].measured
+ assert points[300].yRel == pytest.approx(2.0)
+ assert points[300].yvRel == 0.0
diff --git a/iqdbc_repo/iqdbc/car/hyundai/values.py b/iqdbc_repo/iqdbc/car/hyundai/values.py
index e2434dd..3fd7310 100644
--- a/iqdbc_repo/iqdbc/car/hyundai/values.py
+++ b/iqdbc_repo/iqdbc/car/hyundai/values.py
@@ -1,21 +1,37 @@
import re
from dataclasses import dataclass, field
-from enum import IntFlag
+from enum import Enum, IntFlag
from iqdbc.car import Bus, CarSpecs, DbcDict, PlatformConfig, Platforms, uds
+from iqdbc.car.lateral import AngleSteeringLimits
from iqdbc.car.common.conversions import Conversions as CV
from iqdbc.car.structs import CarParams
-from iqdbc.car.docs_definitions import CarHarness, CarDocs, CarParts, SupportType
+from iqdbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column
from iqdbc.car.fw_query_definitions import FwQueryConfig, Request, p16
-from iqdbc.lvbs.car.hyundai.values import HyundaiFlagsIQ
-
Ecu = CarParams.Ecu
class CarControllerParams:
- ACCEL_MIN = -3.5 # m/s
- ACCEL_MAX = 2.0 # m/s
+ ACCEL_MIN = -4.0 # m/s
+ ACCEL_MAX = 2.5 # m/s
+ ANGLE_LIMITS: AngleSteeringLimits = AngleSteeringLimits(
+ # LKAS angle command is unlimited, but LFA is limited to 176.7 deg (but does not fault if requesting above)
+ 175, # deg
+ # stock comma's
+ #([0, 9, 16, 25], [1.4, 0.6, 0.4, 0.1]),
+ #([0, 9, 16, 25], [1.4, 0.7, 0.5, 0.1]),
+ ([0, 9, 16, 25], [1.8, 1.6, 1.3, 0.8]),
+ ([0, 9, 16, 25], [2.4, 2.0, 1.6, 1.0]),
+ #([0, 9, 16, 25], [1.6, 1.0, 0.6, 0.15]),
+ #([0, 9, 16, 25], [2.0, 1.2, 0.8, 0.28]),
+ )
+ # Stock LFA system is seen sending 250 max, but for LKAS events it's 175 max.
+ # 250 can at least achieve 4 m/s^2, 80 corresponds to ~2.5 m/s^2
+ ANGLE_MAX_TORQUE = 200 # The maximum amount of torque that will be allowed
+ ANGLE_MIN_TORQUE = 25 # equivalent to ~0.8 m/s^2 of torque (based on ANGLE_MAX_TORQUE) when overriding
+ ANGLE_TORQUE_UP_RATE = 8 #2 # Indicates how fast the torque ramps up after user intervention.
+ ANGLE_TORQUE_DOWN_RATE = 12 #4 Indicates how fast the torque ramps down during user intervention (handing off).
def __init__(self, CP):
self.STEER_DELTA_UP = 3
@@ -41,20 +57,17 @@ class CarControllerParams:
CAR.KIA_OPTIMA_H, CAR.KIA_OPTIMA_H_G4_FL, CAR.KIA_SORENTO):
self.STEER_MAX = 255
+ elif CP.carFingerprint in (CAR.HYUNDAI_SANTA_FE_PHEV_2022):
+ self.STEER_MAX = 409
# these cars have significantly more torque than most HKG; limit to 70% of max
elif CP.flags & HyundaiFlags.ALT_LIMITS:
- self.STEER_MAX = 270
- self.STEER_DELTA_UP = 2
- self.STEER_DELTA_DOWN = 3
-
- elif CP.flags & HyundaiFlags.ALT_LIMITS_2:
- self.STEER_MAX = 170
+ self.STEER_MAX = 384
self.STEER_DELTA_UP = 2
self.STEER_DELTA_DOWN = 3
# Default for most HKG
else:
- self.STEER_MAX = 384
+ self.STEER_MAX = 409
class HyundaiSafetyFlags(IntFlag):
@@ -94,12 +107,7 @@ class HyundaiFlagsIQ(IntFlag):
class HyundaiFlags(IntFlag):
# Dynamic Flags
-
- # Default assumption: all cars use LFA (ADAS) steering from the camera.
- # CANFD_LKA_STEERING/CANFD_LKA_STEERING_ALT cars typically have both LKA (camera) and LFA (ADAS) steering messages,
- # with LKA commands forwarded to the ADAS DRV ECU.
- # Most HDA2 trims are assumed to be equipped with the ADAS DRV ECU, though some variants may not be equipped with one.
- CANFD_LKA_STEERING = 1
+ CANFD_HDA2 = 1
CANFD_ALT_BUTTONS = 2
CANFD_ALT_GEARS = 2 ** 2
CANFD_CAMERA_SCC = 2 ** 3
@@ -109,7 +117,7 @@ class HyundaiFlags(IntFlag):
CANFD_ALT_GEARS_2 = 2 ** 6
SEND_LFA = 2 ** 7
USE_FCA = 2 ** 8
- CANFD_LKA_STEERING_ALT = 2 ** 9
+ CANFD_HDA2_ALT_STEERING = 2 ** 9
# these cars use a different gas signal
HYBRID = 2 ** 10
@@ -125,7 +133,7 @@ class HyundaiFlags(IntFlag):
# The radar does SCC on these cars when HDA I, rather than the camera
RADAR_SCC = 2 ** 14
# The camera does SCC on these cars, rather than the radar
- CAMERA_SCC = 2 ** 15
+ CAMERA_SCC = CANFD_CAMERA_SCC #2 ** 15
CHECKSUM_CRC8 = 2 ** 16
CHECKSUM_6B = 2 ** 17
@@ -144,23 +152,41 @@ class HyundaiFlags(IntFlag):
MIN_STEER_32_MPH = 2 ** 23
- HAS_LDA_BUTTON = 2 ** 24
+ ANGLE_CONTROL = 2 ** 24
FCEV = 2 ** 25
ALT_LIMITS_2 = 2 ** 26
+ CC_ONLY_CAR = 2 ** 31
+
+class HyundaiExtFlags(IntFlag):
+ NAVI_CLUSTER = 2 ** 2
+ HAS_LFAHDA = 2 ** 4
+ CANFD_GEARS_NONE = 2 ** 6
+ RADAR_GROUP1 = 2 ** 7 # 0x210 radar group 1, 0x3A5 radar group 2
+ CANFD_GEARS_69 = 2 ** 10
+ RADAR_GROUP3 = 2 ** 11 # 0x400-0x41D radar object group
+ CORNER_RADAR_OBJECTS_235 = 2 ** 12 # 0x230 status + 0x235-0x248 raw corner radar objects
+ CORNER_RADAR_OBJECTS_180 = 2 ** 13 # 0x180-0x184 bus 1 two-slot raw corner/front radar objects
+ CORNER_RADAR_OBJECTS_430 = 2 ** 14 # 0x430-0x437 left + 0x440-0x447 right IONIQ 9 corner radar bins
+ RADAR_GROUP4 = 2 ** 15 # 0x500-0x507 Denso DNMWR006 stable radar tracks
+ EV_MODE_STATUS_230 = 2 ** 16 # ECAN 0x230/DLC32 exposes the hybrid power-flow mode used for the EV indicator
+
+class Footnote(Enum):
+ CANFD = CarFootnote(
+ "Requires a CAN FD panda kit if not using " +
+ "comma 3X for this CAN FD car.",
+ Column.MODEL)
+
@dataclass
class HyundaiCarDocs(CarDocs):
package: str = "Smart Cruise Control (SCC)"
-
-@dataclass
-class HyundaiNonSccCarDocs(CarDocs):
- package: str = "No Smart Cruise Control (Non-SCC)"
- support_type: SupportType = SupportType.COMMUNITY
- support_link: str = "community"
+ def init_make(self, CP: CarParams):
+ if CP.flags & HyundaiFlags.CANFD:
+ self.footnotes.insert(0, Footnote.CANFD)
@dataclass
@@ -175,20 +201,9 @@ class HyundaiPlatformConfig(PlatformConfig):
self.specs = self.specs.override(minSteerSpeed=32 * CV.MPH_TO_MS)
-@dataclass
-class HyundaiNonSccPlatformConfig(PlatformConfig):
- dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: "hyundai_kia_generic"})
-
- def init(self):
- self.iq_flags |= HyundaiFlagsIQ.NON_SCC
-
- if self.flags & HyundaiFlags.MIN_STEER_32_MPH:
- self.specs = self.specs.override(minSteerSpeed=32 * CV.MPH_TO_MS)
-
-
@dataclass
class HyundaiCanFDPlatformConfig(PlatformConfig):
- dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: "hyundai_canfd_generated"})
+ dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: "hyundai_canfd_generated", Bus.radar: 'hyundai_canfd_radar_generated'})
def init(self):
self.flags |= HyundaiFlags.CANFD
@@ -196,6 +211,10 @@ class HyundaiCanFDPlatformConfig(PlatformConfig):
class CAR(Platforms):
# Hyundai
+ HYUNDAI_AZERA_7TH_GEN = HyundaiCanFDPlatformConfig(
+ [HyundaiCarDocs("Hyundai Azera 2023-2024", "All", car_parts=CarParts.common([CarHarness.hyundai_a]))],
+ CarSpecs(mass=1700, wheelbase=2.895, steerRatio=16.5),
+ )
HYUNDAI_AZERA_6TH_GEN = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Azera 2022", "All", car_parts=CarParts.common([CarHarness.hyundai_k]))],
CarSpecs(mass=1600, wheelbase=2.885, steerRatio=14.5),
@@ -282,9 +301,9 @@ class CAR(Platforms):
flags=HyundaiFlags.CLUSTER_GEARS | HyundaiFlags.ALT_LIMITS,
)
HYUNDAI_KONA_2022 = HyundaiPlatformConfig(
- [HyundaiCarDocs("Hyundai Kona 2022-23", car_parts=CarParts.common([CarHarness.hyundai_o]))],
+ [HyundaiCarDocs("Hyundai Kona 2022", car_parts=CarParts.common([CarHarness.hyundai_o]))],
CarSpecs(mass=1491, wheelbase=2.6, steerRatio=13.42, tireStiffnessFactor=0.385),
- flags=HyundaiFlags.CAMERA_SCC | HyundaiFlags.ALT_LIMITS_2,
+ flags=HyundaiFlags.CAMERA_SCC,
)
HYUNDAI_KONA_EV = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Kona Electric 2018-21", car_parts=CarParts.common([CarHarness.hyundai_g]))],
@@ -307,6 +326,11 @@ class CAR(Platforms):
CarSpecs(mass=1425, wheelbase=2.6, steerRatio=13.42, tireStiffnessFactor=0.385),
flags=HyundaiFlags.HYBRID | HyundaiFlags.ALT_LIMITS,
)
+ HYUNDAI_KONA_HEV_2ND_GEN = HyundaiCanFDPlatformConfig(
+ [HyundaiCarDocs("Hyundai Kona Hybrid 2024", car_parts=CarParts.common([CarHarness.hyundai_l]))],
+ CarSpecs(mass=1590, wheelbase=2.66, steerRatio=13.6, tireStiffnessFactor=0.385),
+ flags=HyundaiFlags.HYBRID,
+ )
HYUNDAI_NEXO_1ST_GEN = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Nexo 2021", "All", car_parts=CarParts.common([CarHarness.hyundai_h]))],
CarSpecs(mass=3990 * CV.LB_TO_KG, wheelbase=2.79, steerRatio=14.19), # https://www.hyundainews.com/assets/documents/original/42768-2021NEXOProductGuideSpecs.pdf
@@ -322,17 +346,17 @@ class CAR(Platforms):
[HyundaiCarDocs("Hyundai Santa Fe 2021-23", "All", video="https://youtu.be/VnHzSTygTS4",
car_parts=CarParts.common([CarHarness.hyundai_l]))],
HYUNDAI_SANTA_FE.specs,
- flags=HyundaiFlags.MANDO_RADAR | HyundaiFlags.CHECKSUM_CRC8,
+ flags=HyundaiFlags.CHECKSUM_CRC8,
)
HYUNDAI_SANTA_FE_HEV_2022 = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Santa Fe Hybrid 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l]))],
HYUNDAI_SANTA_FE.specs,
- flags=HyundaiFlags.MANDO_RADAR | HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.HYBRID,
+ flags=HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.HYBRID,
)
HYUNDAI_SANTA_FE_PHEV_2022 = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Santa Fe Plug-in Hybrid 2022-23", "All", car_parts=CarParts.common([CarHarness.hyundai_l]))],
HYUNDAI_SANTA_FE.specs,
- flags=HyundaiFlags.MANDO_RADAR | HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.HYBRID,
+ flags=HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.HYBRID,
)
HYUNDAI_SONATA = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Sonata 2020-23", "All", video="https://www.youtube.com/watch?v=ix63r9kE3Fw",
@@ -343,8 +367,14 @@ class CAR(Platforms):
HYUNDAI_SONATA_LF = HyundaiPlatformConfig(
[HyundaiCarDocs("Hyundai Sonata 2018-19", car_parts=CarParts.common([CarHarness.hyundai_e]))],
CarSpecs(mass=1536, wheelbase=2.804, steerRatio=13.27 * 1.15), # 15% higher at the center seems reasonable
+
flags=HyundaiFlags.UNSUPPORTED_LONGITUDINAL | HyundaiFlags.TCU_GEARS,
)
+ HYUNDAI_SONATA_2024 = HyundaiCanFDPlatformConfig(
+ [HyundaiCarDocs("Hyundai Sonata 2024-25", "All", car_parts=CarParts.common([CarHarness.hyundai_a]))],
+ CarSpecs(mass=1556, wheelbase=2.84, steerRatio=12.81),
+ flags=HyundaiFlags.CAMERA_SCC,
+ )
HYUNDAI_STARIA_4TH_GEN = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Staria 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_k]))],
CarSpecs(mass=2205, wheelbase=3.273, steerRatio=11.94), # https://www.hyundai.com/content/dam/hyundai/au/en/models/staria-load/premium-pip-update-2023/spec-sheet/STARIA_Load_Spec-Table_March_2023_v3.1.pdf
@@ -384,11 +414,32 @@ class CAR(Platforms):
CarSpecs(mass=1948, wheelbase=2.97, steerRatio=14.26, tireStiffnessFactor=0.65),
flags=HyundaiFlags.EV,
)
+ HYUNDAI_IONIQ_5_PE = HyundaiCanFDPlatformConfig(
+ [
+ HyundaiCarDocs("Hyundai IONIQ 5 PE (NE1)", car_parts=CarParts.common([CarHarness.hyundai_q])),
+ HyundaiCarDocs("Hyundai Ioniq 5 PE (with HDA II) 2024", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_q])),
+ ],
+ #CarSpecs(mass=2012, wheelbase=3.0, steerRatio=14.26, tireStiffnessFactor=0.65),
+ CarSpecs(mass=2012, wheelbase=3.0, steerRatio=14.26, tireStiffnessFactor=1.0),
+ flags=HyundaiFlags.EV | HyundaiFlags.ANGLE_CONTROL,
+ )
+ HYUNDAI_IONIQ_5_N = HyundaiCanFDPlatformConfig(
+ [HyundaiCarDocs("Hyundai Ioniq 5 N (with HDA II) 2024", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_m]))],
+ CarSpecs(mass=2200, wheelbase=3.00, steerRatio=12.54),
+ flags=HyundaiFlags.EV,
+ )
HYUNDAI_IONIQ_6 = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Hyundai Ioniq 6 (with HDA II) 2023-24", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))],
HYUNDAI_IONIQ_5.specs,
flags=HyundaiFlags.EV | HyundaiFlags.CANFD_NO_RADAR_DISABLE,
)
+ HYUNDAI_IONIQ_9 = HyundaiCanFDPlatformConfig(
+ [
+ HyundaiCarDocs("Hyundai Ioniq 9", "All", car_parts=CarParts.common([CarHarness.hyundai_m])),
+ ],
+ CarSpecs(mass=2505, wheelbase=3.13, steerRatio=16.02),
+ flags=HyundaiFlags.EV | HyundaiFlags.ANGLE_CONTROL,
+ )
HYUNDAI_TUCSON_4TH_GEN = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Hyundai Tucson 2022", car_parts=CarParts.common([CarHarness.hyundai_n])),
@@ -408,6 +459,36 @@ class CAR(Platforms):
CarSpecs(mass=1690, wheelbase=3.055, steerRatio=17), # mass: from https://www.hyundai-motor.com.tw/clicktobuy/custin#spec_0, steerRatio: from learner
flags=HyundaiFlags.CHECKSUM_CRC8,
)
+ HYUNDAI_CASPER = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Hyundai Casper 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_k]))],
+ CarSpecs(mass=1060, wheelbase=2.4, steerRatio=14.3), # mass: from https://www.hyundai-motor.com.tw/clicktobuy/custin#spec_0, steerRatio: from learner
+ flags=HyundaiFlags.CAMERA_SCC | HyundaiFlags.CHECKSUM_CRC8,
+ )
+
+ HYUNDAI_CASPER_EV = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Hyundai Casper EV 2024", "All", car_parts=CarParts.common([CarHarness.hyundai_k]))],
+ CarSpecs(mass=1355, wheelbase=2.58, steerRatio=14.3), # mass: from https://www.hyundai-motor.com.tw/clicktobuy/custin#spec_0, steerRatio: from learner
+ flags=HyundaiFlags.CAMERA_SCC | HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.EV
+ )
+ HYUNDAI_PORTER_II_EV = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Hyundai Porter II EV 2024", car_parts=CarParts.common([CarHarness.hyundai_h]))],
+ CarSpecs(mass=1970, wheelbase=2.64, steerRatio=14.5),
+ flags=HyundaiFlags.EV | HyundaiFlags.CC_ONLY_CAR,
+ )
+ HYUNDAI_SANTAFE_MX5 = HyundaiCanFDPlatformConfig(
+ [
+ HyundaiCarDocs("Hyundai SANTAFE (MX5)", car_parts=CarParts.common([CarHarness.hyundai_k])),
+ ],
+ CarSpecs(mass=1910, wheelbase=2.76, steerRatio=15.8, tireStiffnessFactor=0.82),
+ flags=HyundaiFlags.ANGLE_CONTROL,
+ )
+ HYUNDAI_SANTAFE_MX5_HEV = HyundaiCanFDPlatformConfig(
+ [
+ HyundaiCarDocs("Hyundai SANTAFE HYBRID (MX5)", car_parts=CarParts.common([CarHarness.hyundai_k])),
+ ],
+ HYUNDAI_SANTAFE_MX5.specs,
+ flags=HyundaiFlags.ANGLE_CONTROL,
+ )
# Kia
KIA_FORTE = HyundaiPlatformConfig(
@@ -427,6 +508,18 @@ class CAR(Platforms):
KIA_K5_2021.specs,
flags=HyundaiFlags.MANDO_RADAR | HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.HYBRID,
)
+ KIA_K5_DL3_24 = HyundaiCanFDPlatformConfig(
+ [
+ HyundaiCarDocs("Kia K5 2024", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_k])),
+ ],
+ CarSpecs(mass=1553, wheelbase=2.85, steerRatio=13.27, tireStiffnessFactor=0.5),
+ )
+ KIA_K5_DL3_24_HEV = HyundaiCanFDPlatformConfig(
+ [
+ HyundaiCarDocs("Kia K5 Hybrid 2024", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_k])),
+ ],
+ CarSpecs(mass=1553, wheelbase=2.85, steerRatio=13.27, tireStiffnessFactor=0.5),
+ )
KIA_K8_HEV_1ST_GEN = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Kia K8 Hybrid (with HDA II) 2023", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_q]))],
# mass: https://carprices.ae/brands/kia/2023/k8/1.6-turbo-hybrid, steerRatio: guesstimate from K5 platform
@@ -443,16 +536,13 @@ class CAR(Platforms):
flags=HyundaiFlags.MANDO_RADAR | HyundaiFlags.EV,
)
KIA_NIRO_EV_2ND_GEN = HyundaiCanFDPlatformConfig(
- [
- HyundaiCarDocs("Kia Niro EV (without HDA II) 2023-25", "All", car_parts=CarParts.common([CarHarness.hyundai_a])),
- HyundaiCarDocs("Kia Niro EV (with HDA II) 2025", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_r])),
- ],
+ [HyundaiCarDocs("Kia Niro EV 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_a]))],
KIA_NIRO_EV.specs,
flags=HyundaiFlags.EV,
)
KIA_NIRO_PHEV = HyundaiPlatformConfig(
[
- HyundaiCarDocs("Kia Niro Hybrid 2018", min_enable_speed=10. * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_c])),
+ HyundaiCarDocs("Kia Niro Hybrid 2018", "All", min_enable_speed=10. * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_c])),
HyundaiCarDocs("Kia Niro Plug-in Hybrid 2018-19", "All", min_enable_speed=10. * CV.MPH_TO_MS, car_parts=CarParts.common([CarHarness.hyundai_c])),
HyundaiCarDocs("Kia Niro Plug-in Hybrid 2020", car_parts=CarParts.common([CarHarness.hyundai_d])),
],
@@ -493,7 +583,7 @@ class CAR(Platforms):
# TODO: may support adjacent years. may have a non-zero minimum steering speed
KIA_OPTIMA_H = HyundaiPlatformConfig(
[HyundaiCarDocs("Kia Optima Hybrid 2017", "Advanced Smart Cruise Control", car_parts=CarParts.common([CarHarness.hyundai_c]))],
- CarSpecs(mass=3558 * CV.LB_TO_KG, wheelbase=2.8, steerRatio=13.75, tireStiffnessFactor=0.5),
+ CarSpecs(mass=3758 * CV.LB_TO_KG, wheelbase=2.8, steerRatio=13.75, tireStiffnessFactor=0.5),
flags=HyundaiFlags.HYBRID | HyundaiFlags.LEGACY,
)
KIA_OPTIMA_H_G4_FL = HyundaiPlatformConfig(
@@ -521,6 +611,7 @@ class CAR(Platforms):
HyundaiCarDocs("Kia Sorento 2019", video="https://www.youtube.com/watch?v=Fkh3s6WHJz8", car_parts=CarParts.common([CarHarness.hyundai_e])),
],
CarSpecs(mass=1985, wheelbase=2.78, steerRatio=14.4 * 1.1), # 10% higher at the center seems reasonable
+ dbc_dict={Bus.pt: "hyundai_kia_generic", Bus.radar: "hyundai_kia_denso_front_radar_generated"},
flags=HyundaiFlags.CHECKSUM_6B | HyundaiFlags.UNSUPPORTED_LONGITUDINAL,
)
KIA_SORENTO_4TH_GEN = HyundaiCanFDPlatformConfig(
@@ -550,6 +641,11 @@ class CAR(Platforms):
CarSpecs(mass=1450, wheelbase=2.65, steerRatio=13.75, tireStiffnessFactor=0.5),
flags=HyundaiFlags.LEGACY,
)
+ KIA_EV4 = HyundaiCanFDPlatformConfig(
+ [HyundaiCarDocs("Kia EV4 2025", "All", car_parts=CarParts.common([CarHarness.hyundai_q]))],
+ CarSpecs(mass=1710, wheelbase=2.83, steerRatio=14.5, tireStiffnessFactor=0.65),
+ flags=HyundaiFlags.EV,
+ )
KIA_EV6 = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Kia EV6 (Southeast Asia only) 2022-24", "All", car_parts=CarParts.common([CarHarness.hyundai_p])),
@@ -559,6 +655,14 @@ class CAR(Platforms):
CarSpecs(mass=2055, wheelbase=2.9, steerRatio=16, tireStiffnessFactor=0.65),
flags=HyundaiFlags.EV,
)
+ KIA_EV6_PE = HyundaiCanFDPlatformConfig(
+ [
+ HyundaiCarDocs("Kia EV6 PE (CV1)", car_parts=CarParts.common([CarHarness.hyundai_p])),
+ HyundaiCarDocs("Kia EV6 PE (with HDA II) 2025", "Highway Driving Assist II", car_parts=CarParts.common([CarHarness.hyundai_p]))
+ ],
+ CarSpecs(mass=2055, wheelbase=2.9, steerRatio=16, tireStiffnessFactor=0.65),
+ flags=HyundaiFlags.EV | HyundaiFlags.ANGLE_CONTROL,
+ )
KIA_CARNIVAL_4TH_GEN = HyundaiCanFDPlatformConfig(
[
HyundaiCarDocs("Kia Carnival 2022-24", car_parts=CarParts.common([CarHarness.hyundai_a])),
@@ -627,54 +731,116 @@ class CAR(Platforms):
CarSpecs(mass=2258, wheelbase=2.95, steerRatio=14.14),
flags=HyundaiFlags.RADAR_SCC,
)
-
- # port extensions
- HYUNDAI_BAYON_1ST_GEN_NON_SCC = HyundaiNonSccPlatformConfig(
- [HyundaiNonSccCarDocs("Hyundai Bayon Non-SCC 2021", car_parts=CarParts.common([CarHarness.hyundai_n]))],
- CarSpecs(mass=1150, wheelbase=2.58, steerRatio=13.27 * 1.15),
- flags=HyundaiFlags.CHECKSUM_CRC8,
+ GENESIS_GV70_EV_1ST_GEN = HyundaiCanFDPlatformConfig(
+ [HyundaiCarDocs("Genesis GV70 EV 2020-2023", "All", car_parts=CarParts.common([CarHarness.hyundai_m]))],
+ CarSpecs(mass=2230, wheelbase=2.87, steerRatio=14.6),
+ flags=HyundaiFlags.EV | HyundaiFlags.RADAR_SCC,
)
- HYUNDAI_ELANTRA_2022_NON_SCC = HyundaiNonSccPlatformConfig(
- [HyundaiNonSccCarDocs("Hyundai Elantra Non-SCC 2022", car_parts=CarParts.common([CarHarness.hyundai_k]))],
- HYUNDAI_ELANTRA_2021.specs,
- flags=HyundaiFlags.CHECKSUM_CRC8,
+ HYUNDAI_GRANDEUR_IG = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Hyundai Grandeur 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
+ CarSpecs(mass=1570, wheelbase=2.845, steerRatio=16., tireStiffnessFactor=0.7),
+ flags=HyundaiFlags.LEGACY | HyundaiFlags.CLUSTER_GEARS,
)
- HYUNDAI_KONA_NON_SCC = HyundaiNonSccPlatformConfig(
- [HyundaiNonSccCarDocs("Hyundai Kona Non-SCC 2019", car_parts=CarParts.common([CarHarness.hyundai_b]))],
- HYUNDAI_KONA.specs,
- flags=HyundaiFlags.ALT_LIMITS,
+ HYUNDAI_GRANDEUR_IG_HEV = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Hyundai Grandeur HEV 2018-19", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
+ CarSpecs(mass=1570, wheelbase=2.845, steerRatio=16., tireStiffnessFactor=0.7),
+ flags=HyundaiFlags.HYBRID | HyundaiFlags.LEGACY,
)
- HYUNDAI_KONA_EV_NON_SCC = HyundaiNonSccPlatformConfig(
- [HyundaiNonSccCarDocs("Hyundai Kona Electric Non-SCC 2019", car_parts=CarParts.common([CarHarness.hyundai_g]))],
- HYUNDAI_KONA_EV.specs,
- flags=HyundaiFlags.EV | HyundaiFlags.ALT_LIMITS,
+ GENESIS_EQ900 = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Genesis EQ900 2017", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
+ CarSpecs(mass=2200, wheelbase=3.15, steerRatio=16., tireStiffnessFactor=0.7),
+ flags=HyundaiFlags.LEGACY,
)
- KIA_CEED_PHEV_2022_NON_SCC = HyundaiNonSccPlatformConfig(
- [HyundaiNonSccCarDocs("Kia Ceed Plug-in Hybrid Non-SCC 2022", car_parts=CarParts.common([CarHarness.hyundai_i]))],
- CarSpecs(mass=1650, wheelbase=2.65, steerRatio=13.75, tireStiffnessFactor=0.5),
+ GENESIS_EQ900_L = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Genesis EQ900 LIMOUSINE", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
+ CarSpecs(mass=2290, wheelbase=3.45, steerRatio=16., tireStiffnessFactor=0.7),
+ flags=HyundaiFlags.LEGACY,
+ )
+ GENESIS_G90_2019 = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Genesis G90 2019", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
+ CarSpecs(mass=2150, wheelbase=3.16, steerRatio=16., tireStiffnessFactor=0.7),
+ flags=HyundaiFlags.LEGACY,
+ )
+ HYUNDAI_NEXO = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Hyundai Nexo", "All", car_parts=CarParts.common([CarHarness.hyundai_a]))],
+ CarSpecs(mass=1885, wheelbase=2.79, steerRatio=15.3, tireStiffnessFactor=0.385),
+ flags=HyundaiFlags.EV,
+ )
+ KIA_MOHAVE = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Kia Mohave 2019", "All", car_parts=CarParts.common([CarHarness.hyundai_k]))],
+ CarSpecs(mass=2285, wheelbase=2.895, steerRatio=16., tireStiffnessFactor=0.7),
+ flags=HyundaiFlags.LEGACY,
+ )
+ KIA_K5 = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Kia K5 2019 & 2016", "All", car_parts=CarParts.common([CarHarness.hyundai_b]))],
+ CarSpecs(mass=1515, wheelbase=2.80, steerRatio=15.5, tireStiffnessFactor=0.7),
+ flags=HyundaiFlags.LEGACY | HyundaiFlags.TCU_GEARS,
+ )
+ KIA_K5_HEV = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Kia K5 Hybrid 2017", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
+ CarSpecs(mass=1705, wheelbase=2.80, steerRatio=15.5, tireStiffnessFactor=0.7),
+ flags=HyundaiFlags.HYBRID | HyundaiFlags.LEGACY,
+ )
+ KIA_K5_HEV_2022 = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Kia K5 Hybrid 2022", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
+ CarSpecs(mass=1515, wheelbase=2.85, steerRatio=15.5, tireStiffnessFactor=0.7),
+ flags=HyundaiFlags.HYBRID | HyundaiFlags.LEGACY,
+ )
+ KIA_K7 = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Kia K7 2016-2019", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
+ CarSpecs(mass=1850, wheelbase=2.855, steerRatio=15.5, tireStiffnessFactor=0.7),
+ flags=HyundaiFlags.LEGACY | HyundaiFlags.CLUSTER_GEARS,
+ )
+ KIA_K7_HEV = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Kia K7 Hybrid 2016-2019", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
+ CarSpecs(mass=1515, wheelbase=2.855, steerRatio=15.5, tireStiffnessFactor=0.7),
+ flags=HyundaiFlags.HYBRID | HyundaiFlags.LEGACY,
+ )
+ KIA_K7_PE = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Kia K7 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
+ CarSpecs(mass=1850, wheelbase=2.855, steerRatio=15.5, tireStiffnessFactor=0.7),
+ )
+ KIA_K7_HEV_PE = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Kia K7 Hybrid 2020", "All", car_parts=CarParts.common([CarHarness.hyundai_c]))],
+ CarSpecs(mass=1515, wheelbase=2.855, steerRatio=15.5, tireStiffnessFactor=0.7),
flags=HyundaiFlags.HYBRID,
)
- KIA_FORTE_2019_NON_SCC = HyundaiNonSccPlatformConfig(
- [HyundaiNonSccCarDocs("Kia Forte Non-SCC 2019", car_parts=CarParts.common([CarHarness.hyundai_g]))],
- KIA_FORTE.specs,
- iq_flags=HyundaiFlagsIQ.NON_SCC_NO_FCA,
+ KIA_K9 = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Kia K9 2016-2019", "All", car_parts=CarParts.common([CarHarness.hyundai_h]))],
+ CarSpecs(mass=2075, wheelbase=3.15, steerRatio=14.5, tireStiffnessFactor=0.7),
+ flags=HyundaiFlags.LEGACY,
)
- KIA_FORTE_2021_NON_SCC = HyundaiNonSccPlatformConfig(
- [HyundaiNonSccCarDocs("Kia Forte Non-SCC 2021", car_parts=CarParts.common([CarHarness.hyundai_g]))],
- KIA_FORTE.specs,
+ KIA_EV_SK3 = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Kia Soul EV 2019", car_parts=CarParts.common([CarHarness.hyundai_c]))],
+ CarSpecs(mass=1695, wheelbase=2.6, steerRatio=13.75),
+ flags=HyundaiFlags.CHECKSUM_CRC8 | HyundaiFlags.EV,
)
- KIA_SELTOS_2023_NON_SCC = HyundaiNonSccPlatformConfig(
- [HyundaiNonSccCarDocs("Kia Seltos Non-SCC 2023-24", car_parts=CarParts.common([CarHarness.hyundai_l]))],
- KIA_SELTOS.specs,
- flags=HyundaiFlags.CHECKSUM_CRC8,
+ KIA_EV9 = HyundaiCanFDPlatformConfig(
+ [
+ HyundaiCarDocs("Kia EV9 (MV)", car_parts=CarParts.common([CarHarness.hyundai_k])),
+ ],
+ CarSpecs(mass=2625, wheelbase=3.1, steerRatio=16.02),
+ flags=HyundaiFlags.EV | HyundaiFlags.ANGLE_CONTROL,
)
- GENESIS_G70_2021_NON_SCC = HyundaiNonSccPlatformConfig(
- [HyundaiNonSccCarDocs("Genesis G70 Non-SCC 2021", car_parts=CarParts.common([CarHarness.hyundai_f]))],
- GENESIS_G70_2020.specs,
- flags=HyundaiFlags.CHECKSUM_CRC8,
- iq_flags=HyundaiFlagsIQ.NON_SCC_RADAR_FCA,
+ KIA_EV3 = HyundaiCanFDPlatformConfig(
+ [
+ HyundaiCarDocs("Kia EV3 (SV1)", car_parts=CarParts.common([CarHarness.hyundai_n])),
+ ],
+ CarSpecs(mass=2055, wheelbase=2.90, steerRatio=16.0, tireStiffnessFactor=0.65),
+ flags=HyundaiFlags.EV,
+ )
+ KIA_PV5 = HyundaiCanFDPlatformConfig(
+ [
+ HyundaiCarDocs("Kia PV5 (SW1)", car_parts=CarParts.common([CarHarness.hyundai_n])),
+ ],
+ CarSpecs(mass=2600, wheelbase=2.995, steerRatio=16.0, tireStiffnessFactor=0.65),
+ flags=HyundaiFlags.EV,
+ )
+ KIA_RAY_EV = HyundaiPlatformConfig(
+ [HyundaiCarDocs("Kia Ray EV", car_parts=CarParts.common([CarHarness.hyundai_h]))],
+ CarSpecs(mass=1295, wheelbase=2.520, steerRatio=14.5),
+ flags=HyundaiFlags.EV | HyundaiFlags.CC_ONLY_CAR | HyundaiFlags.CHECKSUM_CRC8,
)
-
class Buttons:
NONE = 0
@@ -682,6 +848,7 @@ class Buttons:
SET_DECEL = 2
GAP_DIST = 3
CANCEL = 4 # on newer models, this is a pause/resume button
+ LFA_BUTTON = 5
def get_platform_codes(fw_versions: list[bytes]) -> set[tuple[bytes, bytes | None]]:
@@ -862,11 +1029,21 @@ CAN_GEARS = {
# which message has the gear. hybrid and EV use ELECT_GEAR
"use_cluster_gears": CAR.with_flags(HyundaiFlags.CLUSTER_GEARS),
"use_tcu_gears": CAR.with_flags(HyundaiFlags.TCU_GEARS),
+ "send_mdps12": {CAR.GENESIS_G90, CAR.GENESIS_G90_2019, CAR.KIA_K9, CAR.KIA_K7},
}
CANFD_CAR = CAR.with_flags(HyundaiFlags.CANFD)
CANFD_RADAR_SCC_CAR = CAR.with_flags(HyundaiFlags.RADAR_SCC) # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
+CANFD_HYBRID_STATUS_ADDR = 0xFA
+CANFD_HYBRID_STATUS_DLC = 32
+
+EV_MODE_STATUS_ADDR = 0x230
+EV_MODE_STATUS_DLC = 32
+EV_MODE_STATUS_MSG = "HCU_STATUS_230"
+EV_MODE_STATUS_SIGNAL = "HYBRID_POWER_FLOW_MODE"
+EV_MODE_ACTIVE_VALUES = frozenset((1, 2, 6))
+
CANFD_UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.CANFD_NO_RADAR_DISABLE) # TODO: merge with UNSUPPORTED_LONGITUDINAL_CAR
CAMERA_SCC_CAR = CAR.with_flags(HyundaiFlags.CAMERA_SCC)
@@ -881,7 +1058,13 @@ LEGACY_SAFETY_MODE_CAR = CAR.with_flags(HyundaiFlags.LEGACY)
# HyundaiFlags.CANFD_RADAR_SCC | HyundaiFlags.CANFD_NO_RADAR_DISABLE | )
UNSUPPORTED_LONGITUDINAL_CAR = CAR.with_flags(HyundaiFlags.LEGACY) | CAR.with_flags(HyundaiFlags.UNSUPPORTED_LONGITUDINAL)
-# port extensions
-NON_SCC_CAR = CAR.with_iq_flags(HyundaiFlagsIQ.NON_SCC)
-
DBC = CAR.create_dbc_map()
+
+if __name__ == "__main__":
+ cars = []
+ for platform in CAR:
+ for doc in platform.config.car_docs:
+ cars.append(doc.name)
+ cars.sort()
+ for c in cars:
+ print(c)
diff --git a/iqdbc_repo/iqdbc/car/interfaces.py b/iqdbc_repo/iqdbc/car/interfaces.py
index e61f667..7f68e40 100644
--- a/iqdbc_repo/iqdbc/car/interfaces.py
+++ b/iqdbc_repo/iqdbc/car/interfaces.py
@@ -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.]
@@ -335,6 +332,12 @@ class CarStateBase(ABC):
x0=[[0.0], [0.0]]
K = get_kalman_gain(DT_CTRL, np.array(A), np.array(C), np.array(Q), R)
self.v_ego_kf = KF1D(x0=x0, A=A, C=C[0], K=K)
+ self.v_ego_clu_kf = KF1D(x0=x0, A=A, C=C[0], K=K)
+
+ self.softHoldActive = 0
+ self.is_metric = True
+ self.lkas_enabled = False
+ self.modelV2 = None
@abstractmethod
def update(self, can_parsers) -> tuple[structs.CarState, structs.IQCarState]:
@@ -351,6 +354,22 @@ class CarStateBase(ABC):
v_ego_x = self.v_ego_kf.update(v_ego_raw)
return float(v_ego_x[0]), float(v_ego_x[1])
+ def update_clu_speed_kf(self, v_ego_raw):
+ if abs(v_ego_raw - self.v_ego_clu_kf.x[0][0]) > 2.0:
+ self.v_ego_clu_kf.set_x([[v_ego_raw], [0.0]])
+
+ v_ego_x = self.v_ego_clu_kf.update(v_ego_raw)
+ return float(v_ego_x[0]), float(v_ego_x[1])
+
+ def get_wheel_speeds(self, fl, fr, rl, rr, unit=CV.KPH_TO_MS):
+ factor = unit * self.CP.wheelSpeedFactor
+ wheel_speeds = structs.CarState.WheelSpeeds()
+ wheel_speeds.fl = fl * factor
+ wheel_speeds.fr = fr * factor
+ wheel_speeds.rl = rl * factor
+ wheel_speeds.rr = rr * factor
+ return wheel_speeds
+
def update_blinker_from_lamp(self, blinker_time: int, left_blinker_lamp: bool, right_blinker_lamp: bool):
"""Update blinkers from lights. Enable output when light was seen within the last `blinker_time`
iterations"""
diff --git a/iqdbc_repo/iqdbc/car/lateral.py b/iqdbc_repo/iqdbc/car/lateral.py
index 7801014..38179a2 100644
--- a/iqdbc_repo/iqdbc/car/lateral.py
+++ b/iqdbc_repo/iqdbc/car/lateral.py
@@ -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
diff --git a/iqdbc_repo/iqdbc/car/logreader.py b/iqdbc_repo/iqdbc/car/logreader.py
index 36f2817..92a5f6e 100644
--- a/iqdbc_repo/iqdbc/car/logreader.py
+++ b/iqdbc_repo/iqdbc/car/logreader.py
@@ -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:
diff --git a/iqdbc_repo/iqdbc/car/nissan/carstate.py b/iqdbc_repo/iqdbc/car/nissan/carstate.py
index acf10f1..d5394b8 100644
--- a/iqdbc_repo/iqdbc/car/nissan/carstate.py
+++ b/iqdbc_repo/iqdbc/car/nissan/carstate.py
@@ -5,17 +5,18 @@ from iqdbc.car import Bus, create_button_events, structs
from iqdbc.car.common.conversions import Conversions as CV
from iqdbc.car.interfaces import CarStateBase
from iqdbc.car.nissan.values import CAR, DBC, CarControllerParams
-from iqdbc.lvbs.car.nissan.carstate_ext import CarStateExt
+
+from iqdbc.lvbs.car.nissan.iq_carstate import IQCarState
ButtonType = structs.CarState.ButtonEvent.Type
TORQUE_SAMPLES = 12
-class CarState(CarStateBase, CarStateExt):
+class CarState(CarStateBase, IQCarState):
def __init__(self, CP, CP_IQ):
CarStateBase.__init__(self, CP, CP_IQ)
- CarStateExt.__init__(self, CP, CP_IQ)
+ IQCarState.__init__(self, CP, CP_IQ)
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
self.lkas_hud_msg = {}
@@ -129,7 +130,7 @@ class CarState(CarStateBase, CarStateExt):
self.lkas_hud_msg = copy.copy(cp_adas.vl["PROPILOT_HUD"])
self.lkas_hud_info_msg = copy.copy(cp_adas.vl["PROPILOT_HUD_INFO_MSG"])
- CarStateExt.update(self, ret, ret_iq, can_parsers)
+ IQCarState.update(self, ret, ret_iq, can_parsers)
ret.buttonEvents = [
*create_button_events(self.distance_button, prev_distance_button, {1: ButtonType.gapAdjustCruise}),
diff --git a/iqdbc_repo/iqdbc/car/rivian/carstate.py b/iqdbc_repo/iqdbc/car/rivian/carstate.py
index 225a043..1901913 100644
--- a/iqdbc_repo/iqdbc/car/rivian/carstate.py
+++ b/iqdbc_repo/iqdbc/car/rivian/carstate.py
@@ -4,15 +4,15 @@ from iqdbc.car import Bus, structs
from iqdbc.car.interfaces import CarStateBase
from iqdbc.car.rivian.values import DBC, GEAR_MAP
from iqdbc.car.common.conversions import Conversions as CV
-from iqdbc.lvbs.car.rivian.carstate_ext import CarStateExt
+from iqdbc.lvbs.car.rivian.iq_carstate import IQCarState
GearShifter = structs.CarState.GearShifter
-class CarState(CarStateBase, CarStateExt):
+class CarState(CarStateBase, IQCarState):
def __init__(self, CP, CP_IQ):
CarStateBase.__init__(self, CP, CP_IQ)
- CarStateExt.__init__(self, CP, CP_IQ)
+ IQCarState.__init__(self, CP, CP_IQ)
self.last_speed = 30
self.acm_lka_hba_cmd = None
@@ -95,7 +95,7 @@ class CarState(CarStateBase, CarStateExt):
self.sccm_wheel_touch = copy.copy(cp.vl["SCCM_WheelTouch"])
self.vdm_adas_status = copy.copy(cp.vl["VDM_AdasSts"])
- CarStateExt.update(self, ret, can_parsers)
+ IQCarState.update(self, ret, can_parsers)
return ret, ret_iq
@@ -105,5 +105,5 @@ class CarState(CarStateBase, CarStateExt):
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 0),
Bus.adas: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 1),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 2),
- **CarStateExt.get_parser(CP, CP_IQ),
+ **IQCarState.get_parser(CP, CP_IQ),
}
diff --git a/iqdbc_repo/iqdbc/car/rivian/interface.py b/iqdbc_repo/iqdbc/car/rivian/interface.py
index 858bf03..a211a98 100644
--- a/iqdbc_repo/iqdbc/car/rivian/interface.py
+++ b/iqdbc_repo/iqdbc/car/rivian/interface.py
@@ -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
@@ -40,6 +39,8 @@ class CarInterface(CarInterfaceBase):
@staticmethod
def _get_params_iq(stock_cp: structs.CarParams, ret: structs.IQCarParams, candidate, fingerprint: dict[int, dict[int, int]],
car_fw: list[structs.CarParams.CarFw], alpha_long: bool, is_release_iq: bool, docs: bool) -> structs.IQCarParams:
+ # Longitudinal harness upgrade advertises msg 0x31a on bus 5; when present it
+ # unlocks radar, blind-spot and openpilot longitudinal on Rivian.
if 0x31a in fingerprint[5]:
ret.flags |= RivianFlagsIQ.LONGITUDINAL_HARNESS_UPGRADE.value
stock_cp.radarUnavailable = False
diff --git a/iqdbc_repo/iqdbc/car/structs.py b/iqdbc_repo/iqdbc/car/structs.py
index 583dc22..f3dabdf 100644
--- a/iqdbc_repo/iqdbc/car/structs.py
+++ b/iqdbc_repo/iqdbc/car/structs.py
@@ -52,6 +52,7 @@ class IQCarParams:
pcmCruiseSpeed: bool = auto_field()
enableGasInterceptor: bool = auto_field()
longitudinalStoppingSpeedOverride: float = auto_field()
+ stoppingDecelRateOverride: float = auto_field()
iqLateralNet: 'IQCarParams.LateralNet' = field(default_factory=lambda: IQCarParams.LateralNet())
diff --git a/iqdbc_repo/iqdbc/car/tesla/__init__.py b/iqdbc_repo/iqdbc/car/tesla/__init__.py
index e69de29..8c31053 100644
--- a/iqdbc_repo/iqdbc/car/tesla/__init__.py
+++ b/iqdbc_repo/iqdbc/car/tesla/__init__.py
@@ -0,0 +1,2 @@
+# FIXME: gate by FingerPrint
+TESLA_BLINKERS = False
diff --git a/iqdbc_repo/iqdbc/car/tesla/carcontroller.py b/iqdbc_repo/iqdbc/car/tesla/carcontroller.py
index beb4425..59ca117 100644
--- a/iqdbc_repo/iqdbc/car/tesla/carcontroller.py
+++ b/iqdbc_repo/iqdbc/car/tesla/carcontroller.py
@@ -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.lvbs.car.tesla.torque_blend import TorqueBlendController
+from iqdbc.lvbs.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
diff --git a/iqdbc_repo/iqdbc/car/tesla/carstate.py b/iqdbc_repo/iqdbc/car/tesla/carstate.py
index 3519313..44aa90a 100644
--- a/iqdbc_repo/iqdbc/car/tesla/carstate.py
+++ b/iqdbc_repo/iqdbc/car/tesla/carstate.py
@@ -1,34 +1,37 @@
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.lvbs.car.tesla.carstate_ext import CarStateExt
+from iqdbc.lvbs.car.tesla.iq_carstate import IQCarState
+from iqdbc.lvbs.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
-class CarState(CarStateBase, CarStateExt):
+class CarState(CarStateBase, IQCarState):
def __init__(self, CP, CP_IQ):
CarStateBase.__init__(self, CP, CP_IQ)
- CarStateExt.__init__(self, CP, CP_IQ)
+ IQCarState.__init__(self, CP, CP_IQ)
self.can_define = CANDefine(DBC[CP.carFingerprint][Bus.party])
self.shifter_values = self.can_define.dv["DI_systemStatus"]["DI_gear"]
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"])
- CarStateExt.update(self, ret, ret_iq, can_parsers)
+ # 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""))
+
+ IQCarState.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),
+ **IQCarState.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
diff --git a/iqdbc_repo/iqdbc/car/tesla/interface.py b/iqdbc_repo/iqdbc/car/tesla/interface.py
index 9d191e7..1f292c5 100644
--- a/iqdbc_repo/iqdbc/car/tesla/interface.py
+++ b/iqdbc_repo/iqdbc/car/tesla/interface.py
@@ -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.lvbs.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
diff --git a/iqdbc_repo/iqdbc/car/tesla/teslacan.py b/iqdbc_repo/iqdbc/car/tesla/teslacan.py
index 68e4734..35e5f66 100644
--- a/iqdbc_repo/iqdbc/car/tesla/teslacan.py
+++ b/iqdbc_repo/iqdbc/car/tesla/teslacan.py
@@ -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 torque_blend: 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)
diff --git a/iqdbc_repo/iqdbc/car/tesla/tests/test_tesla.py b/iqdbc_repo/iqdbc/car/tesla/tests/test_tesla.py
index b36db0d..c9bb75f 100644
--- a/iqdbc_repo/iqdbc/car/tesla/tests/test_tesla.py
+++ b/iqdbc_repo/iqdbc/car/tesla/tests/test_tesla.py
@@ -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())
diff --git a/iqdbc_repo/iqdbc/car/tesla/values.py b/iqdbc_repo/iqdbc/car/tesla/values.py
index 641b744..2800943 100644
--- a/iqdbc_repo/iqdbc/car/tesla/values.py
+++ b/iqdbc_repo/iqdbc/car/tesla/values.py
@@ -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
diff --git a/iqdbc_repo/iqdbc/car/tests/routes.py b/iqdbc_repo/iqdbc/car/tests/routes.py
index 398d0e6..4a826da 100644
--- a/iqdbc_repo/iqdbc/car/tests/routes.py
+++ b/iqdbc_repo/iqdbc/car/tests/routes.py
@@ -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),
diff --git a/iqdbc_repo/iqdbc/car/tests/test_vw_real_can.py b/iqdbc_repo/iqdbc/car/tests/test_vw_real_can.py
new file mode 100644
index 0000000..8f3787b
--- /dev/null
+++ b/iqdbc_repo/iqdbc/car/tests/test_vw_real_can.py
@@ -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//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////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"]))
diff --git a/iqdbc_repo/iqdbc/car/torque_data/override.toml b/iqdbc_repo/iqdbc/car/torque_data/override.toml
index 4770e85..e7b2cfe 100644
--- a/iqdbc_repo/iqdbc/car/torque_data/override.toml
+++ b/iqdbc_repo/iqdbc/car/torque_data/override.toml
@@ -7,9 +7,6 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"NISSAN_LEAF" = [nan, 1.5, nan]
"NISSAN_ROGUE" = [nan, 1.5, nan]
-# PSA angle based controllers
-"PSA_PEUGEOT_208" = [nan, 2.0, nan]
-
# New subarus angle based controllers
"SUBARU_FORESTER_2022" = [nan, 3.0, nan]
"SUBARU_OUTBACK_2023" = [nan, 3.0, nan]
@@ -21,14 +18,11 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
# Tesla angle based controllers
"TESLA_MODEL_3" = [nan, 2.5, nan]
"TESLA_MODEL_Y" = [nan, 2.5, nan]
-"TESLA_MODEL_X" = [nan, 2.5, nan]
# Guess
"FORD_BRONCO_SPORT_MK1" = [nan, 1.5, nan]
"FORD_ESCAPE_MK4" = [nan, 1.5, nan]
-"FORD_ESCAPE_MK4_5" = [nan, 1.5, nan]
"FORD_EXPLORER_MK6" = [nan, 1.5, nan]
-"FORD_EXPEDITION_MK4" = [nan, 1.5, nan]
"FORD_F_150_MK14" = [nan, 1.5, nan]
"FORD_FOCUS_MK4" = [nan, 1.5, nan]
"FORD_MAVERICK_MK1" = [nan, 1.5, nan]
@@ -44,26 +38,20 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"RAM_1500_5TH_GEN" = [2.0, 2.0, 0.05]
"RAM_HD_5TH_GEN" = [1.4, 1.4, 0.05]
"SUBARU_OUTBACK" = [2.0, 1.5, 0.2]
+"BUICK_BABYENCLAVE" = [1.45, 1.6, 0.2]
"CADILLAC_ESCALADE" = [1.899999976158142, 1.842270016670227, 0.1120000034570694]
"CADILLAC_ESCALADE_ESV_2019" = [1.15, 1.3, 0.2]
"CADILLAC_XT4" = [1.45, 1.6, 0.2]
-"CHEVROLET_BOLT_EUV" = [1.0, 2.0, 0.175]
+"CHEVROLET_BOLT_EUV" = [2.0, 2.0, 0.05]
+"CHEVROLET_MALIBU_CC" = [1.85, 1.85, 0.075]
"CHEVROLET_SILVERADO" = [1.9, 1.9, 0.112]
"CHEVROLET_TRAILBLAZER" = [1.33, 1.9, 0.16]
"CHEVROLET_TRAVERSE" = [1.33, 1.33, 0.18]
"CHEVROLET_EQUINOX" = [2.5, 2.5, 0.05]
"CHEVROLET_VOLT_2019" = [1.4, 1.4, 0.16]
-"VOLKSWAGEN_GOLF_MK8" = [nan, 2.5, nan]
-"CUPRA_BORN_MK1" = [nan, 2.5, nan]
-"VOLKSWAGEN_ID3_MK1" = [nan, 2.5, nan]
-"VOLKSWAGEN_ID3_MK2" = [nan, 2.5, nan]
-"VOLKSWAGEN_ID4_MK1" = [nan, 2.5, nan]
-"VOLKSWAGEN_ID4_MK2" = [nan, 2.5, nan]
-"AUDI_Q4_MK1" = [nan, 2.5, nan]
-"AUDI_Q4_MK2" = [nan, 2.5, nan]
-"SEAT_LEON_MK4" = [nan, 2.5, nan]
-"SKODA_ENYAQ_MK1" = [nan, 2.5, nan]
-"SKODA_ENYAQ_MK2" = [nan, 2.5, nan]
+"CHEVROLET_TRAX" = [1.33, 1.9, 0.16]
+"VOLKSWAGEN_ID4_MK1" = [2.0, 2.0, 0.1]
+"VOLKSWAGEN_ID4_MK2" = [2.0, 2.0, 0.1]
"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]
@@ -81,33 +69,22 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"GMC_ACADIA" = [1.6, 1.6, 0.2]
"LEXUS_IS_TSS2" = [2.0, 2.0, 0.1]
"HYUNDAI_KONA_EV_2ND_GEN" = [2.5, 2.5, 0.1]
+"HYUNDAI_KONA_HEV_2ND_GEN" = [2.5, 2.5, 0.1]
"HYUNDAI_IONIQ_6" = [2.5, 2.5, 0.005]
+"HYUNDAI_IONIQ_9" = [1.75, 1.75, 0.15]
+"HYUNDAI_AZERA_7TH_GEN" = [1.8, 1.8, 0.1]
"HYUNDAI_AZERA_6TH_GEN" = [1.8, 1.8, 0.1]
"HYUNDAI_AZERA_HEV_6TH_GEN" = [1.8, 1.8, 0.1]
"KIA_K8_HEV_1ST_GEN" = [2.5, 2.5, 0.1]
"HYUNDAI_CUSTIN_1ST_GEN" = [2.5, 2.5, 0.1]
"LEXUS_GS_F" = [2.5, 2.5, 0.08]
"HYUNDAI_STARIA_4TH_GEN" = [1.8, 2.0, 0.15]
+"HYUNDAI_PORTER_II_EV" = [1.8, 2.0, 0.15]
+"KIA_RAY_EV" = [1.8, 2.0, 0.15]
"GENESIS_GV70_ELECTRIFIED_1ST_GEN" = [1.9, 1.9, 0.09]
"GENESIS_G80_2ND_GEN_FL" = [2.5819356441497803, 2.5, 0.11244568973779678]
-# Note that some Rivians achieve significantly less lateral acceleration than this
"RIVIAN_R1_GEN1" = [2.8, 2.5, 0.07]
"HYUNDAI_NEXO_1ST_GEN" = [2.5, 2.5, 0.1]
-"HONDA_ACCORD_11G" = [1.35, 1.35, 0.17]
-"HONDA_PILOT_4G" = [1.25, 1.25, 0.21]
-"HONDA_PASSPORT_4G" = [1.2, 1.2, 0.16]
-"ACURA_MDX_4G_MMR" = [1.25, 1.25, 0.15]
-"HONDA_CRV_6G" = [1.3, 1.3, 0.2]
-"HONDA_CITY_7G" = [1.2, 1.2, 0.23]
-"HONDA_ODYSSEY_5G_MMR" = [0.9, 0.9, 0.2]
-"HONDA_NBOX_2G" = [1.2, 1.2, 0.2]
-"ACURA_TLX_2G" = [1.2, 1.2, 0.15]
-"ACURA_TLX_2G_MMR" = [1.7, 1.7, 0.16]
-"PORSCHE_MACAN_MK1" = [2.0, 2.0, 0.2]
-"AUDI_Q5_MK1" = [1.8, 1.8, 0.18]
-"LEXUS_LS" = [1.35, 1.7, 0.17]
-"TOYOTA_RAV4_PRIME" = [1.7, 2.0, 0.14]
-"TOYOTA_RAV4_TSS2_2022" = [1.9, 1.9304407208090029, 0.112174]
# Dashcam or fallback configured as ideal car
"MOCK" = [10.0, 10, 0.0]
@@ -116,6 +93,46 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"HONDA_CIVIC_2022" = [2.5, 1.2, 0.15]
"HONDA_HRV_3G" = [2.5, 1.2, 0.2]
-# port extensions
-"HONDA_CLARITY" = [0.96, 0.4018518740819229, 0.19]
-"CHEVROLET_MALIBU_NON_ACC_9TH_GEN" = [1.85, 1.85, 0.075]
+# Community
+"HYUNDAI_GRANDEUR_IG" = [2.3, 2.3, 0.1]
+"HYUNDAI_GRANDEUR_IG_HEV" = [2.3, 2.3, 0.1]
+"GENESIS_EQ900" = [2.3, 2.3, 0.1]
+"GENESIS_EQ900_L" = [2.3, 2.3, 0.1]
+"GENESIS_G90_2019" = [2.3, 2.3, 0.1]
+"KIA_MOHAVE" = [2.3, 2.3, 0.1]
+"KIA_K5" = [2.3, 2.3, 0.1]
+"KIA_K5_HEV" = [2.3, 2.3, 0.1]
+"KIA_K5_HEV_2022" = [2.3, 2.3, 0.1]
+"KIA_K7" = [2.3, 2.3, 0.1]
+"KIA_K7_HEV" = [2.3, 2.3, 0.1]
+"KIA_K7_PE" = [2.3, 2.3, 0.1]
+"KIA_K7_HEV_PE" = [2.3, 2.3, 0.1]
+"KIA_K9" = [2.3, 2.3, 0.1]
+"GENESIS_GV70_EV_1ST_GEN" = [2.42, 2.42, 0.1]
+"HYUNDAI_NEXO" = [2.7, 2.7, 0.1]
+"KIA_EV_SK3" = [2.5, 2.5, 0.1]
+"HYUNDAI_CASPER"= [2.5, 2.5, 0.1]
+"HYUNDAI_CASPER_EV"= [2.5, 2.5, 0.1]
+"HYUNDAI_IONIQ_5_N" = [3.17, 2.71, 0.097]
+"HYUNDAI_IONIQ_5_PE" = [1.75, 1.75, 0.15]
+
+# Synced verbatim from comma opendbc torque_data/override.toml — these platforms
+# exist upstream and were simply never carried over when iqdbc forked.
+ACURA_MDX_4G_MMR = [1.25, 1.25, 0.15]
+ACURA_TLX_2G = [1.2, 1.2, 0.15]
+ACURA_TLX_2G_MMR = [1.7, 1.7, 0.16]
+AUDI_Q5_MK1 = [1.8, 1.8, 0.18]
+CUPRA_BORN_MK1 = [nan, 2.5, nan]
+FORD_ESCAPE_MK4_5 = [nan, 1.5, nan]
+FORD_EXPEDITION_MK4 = [nan, 1.5, nan]
+HONDA_ACCORD_11G = [1.35, 1.35, 0.17]
+HONDA_CITY_7G = [1.2, 1.2, 0.23]
+HONDA_CRV_6G = [1.3, 1.3, 0.2]
+HONDA_NBOX_2G = [1.2, 1.2, 0.2]
+HONDA_ODYSSEY_5G_MMR = [0.9, 0.9, 0.2]
+HONDA_PASSPORT_4G = [1.2, 1.2, 0.16]
+HONDA_PILOT_4G = [1.25, 1.25, 0.21]
+LEXUS_LS = [1.35, 1.7, 0.17]
+PORSCHE_MACAN_MK1 = [2.0, 2.0, 0.2]
+PSA_PEUGEOT_208 = [nan, 2.0, nan]
+TESLA_MODEL_X = [nan, 2.5, nan]
diff --git a/iqdbc_repo/iqdbc/car/torque_data/params.toml b/iqdbc_repo/iqdbc/car/torque_data/params.toml
index 1fbabf6..1f56375 100644
--- a/iqdbc_repo/iqdbc/car/torque_data/params.toml
+++ b/iqdbc_repo/iqdbc/car/torque_data/params.toml
@@ -37,13 +37,21 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"HYUNDAI_SONATA" = [2.9638737459977467, 2.1259108157250735, 0.07813665616927593]
"HYUNDAI_SONATA_HYBRID" = [2.8990264092395734, 2.061410192222139, 0.0899805488717382]
"HYUNDAI_TUCSON_4TH_GEN" = [2.960174, 2.860284, 0.108745]
+"HYUNDAI_SANTAFE_MX5" = [3.2, 3.0, 0.05]
+"HYUNDAI_SANTAFE_MX5_HEV" = [3.2, 3.0, 0.05]
"JEEP_GRAND_CHEROKEE_2019" = [2.30972, 1.289689569171081, 0.117048]
"JEEP_GRAND_CHEROKEE" = [2.27116, 1.4057367824262523, 0.11725947414922003]
"KIA_EV6" = [3.2, 2.093457, 0.005]
+"KIA_EV6_PE" = [3.2, 2.093457, 0.005]
"KIA_K5_2021" = [2.405339728085138, 1.460032270828705, 0.11650989850813716]
+"KIA_K5_DL3_24" = [2.5, 2.5, 0.1]
+"KIA_K5_DL3_24_HEV" = [2.5, 2.5, 0.1]
"KIA_NIRO_EV" = [2.9215954981365337, 2.1500583840260044, 0.09236802474810267]
"KIA_SORENTO" = [2.464854685101844, 1.5335274218367956, 0.12056170567599558]
"KIA_STINGER" = [2.7499043387418967, 1.849652021986449, 0.12048334239559202]
+"KIA_EV9" = [1.75, 1.75, 0.15]
+"KIA_EV3" = [3.2, 2.093457, 0.005]
+"KIA_PV5" = [3.2, 2.093457, 0.005]
"LEXUS_ES_TSS2" = [2.0357564999999997, 1.999082295195227, 0.101533]
"LEXUS_NX" = [2.3525924753753613, 1.9731412277641067, 0.15168101064205927]
"LEXUS_NX_TSS2" = [2.4331999786982936, 2.1045680431705414, 0.14099899317761067]
@@ -69,8 +77,9 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"TOYOTA_PRIUS" = [1.60, 1.5023147650693636, 0.151515]
"TOYOTA_PRIUS_TSS2" = [1.972600, 1.9104337425537743, 0.170968]
"TOYOTA_RAV4" = [2.085695074355425, 2.2142832316984733, 0.13339165270103975]
-"TOYOTA_RAV4_TSS2" = [1.9557514786720276, 2.087101966779332, 0.12075843289494514]
+"TOYOTA_RAV4_TSS2" = [2.279239424615458, 2.087101966779332, 0.13682208413446817]
"TOYOTA_RAV4H" = [1.9796257271652042, 1.7503987331707576, 0.14628860048885406]
+"TOYOTA_RAV4_TSS2_2022" = [2.241883248393209, 1.9304407208090029, 0.112174]
"TOYOTA_SIENNA" = [1.689726, 1.3208264576110418, 0.140456]
"TOYOTA_YARIS" = [2.22984, 1.86145, 0.168189]
"VOLKSWAGEN_ARTEON_MK1" = [1.45136518053819, 1.3639364049316804, 0.23806361745695032]
diff --git a/iqdbc_repo/iqdbc/car/torque_data/substitute.toml b/iqdbc_repo/iqdbc/car/torque_data/substitute.toml
index b6707cb..a5f5c30 100644
--- a/iqdbc_repo/iqdbc/car/torque_data/substitute.toml
+++ b/iqdbc_repo/iqdbc/car/torque_data/substitute.toml
@@ -9,12 +9,12 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"TOYOTA_ALPHARD_TSS2" = "TOYOTA_SIENNA"
"TOYOTA_PRIUS_V" = "TOYOTA_PRIUS"
-"TOYOTA_SIENNA_4TH_GEN" = "TOYOTA_RAV4_PRIME"
+"TOYOTA_RAV4_PRIME" = "TOYOTA_RAV4_TSS2"
+"TOYOTA_SIENNA_4TH_GEN" = "TOYOTA_RAV4_TSS2"
"LEXUS_IS" = "LEXUS_NX"
"LEXUS_CTH" = "LEXUS_NX"
"LEXUS_ES" = "TOYOTA_CAMRY"
"LEXUS_RC" = "LEXUS_NX_TSS2"
-"LEXUS_RC_TSS2" = "LEXUS_NX_TSS2"
"LEXUS_LC_TSS2" = "LEXUS_NX_TSS2"
"KIA_OPTIMA_G4" = "HYUNDAI_SONATA"
@@ -25,6 +25,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"KIA_CEED" = "HYUNDAI_SONATA"
"KIA_SELTOS" = "HYUNDAI_SONATA"
"KIA_NIRO_PHEV" = "KIA_NIRO_EV"
+"KIA_EV4" = "KIA_EV6"
"KIA_NIRO_PHEV_2022" = "KIA_NIRO_EV"
"KIA_NIRO_HEV_2021" = "KIA_NIRO_EV"
"HYUNDAI_VELOSTER" = "HYUNDAI_SONATA_LF"
@@ -45,12 +46,13 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"GENESIS_G90" = "GENESIS_G70"
"GENESIS_G80" = "GENESIS_G70"
"GENESIS_G70_2020" = "HYUNDAI_SONATA"
+"HYUNDAI_SONATA_2024" = "HYUNDAI_SONATA"
"HONDA_FREED" = "HONDA_ODYSSEY"
"HONDA_CRV_EU" = "HONDA_CRV"
"HONDA_CIVIC_BOSCH_DIESEL" = "HONDA_CIVIC_BOSCH"
"HONDA_E" = "HONDA_CIVIC_BOSCH"
-"HONDA_ODYSSEY_TWN" = "HONDA_ODYSSEY"
+"HONDA_ODYSSEY_CHN" = "HONDA_ODYSSEY"
"BUICK_LACROSSE" = "CHEVROLET_VOLT"
"BUICK_REGAL" = "CHEVROLET_VOLT"
@@ -58,6 +60,18 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"CADILLAC_ATS" = "CHEVROLET_VOLT"
"CHEVROLET_MALIBU" = "CHEVROLET_VOLT"
"HOLDEN_ASTRA" = "CHEVROLET_VOLT"
+"CHEVROLET_VOLT_CC" = "CHEVROLET_VOLT"
+"CHEVROLET_BOLT_CC" = "CHEVROLET_BOLT_EUV"
+"CHEVROLET_BOLT_2017" = "CHEVROLET_BOLT_EUV"
+"CHEVROLET_BOLT_2018" = "CHEVROLET_BOLT_EUV"
+"CHEVROLET_EQUINOX_CC" = "CHEVROLET_EQUINOX"
+"CHEVROLET_SUBURBAN" = "CHEVROLET_SILVERADO"
+"CHEVROLET_SUBURBAN_CC" = "CHEVROLET_SILVERADO"
+"CHEVROLET_TRAX_2024" = "CHEVROLET_VOLT"
+"CADILLAC_CT6_CC" = "CHEVROLET_VOLT"
+"CADILLAC_CT6_ACC" = "CHEVROLET_VOLT"
+"CHEVROLET_TRAILBLAZER_CC" = "CHEVROLET_TRAILBLAZER"
+"CADILLAC_XT5_CC" = "GMC_ACADIA"
"SKODA_FABIA_MK4" = "VOLKSWAGEN_GOLF_MK7"
"SKODA_OCTAVIA_MK3" = "SKODA_SUPERB_MK3"
@@ -74,8 +88,6 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"VOLKSWAGEN_POLO_MK6" = "VOLKSWAGEN_GOLF_MK7"
"SEAT_ATECA_MK1" = "VOLKSWAGEN_GOLF_MK7"
"VOLKSWAGEN_JETTA_MK6" = "VOLKSWAGEN_PASSAT_NMS"
-"VOLKSWAGEN_PASSAT_MK7" = "VOLKSWAGEN_PASSAT_NMS"
-"VOLKSWAGEN_PASSAT_NMS_PLUS" = "VOLKSWAGEN_PASSAT_NMS"
"SUBARU_CROSSTREK_HYBRID" = "SUBARU_IMPREZA_2020"
"SUBARU_FORESTER_HYBRID" = "SUBARU_IMPREZA_2020"
@@ -88,21 +100,34 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"SUBARU_LEGACY_PREGLOBAL" = "SUBARU_IMPREZA"
"SUBARU_ASCENT" = "SUBARU_FORESTER"
-# port extensions
-"KIA_CEED_PHEV_2022_NON_SCC" = "HYUNDAI_SONATA"
-"HYUNDAI_KONA_EV_NON_SCC" = "HYUNDAI_KONA_EV"
-"KIA_FORTE_2019_NON_SCC" = "HYUNDAI_SONATA"
-"KIA_FORTE_2021_NON_SCC" = "HYUNDAI_SONATA"
-"KIA_SELTOS_2023_NON_SCC" = "HYUNDAI_SONATA"
-"HYUNDAI_KONA_NON_SCC" = "HYUNDAI_KONA_EV"
-"HYUNDAI_ELANTRA_2022_NON_SCC" = "HYUNDAI_ELANTRA_2021"
-"GENESIS_G70_2021_NON_SCC" = "HYUNDAI_SONATA"
-"HYUNDAI_BAYON_1ST_GEN_NON_SCC" = "HYUNDAI_SONATA"
-"CHEVROLET_BOLT_NON_ACC_2ND_GEN" = "CHEVROLET_BOLT_EUV"
+# IQ.Pilot GM Non-ACC ports borrow their base platform's lateral tune
"CHEVROLET_BOLT_NON_ACC" = "CHEVROLET_BOLT_EUV"
"CHEVROLET_BOLT_NON_ACC_1ST_GEN" = "CHEVROLET_BOLT_EUV"
+"CHEVROLET_BOLT_NON_ACC_2ND_GEN" = "CHEVROLET_BOLT_EUV"
"CHEVROLET_EQUINOX_NON_ACC_3RD_GEN" = "CHEVROLET_EQUINOX"
"CHEVROLET_SUBURBAN_NON_ACC_11TH_GEN" = "CHEVROLET_SILVERADO"
"CADILLAC_CT6_NON_ACC_1ST_GEN" = "CHEVROLET_VOLT"
"CHEVROLET_TRAILBLAZER_NON_ACC_2ND_GEN" = "CHEVROLET_TRAILBLAZER"
-"CADILLAC_XT5_NON_ACC_1ST_GEN" = "GMC_ACADIA"
+"CHEVROLET_MALIBU_NON_ACC_9TH_GEN" = "CHEVROLET_VOLT"
+"CADILLAC_XT5_NON_ACC_1ST_GEN" = "CADILLAC_XT4"
+
+# Synced verbatim from comma opendbc torque_data/substitute.toml
+"HONDA_ODYSSEY_TWN" = "HONDA_ODYSSEY"
+"LEXUS_RC_TSS2" = "LEXUS_NX_TSS2"
+
+# Platform-sibling substitutes: comma has never shipped torque data for these,
+# so rather than invent lateral-accel figures they borrow the tune of the closest
+# platform twin. REVIEW: replace with measured values when available.
+"SEAT_ALHAMBRA_MK1" = "VOLKSWAGEN_SHARAN_MK2"
+"VOLKSWAGEN_PASSAT_NMS_PLUS" = "VOLKSWAGEN_PASSAT_NMS"
+"VOLKSWAGEN_ID3_MK1" = "VOLKSWAGEN_ID4_MK1"
+"VOLKSWAGEN_ID3_MK2" = "VOLKSWAGEN_ID4_MK2"
+"SKODA_ENYAQ_MK1" = "VOLKSWAGEN_ID4_MK1"
+"SKODA_ENYAQ_MK2" = "VOLKSWAGEN_ID4_MK2"
+"AUDI_Q4_MK1" = "VOLKSWAGEN_ID4_MK1"
+"AUDI_Q4_MK2" = "VOLKSWAGEN_ID4_MK2"
+"VOLKSWAGEN_GOLF_MK8" = "VOLKSWAGEN_GOLF_MK7"
+"SEAT_LEON_MK4" = "VOLKSWAGEN_GOLF_MK7"
+"VOLKSWAGEN_PASSAT_MK7" = "VOLKSWAGEN_PASSAT_NMS"
+"VOLKSWAGEN_PASSAT_B7" = "VOLKSWAGEN_PASSAT_NMS"
+"HONDA_CLARITY" = "HONDA_ACCORD"
diff --git a/iqdbc_repo/iqdbc/car/toyota/carcontroller.py b/iqdbc_repo/iqdbc/car/toyota/carcontroller.py
index 88548d9..04fb4db 100644
--- a/iqdbc_repo/iqdbc/car/toyota/carcontroller.py
+++ b/iqdbc_repo/iqdbc/car/toyota/carcontroller.py
@@ -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
diff --git a/iqdbc_repo/iqdbc/car/toyota/carstate.py b/iqdbc_repo/iqdbc/car/toyota/carstate.py
index 64a2c73..8300e29 100644
--- a/iqdbc_repo/iqdbc/car/toyota/carstate.py
+++ b/iqdbc_repo/iqdbc/car/toyota/carstate.py
@@ -8,7 +8,7 @@ from iqdbc.car.interfaces import CarStateBase
from iqdbc.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, \
TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR, \
SECOC_CAR
-from iqdbc.lvbs.car.toyota.carstate_ext import CarStateExt
+from iqdbc.lvbs.car.toyota.iq_carstate import IQCarState
from iqdbc.lvbs.car.toyota.values import ToyotaFlagsIQ
ButtonType = structs.CarState.ButtonEvent.Type
@@ -26,10 +26,10 @@ TEMP_STEER_FAULTS = (0, 9, 11, 21, 25)
PERM_STEER_FAULTS = (3, 17)
-class CarState(CarStateBase, CarStateExt):
+class CarState(CarStateBase, IQCarState):
def __init__(self, CP, CP_IQ):
CarStateBase.__init__(self, CP, CP_IQ)
- CarStateExt.__init__(self, CP, CP_IQ)
+ IQCarState.__init__(self, CP, CP_IQ)
can_define = CANDefine(DBC[CP.carFingerprint][Bus.pt])
self.eps_torque_scale = EPS_SCALE[CP.carFingerprint] / 100.
self.cluster_speed_hyst_gap = CV.KPH_TO_MS / 2.
@@ -210,7 +210,7 @@ class CarState(CarStateBase, CarStateExt):
ret.buttonEvents = buttonEvents
- CarStateExt.update(self, ret, ret_iq, can_parsers)
+ IQCarState.update(self, ret, ret_iq, can_parsers)
return ret, ret_iq
diff --git a/iqdbc_repo/iqdbc/car/toyota/fingerprints.py b/iqdbc_repo/iqdbc/car/toyota/fingerprints.py
index e5b5f89..582f314 100644
--- a/iqdbc_repo/iqdbc/car/toyota/fingerprints.py
+++ b/iqdbc_repo/iqdbc/car/toyota/fingerprints.py
@@ -2,8 +2,8 @@
from iqdbc.car.structs import CarParams
from iqdbc.car.toyota.values import CAR
-from iqdbc.lvbs.car.fingerprints_ext import extend_fw_versions
-from iqdbc.lvbs.car.toyota.fingerprints_ext import FW_VERSIONS_EXT
+from iqdbc.lvbs.car.iq_fingerprints import extend_fw_versions
+from iqdbc.lvbs.car.toyota.iq_fingerprints import FW_VERSIONS_EXT
Ecu = CarParams.Ecu
diff --git a/iqdbc_repo/iqdbc/car/toyota/interface.py b/iqdbc_repo/iqdbc/car/toyota/interface.py
index 9455b35..865de2f 100644
--- a/iqdbc_repo/iqdbc/car/toyota/interface.py
+++ b/iqdbc_repo/iqdbc/car/toyota/interface.py
@@ -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
diff --git a/iqdbc_repo/iqdbc/car/toyota/tests/test_toyota_iq.py b/iqdbc_repo/iqdbc/car/toyota/tests/test_toyota_iq.py
index 3bac02a..1004a9d 100644
--- a/iqdbc_repo/iqdbc/car/toyota/tests/test_toyota_iq.py
+++ b/iqdbc_repo/iqdbc/car/toyota/tests/test_toyota_iq.py
@@ -4,26 +4,20 @@ from iqdbc.car.toyota.values import CAR, ToyotaFlags
from iqdbc.lvbs.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():
diff --git a/iqdbc_repo/iqdbc/car/volkswagen/carcontroller.py b/iqdbc_repo/iqdbc/car/volkswagen/carcontroller.py
index 595ab1b..ba5c3ab 100644
--- a/iqdbc_repo/iqdbc/car/volkswagen/carcontroller.py
+++ b/iqdbc_repo/iqdbc/car/volkswagen/carcontroller.py
@@ -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 and not CS.out.radarDisableFailed:
+ 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
diff --git a/iqdbc_repo/iqdbc/car/volkswagen/carstate.py b/iqdbc_repo/iqdbc/car/volkswagen/carstate.py
index 2a2b130..fff7957 100644
--- a/iqdbc_repo/iqdbc/car/volkswagen/carstate.py
+++ b/iqdbc_repo/iqdbc/car/volkswagen/carstate.py
@@ -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, pt_cp.vl["Kombi_02"]["KBI_Kilometerstand"])
self.cruise_faulted = ret.accFaulted
self._apply_iq_private_flags(ret_iq)
@@ -340,19 +372,11 @@ class CarState(CarStateBase):
self.ldw_stock_values = cam_cp.vl["LDW_02"]
- if not (self.CP.flags & VolkswagenFlags.DISABLE_RADAR):
- awv_values = ext_cp.vl.get("AWV_03", ext_cp.vl.get("ACC_10", {}))
- ret.stockFcw = bool(awv_values.get("FCW_Active", 0)) or bool(awv_values.get("AWV2_Freigabe", 0))
- else:
- ret.stockFcw = False
+ awv_values = ext_cp.vl.get("AWV_03", ext_cp.vl.get("ACC_10", {}))
+ ret.stockFcw = bool(awv_values.get("FCW_Active", 0)) or bool(awv_values.get("AWV2_Freigabe", 0))
ret.stockAeb = False
- # Camera harness (DISABLE_RADAR): ext_cp == pt_cp, so ACC_18 reads our own sent value.
- # Hardcode acc_type=2 (stop-and-go capable) to avoid self-referential read on first frame.
- if self.CP.flags & VolkswagenFlags.DISABLE_RADAR:
- self.acc_type = 2
- else:
- self.acc_type = ext_cp.vl["ACC_18"]["ACC_Typ"]
+ self.acc_type = ext_cp.vl["ACC_18"]["ACC_Typ"]
self.travel_assist_available = bool(pt_cp.vl.get("TA_01", {}).get("Travel_Assist_Available", 0))
ret.cruiseState.available = pt_cp.vl["Motor_51"]["TSK_Status"] in (2, 3, 4, 5)
@@ -385,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
@@ -409,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
@@ -426,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
@@ -461,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
@@ -476,7 +498,7 @@ 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
@@ -511,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
@@ -532,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:
@@ -552,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
@@ -571,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"],
@@ -587,6 +641,13 @@ class CarState(CarStateBase):
ret.fuelGauge = pt_cp.vl["Kombi_1"]["Tankinhalt"] / 55.0
ret.fuelTankLevelL = 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
@@ -623,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"])
@@ -656,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)
@@ -688,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
@@ -743,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
@@ -758,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),
}
@@ -771,14 +842,13 @@ 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
]
- # AWV_03 (stock radar FCW/AEB) — don't subscribe when DISABLE_RADAR, the radar is silenced
- # and our carcontroller sends the replacement. Subscribing causes CAN parser timeout errors.
- if CP.networkLocation == NetworkLocation.fwdCamera and not (CP.flags & VolkswagenFlags.DISABLE_RADAR):
+ if CP.networkLocation == NetworkLocation.fwdCamera:
pt_messages.append(("AWV_03", 1))
cam_messages = []
- if CP.networkLocation == NetworkLocation.gateway and not (CP.flags & VolkswagenFlags.DISABLE_RADAR):
+ if CP.networkLocation == NetworkLocation.gateway:
cam_messages.append(("AWV_03", 1))
return {
diff --git a/iqdbc_repo/iqdbc/car/volkswagen/fingerprints.py b/iqdbc_repo/iqdbc/car/volkswagen/fingerprints.py
index afa1286..60e6793 100644
--- a/iqdbc_repo/iqdbc/car/volkswagen/fingerprints.py
+++ b/iqdbc_repo/iqdbc/car/volkswagen/fingerprints.py
@@ -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',
diff --git a/iqdbc_repo/iqdbc/car/volkswagen/interface.py b/iqdbc_repo/iqdbc/car/volkswagen/interface.py
index 4e9418c..85a4a9b 100644
--- a/iqdbc_repo/iqdbc/car/volkswagen/interface.py
+++ b/iqdbc_repo/iqdbc/car/volkswagen/interface.py
@@ -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:
@@ -151,7 +171,7 @@ class CarInterface(CarInterfaceBase):
ret.steerLimitTimer = 0.4
if ret.flags & VolkswagenFlags.PQ:
ret.steerActuatorDelay = 0.2
- ret.longitudinalTuning.kfDEPRECATED = 1.2
+ ret.longitudinalTuning.kf = 1.2
ret.longitudinalTuning.kpBP = [0.]
ret.longitudinalTuning.kpV = [.45]
ret.longitudinalTuning.kiBP = [0.]
@@ -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
diff --git a/iqdbc_repo/iqdbc/car/volkswagen/mebutils.py b/iqdbc_repo/iqdbc/car/volkswagen/mebutils.py
index 13edc7d..0fe157b 100644
--- a/iqdbc_repo/iqdbc/car/volkswagen/mebutils.py
+++ b/iqdbc_repo/iqdbc/car/volkswagen/mebutils.py
@@ -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
diff --git a/iqdbc_repo/iqdbc/car/volkswagen/mlbcan.py b/iqdbc_repo/iqdbc/car/volkswagen/mlbcan.py
index a2d5f42..aee56e2 100644
--- a/iqdbc_repo/iqdbc/car/volkswagen/mlbcan.py
+++ b/iqdbc_repo/iqdbc/car/volkswagen/mlbcan.py
@@ -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)
diff --git a/iqdbc_repo/iqdbc/car/volkswagen/mqbcan.py b/iqdbc_repo/iqdbc/car/volkswagen/mqbcan.py
index 317ca94..bd759e2 100644
--- a/iqdbc_repo/iqdbc/car/volkswagen/mqbcan.py
+++ b/iqdbc_repo/iqdbc/car/volkswagen/mqbcan.py
@@ -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,
}
diff --git a/iqdbc_repo/iqdbc/car/volkswagen/pq_radar_handler.py b/iqdbc_repo/iqdbc/car/volkswagen/pq_radar_handler.py
new file mode 100644
index 0000000..8596bc1
--- /dev/null
+++ b/iqdbc_repo/iqdbc/car/volkswagen/pq_radar_handler.py
@@ -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
diff --git a/iqdbc_repo/iqdbc/car/volkswagen/pqcan.py b/iqdbc_repo/iqdbc/car/volkswagen/pqcan.py
index a6a5505..cc5c168 100644
--- a/iqdbc_repo/iqdbc/car/volkswagen/pqcan.py
+++ b/iqdbc_repo/iqdbc/car/volkswagen/pqcan.py
@@ -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)
diff --git a/iqdbc_repo/iqdbc/car/volkswagen/tests/test_iqpilot_vw_toggles.py b/iqdbc_repo/iqdbc/car/volkswagen/tests/test_iqpilot_vw_toggles.py
new file mode 100644
index 0000000..7e0d6c7
--- /dev/null
+++ b/iqdbc_repo/iqdbc/car/volkswagen/tests/test_iqpilot_vw_toggles.py
@@ -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)
diff --git a/iqdbc_repo/iqdbc/car/volkswagen/tests/test_pq_can_valid.py b/iqdbc_repo/iqdbc/car/volkswagen/tests/test_pq_can_valid.py
new file mode 100644
index 0000000..5858303
--- /dev/null
+++ b/iqdbc_repo/iqdbc/car/volkswagen/tests/test_pq_can_valid.py
@@ -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"
+ )
diff --git a/iqdbc_repo/iqdbc/car/volkswagen/tests/test_stopping.py b/iqdbc_repo/iqdbc/car/volkswagen/tests/test_stopping.py
new file mode 100644
index 0000000..9a07a21
--- /dev/null
+++ b/iqdbc_repo/iqdbc/car/volkswagen/tests/test_stopping.py
@@ -0,0 +1,33 @@
+import pytest
+
+from iqdbc.car.volkswagen.interface import CarInterface
+from iqdbc.car.volkswagen.values import (
+ CAR, PASSAT_B7_STOP_ACCEL, PASSAT_B7_STOPPING_SPEED, PQ_STOPPING_SPEED,
+ VolkswagenFlags, apply_pq_stopping_accel, get_longitudinal_stopping_speed_override,
+)
+
+
+@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
+
+
+@pytest.mark.parametrize("candidate", [
+ CAR.VOLKSWAGEN_JETTA_MK6,
+ CAR.VOLKSWAGEN_PASSAT_NMS,
+])
+def test_pq_longitudinal_feedforward_uses_active_schema_field(candidate):
+ fingerprint = {bus: {} for bus in range(8)}
+ cp = CarInterface.get_params(candidate, fingerprint, [], alpha_long=True, is_release=False, docs=False)
+ assert cp.longitudinalTuning.kf == pytest.approx(1.2)
diff --git a/iqdbc_repo/iqdbc/car/volkswagen/tests/test_volkswagen.py b/iqdbc_repo/iqdbc/car/volkswagen/tests/test_volkswagen.py
index f180743..83a6e24 100644
--- a/iqdbc_repo/iqdbc/car/volkswagen/tests/test_volkswagen.py
+++ b/iqdbc_repo/iqdbc/car/volkswagen/tests/test_volkswagen.py
@@ -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)
diff --git a/iqdbc_repo/iqdbc/car/volkswagen/values.py b/iqdbc_repo/iqdbc/car/volkswagen/values.py
index 3de31b4..d6aa955 100644
--- a/iqdbc_repo/iqdbc/car/volkswagen/values.py
+++ b/iqdbc_repo/iqdbc/car/volkswagen/values.py
@@ -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"]
@@ -141,8 +142,6 @@ class CarControllerParams:
}
elif CP.flags & (VolkswagenFlags.MEB | VolkswagenFlags.MQB_EVO):
- self.AEB_CONTROL_STEP = 100 # AWV_03 radar-replacement at 1Hz (class default 2 = 50Hz is for MQB ACC_10)
- self.AEB_HUD_STEP = 20 # MEB_AWV_01 AEB HUD at 5Hz
self.LDW_STEP = 10
self.ACC_HUD_STEP = 6
self.STEER_DRIVER_ALLOWANCE = 60
@@ -286,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):
@@ -313,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}
@@ -335,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
@@ -544,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(
[
@@ -575,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),
@@ -882,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()
diff --git a/iqdbc_repo/iqdbc/dbc/SConscript b/iqdbc_repo/iqdbc/dbc/SConscript
index 481e024..dfae42d 100644
--- a/iqdbc_repo/iqdbc/dbc/SConscript
+++ b/iqdbc_repo/iqdbc/dbc/SConscript
@@ -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'),
)
diff --git a/iqdbc_repo/iqdbc/dbc/generator/honda/honda_bosch_radarless.dbc b/iqdbc_repo/iqdbc/dbc/generator/honda/honda_bosch_radarless.dbc
index 2b86a33..f57265f 100644
--- a/iqdbc_repo/iqdbc/dbc/generator/honda/honda_bosch_radarless.dbc
+++ b/iqdbc_repo/iqdbc/dbc/generator/honda/honda_bosch_radarless.dbc
@@ -7,7 +7,7 @@ CM_ "IMPORT _gearbox_common.dbc";
BO_ 456 ACC_CONTROL: 8 XXX
SG_ ACCEL_COMMAND : 7|12@0- (0.01,0) [0|0] "m/s^2" XXX
- SG_ IDLESTOP_ALLOW : 8|1@0+ (1,0) [0|1] "" XXX
+ SG_ BRAKE_REQUEST : 8|1@0+ (1,0) [0|1] "" XXX
SG_ STANDSTILL : 9|1@0+ (1,0) [0|1] "" XXX
SG_ CONTROL_ON : 10|1@0+ (1,0) [0|1] "" XXX
SG_ BOH : 23|1@0+ (1,0) [0|1] "" XXX
diff --git a/iqdbc_repo/iqdbc/dbc/generator/hyundai/.gitignore b/iqdbc_repo/iqdbc/dbc/generator/hyundai/.gitignore
index 81f73f3..9f93c92 100644
--- a/iqdbc_repo/iqdbc/dbc/generator/hyundai/.gitignore
+++ b/iqdbc_repo/iqdbc/dbc/generator/hyundai/.gitignore
@@ -1,2 +1,3 @@
hyundai_kia_mando_front_radar.dbc
+hyundai_kia_denso_front_radar.dbc
hyundai_kia_mando_corner_radar.dbc
diff --git a/iqdbc_repo/iqdbc/dbc/generator/hyundai/_hyundai_canfd_common.dbc b/iqdbc_repo/iqdbc/dbc/generator/hyundai/_hyundai_common.dbc
similarity index 94%
rename from iqdbc_repo/iqdbc/dbc/generator/hyundai/_hyundai_canfd_common.dbc
rename to iqdbc_repo/iqdbc/dbc/generator/hyundai/_hyundai_common.dbc
index 1975155..52a0693 100644
--- a/iqdbc_repo/iqdbc/dbc/generator/hyundai/_hyundai_canfd_common.dbc
+++ b/iqdbc_repo/iqdbc/dbc/generator/hyundai/_hyundai_common.dbc
@@ -40,18 +40,21 @@ BO_ 80 LKAS: 16 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX
- SG_ LKA_AVAILABLE : 27|2@1+ (1,0) [0|255] "" XXX
+ SG_ LKA_ACTIVE : 27|2@1+ (1,0) [0|255] "" XXX
SG_ LKA_WARNING : 32|1@1+ (1,0) [0|1] "" XXX
SG_ LKA_ICON : 38|2@1+ (1,0) [0|255] "" XXX
SG_ FCA_SYSWARN : 40|1@0+ (1,0) [0|1] "" XXX
SG_ TORQUE_REQUEST : 41|11@1+ (1,-1024) [0|4095] "" XXX
SG_ STEER_REQ : 52|1@1+ (1,0) [0|1] "" XXX
SG_ LFA_BUTTON : 56|1@1+ (1,0) [0|255] "" XXX
- SG_ LKA_ASSIST : 62|1@1+ (1,0) [0|1] "" XXX
- SG_ STEER_MODE : 65|3@1+ (1,0) [0|1] "" XXX
- SG_ NEW_SIGNAL_2 : 70|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALUE63 : 63|4@0+ (1,0) [0|15] "" XXX
+ SG_ VALUE64 : 64|8@1+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_1 : 75|4@0+ (1,0) [0|15] "" XXX
+ SG_ LKAS_ANGLE_ACTIVE : 77|2@0+ (1,0) [0|3] "" XXX
SG_ HAS_LANE_SAFETY : 80|1@0+ (1,0) [0|1] "" XXX
- SG_ DAMP_FACTOR : 64|8@1+ (1,0) [0|255] "" XXX
+ SG_ LKAS_ANGLE_CMD : 82|14@1- (-0.1,0) [0|511] "" XXX
+ SG_ LKAS_ANGLE_MAX_TORQUE : 96|8@1+ (1,0) [0|255] "" XXX
+ SG_ VALUE104 : 104|8@1+ (1,0) [0|255] "" XXX
BO_ 81 ADRV_0x51: 32 ADRV
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
diff --git a/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd.dbc b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd.dbc
index e97cb97..26aa743 100644
--- a/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd.dbc
+++ b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd.dbc
@@ -1,4 +1,40 @@
-CM_ "IMPORT _hyundai_canfd_common.dbc";
+VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ VAL_TABLE_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX CAMERA FRONT_RADAR ADRV APRK
+
BO_ 53 ACCELERATOR: 32 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
@@ -10,22 +46,56 @@ BO_ 64 GEAR_ALT: 32 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ GEAR : 32|3@1+ (1,0) [0|7] "" XXX
+ SG_ GEAR_STEP : 67|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_4 : 68|4@1+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_1 : 75|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_3 : 76|4@1+ (1,0) [0|15] "" XXX
BO_ 69 GEAR: 24 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ GEAR : 44|3@1+ (1,0) [0|7] "" XXX
+ SG_ RIGHT_PADDLE : 57|1@0+ (1,0) [0|1] "" XXX
+ SG_ LEFT_PADDLE : 58|1@0+ (1,0) [0|1] "" XXX
+ SG_ GEAR_STEP : 146|5@1+ (1,0) [0|31] "" XXX
+ SG_ GEAR_STEP1 : 154|5@1+ (1,0) [0|31] "" XXX
+
+BO_ 80 LKAS: 16 XXX
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX
+ SG_ LKA_ACTIVE : 27|2@1+ (1,0) [0|255] "" XXX
+ SG_ LKA_WARNING : 32|1@1+ (1,0) [0|1] "" XXX
+ SG_ LKA_ICON : 38|2@1+ (1,0) [0|255] "" XXX
+ SG_ FCA_SYSWARN : 40|1@0+ (1,0) [0|1] "" XXX
+ SG_ TORQUE_REQUEST : 41|11@1+ (1,-1024) [0|4095] "" XXX
+ SG_ STEER_REQ : 52|1@1+ (1,0) [0|1] "" XXX
+ SG_ LFA_BUTTON : 56|1@1+ (1,0) [0|255] "" XXX
+ SG_ VALUE63 : 63|4@0+ (1,0) [0|15] "" XXX
+ SG_ VALUE64 : 64|8@1+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_1 : 75|4@0+ (1,0) [0|15] "" XXX
+ SG_ LKAS_ANGLE_ACTIVE : 77|2@0+ (1,0) [0|3] "" XXX
+ SG_ HAS_LANE_SAFETY : 80|1@0+ (1,0) [0|1] "" XXX
+ SG_ LKAS_ANGLE_CMD : 82|14@1- (-0.1,0) [0|511] "" XXX
+ SG_ LKAS_ANGLE_MAX_TORQUE : 96|8@1+ (1,0) [0|255] "" XXX
+ SG_ DampingGain : 104|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 81 ADRV_0x51: 32 ADRV
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
BO_ 96 ESP_STATUS: 32 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ TRACTION_AND_STABILITY_CONTROL : 42|3@1+ (1,0) [0|63] "" XXX
- SG_ BRAKE_PRESSURE : 128|10@1+ (1,0) [0|65535] "" XXX
+ SG_ BRAKE_PRESSURE : 128|11@1+ (1,0) [0|2047] "" XXX
SG_ BRAKE_PRESSED : 148|1@1+ (1,0) [0|3] "" XXX
+ SG_ AUTO_HOLD : 192|1@0+ (1,0) [0|1] "" XXX
BO_ 101 BRAKE: 32 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ BRAKE_LIGHT : 29|1@0+ (1,0) [0|1] "" XXX
SG_ BRAKE_POSITION : 40|16@1- (1,0) [0|65535] "" XXX
SG_ BRAKE_PRESSED : 57|1@1+ (1,0) [0|3] "" XXX
@@ -41,32 +111,35 @@ BO_ 160 WHEEL_SPEEDS: 24 XXX
SG_ MOVING_BACKWARD : 57|1@0+ (1,0) [0|1] "" XXX
SG_ MOVING_FORWARD2 : 58|1@0+ (1,0) [0|1] "" XXX
SG_ MOVING_BACKWARD2 : 59|1@0+ (1,0) [0|1] "" XXX
- SG_ WHL_SpdFLVal : 64|14@1+ (0.03125,0) [0|0] "km^h" XXX
- SG_ WHL_SpdFRVal : 80|14@1+ (0.03125,0) [0|0] "km^h" XXX
- SG_ WHL_SpdRLVal : 96|14@1+ (0.03125,0) [0|0] "km^h" XXX
- SG_ WHL_SpdRRVal : 112|14@1+ (0.03125,0) [0|0] "km^h" XXX
+ SG_ WHEEL_SPEED_1 : 64|16@1+ (0.03125,0) [0|65535] "kph" XXX
+ SG_ WHEEL_SPEED_2 : 80|16@1+ (0.03125,0) [0|65535] "kph" XXX
+ SG_ WHEEL_SPEED_3 : 96|16@1+ (0.03125,0) [0|65535] "kph" XXX
+ SG_ WHEEL_SPEED_4 : 112|16@1+ (0.03125,0) [0|65535] "kph" XXX
-BO_ 203 ADAS_CMD_35_10ms: 24 CGW_CCU
- SG_ CHECKSUM : 0|16@1+ (1,0) [0|0] "0" FCU_C,GW_RGW,MDPS,SFA
- SG_ COUNTER : 16|8@1+ (1,0) [0|0] "0" FCU_C,GW_RGW,MDPS,SFA
- SG_ ADAS_ActvACISta : 24|4@1+ (1,0) [0|0] "" GW_RGW,MDPS,SFA
- SG_ ADAS_ActvACILvl2Sta : 28|4@1+ (1,0) [0|0] "" ESC,FCU_C,GW_RGW,MDPS,SFA,VPC_C
- SG_ ADAS_StrAnglReqVal : 32|14@1- (0.1,0) [0|119.9] "Deg" GW_RGW,MDPS,SFA
- SG_ ADAS_ACIAnglTqRedcGainVal : 48|8@1+ (0.004,0) [0|1] "" GW_RGW,MDPS,SFA
- SG_ FCA_ESA_ActvSta : 56|2@1+ (1,0) [0|0] "" GW_RGW,MDPS,SFA
- SG_ FCA_ESA_TqBstGainVal : 64|8@1+ (0.004,0) [0|0] "" GW_RGW,MDPS,SFA
+BO_ 203 LFA_ALT: 24 ADRV
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ LKAS_ANGLE_ACTIVE : 29|2@0+ (1,0) [0|3] "" XXX
+ SG_ LKAS_ANGLE_CMD : 32|14@1- (-0.1,0) [0|511] "" XXX
+ SG_ LKAS_ANGLE_MAX_TORQUE : 55|8@0+ (1,0) [0|255] "" XXX
BO_ 234 MDPS: 24 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_1 : 31|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_2 : 39|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_3 : 47|8@0+ (1,0) [0|255] "" XXX
SG_ LKA_ACTIVE : 48|1@0+ (1,0) [0|16777215] "" XXX
SG_ LKA_FAULT : 54|1@0+ (1,0) [0|1] "" XXX
SG_ STEERING_OUT_TORQUE : 64|12@1+ (0.1,-204.8) [0|65535] "" XXX
SG_ STEERING_COL_TORQUE : 80|13@1+ (1,-4095) [0|4095] "" XXX
- SG_ STEERING_ANGLE : 96|16@1- (0.1,0) [0|255] "deg" XXX
- SG_ STEERING_ANGLE_2 : 128|16@1- (0.1,0) [0|65535] "deg" XXX
- SG_ LKA_ANGLE_ACTIVE : 145|2@0+ (1,0) [0|3] "" XXX
- SG_ LKA_ANGLE_FAULT : 149|1@0+ (1,0) [0|1] "" XXX
+ SG_ STEERING_ANGLE : 96|16@1- (-0.1,0) [0|255] "deg" XXX
+ SG_ STEERING_ANGLE_2 : 128|16@1- (-0.1,0) [0|65535] "deg" XXX
+ SG_ LFA2_ACTIVE : 145|2@0+ (1,0) [0|3] "" XXX
+ SG_ LFA2_FAULT : 149|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_4 : 159|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_5 : 167|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_6 : 175|8@0+ (1,0) [0|255] "" XXX
BO_ 256 ACCELERATOR_BRAKE_ALT: 32 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
@@ -79,73 +152,63 @@ BO_ 261 ACCELERATOR_ALT: 32 XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ ACCELERATOR_PEDAL : 103|10@1+ (0.25,0) [0|1022] "" XXX
+BO_ 267 CRUISE_BUTTONS_ALT2: 16 XXX
+ SG_ CRUISE_BUTTONS : 83|4@0+ (1,0) [0|15] "" XXX
+ SG_ LFA_BTN : 87|1@0+ (1,0) [0|1] "" XXX
+
BO_ 272 LKAS_ALT: 32 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX
- SG_ LKA_AVAILABLE : 27|2@1+ (1,0) [0|255] "" XXX
+ SG_ LKA_ACTIVE : 27|2@1+ (1,0) [0|3] "" XXX
SG_ LKA_WARNING : 32|1@1+ (1,0) [0|1] "" XXX
- SG_ LKA_ICON : 38|2@1+ (1,0) [0|255] "" XXX
+ SG_ LKA_ICON : 38|2@1+ (1,0) [0|3] "" XXX
SG_ FCA_SYSWARN : 40|1@0+ (1,0) [0|1] "" XXX
SG_ TORQUE_REQUEST : 41|11@1+ (1,-1024) [0|4095] "" XXX
SG_ STEER_REQ : 52|1@1+ (1,0) [0|1] "" XXX
- SG_ LFA_BUTTON : 56|1@1+ (1,0) [0|255] "" XXX
- SG_ LKA_ASSIST : 62|1@1+ (1,0) [0|1] "" XXX
- SG_ STEER_MODE : 65|3@1+ (1,0) [0|1] "" XXX
- SG_ NEW_SIGNAL_2 : 70|2@0+ (1,0) [0|3] "" XXX
+ SG_ LFA_BUTTON : 56|1@1+ (1,0) [0|1] "" XXX
+ SG_ VALUE63 : 63|4@0+ (1,0) [0|15] "" XXX
+ SG_ VALUE64 : 64|8@1+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_1 : 75|4@0+ (1,0) [0|15] "" XXX
SG_ LKAS_ANGLE_ACTIVE : 77|2@0+ (1,0) [0|3] "" XXX
SG_ HAS_LANE_SAFETY : 80|1@0+ (1,0) [0|1] "" XXX
- SG_ ADAS_StrAnglReqVal : 82|14@1- (0.1,0) [0|176.7] "Deg" GW_RGW,MDPS,SFA
- SG_ ADAS_ACIAnglTqRedcGainVal : 96|8@1+ (0.004,0) [0|1] "" GW_RGW,MDPS,SFA
- SG_ DAMP_FACTOR : 64|8@1+ (1,0) [0|255] "" XXX
-
-BO_ 282 FR_CMR_01_10ms: 16 FR_CMR
- SG_ FR_CMR_Crc1Val : 0|16@1+ (1,0) [0|0] "" Dummy,IBU_HS,vBDM
- SG_ FR_CMR_AlvCnt1Val : 16|8@1+ (1,0) [0|0] "" CLU,IBU_HS,vBDM
- SG_ HBA_SysOptSta : 24|2@1+ (1,0) [0|3] "" CLU,IBU_HS,vBDM
- SG_ HBA_SysSta : 26|3@1+ (1,0) [0|7] "" CLU,IBU_HS,vBDM
- SG_ HBA_IndLmpReq : 29|2@1+ (1,0) [0|3] "" CLU,vBDM
- SG_ iHBAref_VehLftSta : 31|2@1+ (1,0) [0|3] "" IBU_HS,ICU,vBDM
- SG_ iHBAref_VehCtrSta : 33|2@1+ (1,0) [0|3] "" IBU_HS,ICU,vBDM
- SG_ iHBAref_VehRtSta : 35|2@1+ (1,0) [0|3] "" IBU_HS,ICU,vBDM
- SG_ iHBAref_ILLAmbtSta : 37|2@1+ (1,0) [0|3] "" IBU_HS,ICU,vBDM
- SG_ FCA_Equip_MFC : 39|3@1+ (1,0) [0|0] "" ADAS_DRV,RR_C_RDR,vBDM
- SG_ HBA_OptUsmSta : 42|2@1+ (1,0) [0|3] "" CLU,H_U_MM
- SG_ FCAref_FusSta : 45|3@1+ (1,0) [0|0] "" vBDM
- SG_ DAW_LVDA_PUDis : 48|2@1+ (1,0) [0|0] "" CLU,vBDM
- SG_ DAW_LVDA_OptUsmSta : 50|2@1+ (1,0) [0|3] "" CLU,H_U_MM,vBDM
- SG_ DAW_OptUsmSta : 52|3@1+ (1,0) [0|0] "" CLU,H_U_MM
- SG_ DAW_SysSta : 55|4@1+ (1,0) [0|0] "" CLU
- SG_ DAW_WrnMsgSta : 59|3@1+ (1,0) [0|0] "" CLU
- SG_ DAW_TimeRstReq : 62|2@1+ (1,0) [0|0] "" CLU
- SG_ DAW_SnstvtyModRetVal : 64|3@1+ (1,0) [0|0] "" CLU,H_U_MMz
- SG_ FR_CMR_SCCEquipSta : 85|2@1+ (1,0) [0|3] "" CGW
- SG_ FR_CMR_ReqADASMapMsgVal : 96|16@1+ (1,0) [0|65535] "" CGW
- SG_ FR_CMR_SwVer1Val : 112|4@1+ (1,0) [0|15] "" CGW
- SG_ FR_CMR_SwVer2Val : 120|8@1+ (1,0) [0|255] "" CGW
+ SG_ LKAS_ANGLE_CMD : 82|14@1- (-0.1,0) [0|511] "" XXX
+ SG_ LKAS_ANGLE_MAX_TORQUE : 96|8@1+ (1,0) [0|255] "" XXX
+ SG_ DampingGain : 104|8@1+ (1,0) [0|255] "" XXX
+ SG_ VALUE231 : 231|8@0+ (1,0) [0|255] "" XXX
+ SG_ VALUE239 : 239|8@0+ (1,0) [0|255] "" XXX
+ SG_ VALUE247 : 247|8@0+ (1,0) [0|255] "" XXX
+ SG_ VALUE255 : 255|8@0+ (1,0) [0|255] "" XXX
BO_ 293 STEERING_SENSORS: 16 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
- SG_ STEERING_ANGLE : 24|16@1- (0.1,0) [0|255] "deg" XXX
+ SG_ STEERING_ANGLE : 24|16@1- (-0.1,0) [0|255] "deg" XXX
SG_ STEERING_RATE : 40|8@1+ (4,0) [0|1016] "deg/s" XXX
BO_ 298 LFA: 16 ADRV
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ LKA_MODE : 24|3@1+ (1,0) [0|7] "" XXX
- SG_ NEW_SIGNAL_1 : 27|2@1+ (1,0) [0|255] "" XXX
+ SG_ LKA_ACTIVE : 27|2@1+ (1,0) [0|3] "" XXX
SG_ LKA_WARNING : 32|1@1+ (1,0) [0|1] "" XXX
- SG_ LKA_ICON : 38|2@1+ (1,0) [0|255] "" XXX
+ SG_ LKA_ICON : 38|2@1+ (1,0) [0|3] "" XXX
+ SG_ FCA_SYSWARN : 40|1@0+ (1,0) [0|1] "" XXX
SG_ TORQUE_REQUEST : 41|11@1+ (1,-1024) [0|4095] "" XXX
SG_ STEER_REQ : 52|1@1+ (1,0) [0|1] "" XXX
- SG_ LFA_BUTTON : 56|1@1+ (1,0) [0|255] "" XXX
- SG_ LKA_ASSIST : 62|1@1+ (1,0) [0|1] "" XXX
- SG_ STEER_MODE : 65|3@1+ (1,0) [0|1] "" XXX
- SG_ NEW_SIGNAL_2 : 70|2@0+ (1,0) [0|3] "" XXX
- SG_ NEW_SIGNAL_4 : 72|4@1+ (1,0) [0|15] "" XXX
+ SG_ LFA_BUTTON : 56|1@1+ (1,0) [0|1] "" XXX
+ SG_ VALUE63 : 63|4@0+ (1,0) [0|15] "" XXX
+ SG_ VALUE64 : 64|8@1+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_1 : 75|4@0+ (1,0) [0|15] "" XXX
+ SG_ LKAS_ANGLE_ACTIVE : 77|2@0+ (1,0) [0|3] "" XXX
SG_ HAS_LANE_SAFETY : 80|1@0+ (1,0) [0|1] "" XXX
- SG_ DAMP_FACTOR : 104|8@1+ (1,0) [0|255] "" XXX
+ SG_ LKAS_ANGLE_CMD : 82|14@1- (-0.1,0) [0|511] "" XXX
+ SG_ LKAS_ANGLE_MAX_TORQUE : 96|8@1+ (1,0) [0|255] "" XXX
+ SG_ DampingGain : 104|8@1+ (1,0) [0|255] "" XXX
+ SG_ VALUE231 : 231|8@0+ (1,0) [0|255] "" XXX
+ SG_ VALUE239 : 239|8@0+ (1,0) [0|255] "" XXX
+ SG_ VALUE247 : 247|8@0+ (1,0) [0|255] "" XXX
+ SG_ VALUE255 : 255|8@0+ (1,0) [0|255] "" XXX
BO_ 304 GEAR_SHIFTER: 16 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
@@ -154,75 +217,77 @@ BO_ 304 GEAR_SHIFTER: 16 XXX
SG_ KNOB_POSITION : 40|3@1+ (1,0) [0|3] "" XXX
SG_ GEAR : 64|3@1+ (1,0) [0|7] "" XXX
+BO_ 1079 TRAILER_STATUS: 8 XXX
+ SG_ TRAILER_CONNECTED : 0|1@1+ (1,0) [0|1] "" XXX
+
BO_ 352 ADRV_0x160: 16 ADRV
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ AEB_SETTING : 24|2@1+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_1 : 30|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_4 : 31|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_5 : 39|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_6 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_2 : 55|8@0+ (1,0) [0|255] "" XXX
SG_ SET_ME_2 : 56|8@1+ (1,0) [0|1] "" XXX
SG_ SET_ME_FF : 64|8@1+ (1,0) [0|255] "" XXX
SG_ SET_ME_FC : 72|8@1+ (1,0) [0|255] "" XXX
SG_ SET_ME_9 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_3 : 95|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 102|1@0+ (1,0) [0|1] "" XXX
-BO_ 353 CCNC_0x161: 32 CCNC
+BO_ 353 ADRV_0x161: 32 ADRV
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ FCA_ICON : 24|3@1+ (1,0) [0|7] "" XXX
SG_ FCA_ALT_ICON : 27|3@1+ (1,0) [0|7] "" XXX
SG_ LKA_ICON : 30|3@1+ (1,0) [0|3] "" XXX
SG_ HBA_ICON : 33|3@1+ (1,0) [0|7] "" XXX
- SG_ ZEROS_1 : 36|4@1+ (1,0) [0|15] "" XXX
- SG_ ZEROS_2 : 40|2@1+ (1,0) [0|3] "" XXX
SG_ FCA_IMAGE : 42|3@1+ (1,0) [0|7] "" XXX
- SG_ ZEROS_3 : 45|3@1+ (1,0) [0|7] "" XXX
- SG_ ZEROS_4 : 48|3@1+ (1,0) [0|7] "" XXX
SG_ BCA_LEFT : 51|3@1+ (1,0) [0|7] "" XXX
SG_ BCA_RIGHT : 54|3@1+ (1,0) [0|7] "" XXX
SG_ LCA_LEFT_ARROW : 57|3@1+ (1,0) [0|7] "" XXX
SG_ LCA_RIGHT_ARROW : 60|3@1+ (1,0) [0|7] "" XXX
- SG_ ZEROS_5 : 63|1@0+ (1,0) [0|1] "" XXX
SG_ CENTERLINE : 64|2@1+ (1,0) [0|3] "" XXX
SG_ TARGET : 66|3@1+ (1,0) [0|7] "" XXX
SG_ TARGET_DISTANCE : 69|11@1+ (0.1,0) [0|204.7] "m" XXX
SG_ LANELINE_LEFT : 80|4@1+ (1,0) [0|15] "" XXX
SG_ LANELINE_LEFT_POSITION : 84|6@1+ (1,0) [0|15] "" XXX
SG_ LANELINE_RIGHT : 90|4@1+ (1,0) [0|15] "" XXX
- SG_ LANELINE_RIGHT_POSITION : 94|6@1+ (1,0) [0|3] "" XXX
- SG_ LANELINE_CURVATURE : 100|5@1- (1,15) [0|31] "" XXX
+ SG_ LANELINE_RIGHT_POSITION : 94|6@1+ (1,0) [0|15] "" XXX
+ SG_ LANELINE_CURVATURE : 100|4@1+ (1,0) [0|31] "" XXX
+ SG_ LANELINE_CURVATURE_DIRECTION : 104|1@0+ (1,0) [0|1] "" XXX
SG_ LANE_HIGHLIGHT : 105|4@1+ (1,0) [0|15] "" XXX
SG_ LANE_HIGHLIGHT_DISTANCE : 109|11@1+ (0.1,0) [0|204.7] "m" XXX
SG_ LANE_LEFT : 120|3@1+ (1,0) [0|7] "" XXX
SG_ LANE_RIGHT : 123|3@1+ (1,0) [0|7] "" XXX
SG_ LANE_ZOOM : 126|2@1+ (1,0) [0|3] "" XXX
SG_ ALERTS_1 : 128|6@1+ (1,0) [0|63] "" XXX
- SG_ ALERTS_2 : 134|5@1+ (1,0) [0|3] "" XXX
- SG_ ALERTS_3 : 139|5@1+ (1,0) [0|15] "" XXX
- SG_ ALERTS_4 : 144|8@1+ (1,0) [0|511] "" XXX
- SG_ ALERTS_5 : 152|5@1+ (1,0) [0|7] "" XXX
+ SG_ ALERTS_2 : 134|5@1+ (1,0) [0|31] "" XXX
+ SG_ ALERTS_3 : 139|5@1+ (1,0) [0|31] "" XXX
+ SG_ ALERTS_4 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ ALERTS_5 : 152|5@1+ (1,0) [0|31] "" XXX
SG_ MUTE : 157|3@1+ (1,0) [0|7] "" XXX
SG_ SOUNDS_1 : 160|4@1+ (1,0) [0|3] "" XXX
SG_ SOUNDS_2 : 164|4@1+ (1,0) [0|3] "" XXX
SG_ SOUNDS_3 : 168|4@1+ (1,0) [0|15] "" XXX
SG_ SOUNDS_4 : 172|3@1+ (1,0) [0|7] "" XXX
- SG_ ZEROS_6 : 175|1@0+ (1,0) [0|1] "" XXX
- SG_ ZEROS_7 : 176|5@1+ (1,0) [0|31] "" XXX
- SG_ SETSPEED_HUD : 181|3@1+ (1,0) [0|3] "" XXX
+ SG_ SETSPEED_HUD : 181|3@1+ (1,0) [0|7] "" XXX
SG_ DISTANCE_LEAD : 184|5@1+ (1,0) [0|31] "" XXX
SG_ DISTANCE_CAR : 189|3@1+ (1,0) [0|7] "" XXX
SG_ DISTANCE_SPACING : 192|4@1+ (1,0) [0|15] "" XXX
SG_ DISTANCE : 196|4@1+ (1,0) [0|7] "" XXX
- SG_ SETSPEED_SPEED : 200|8@1+ (1,0) [0|255] "" XXX
- SG_ SETSPEED : 208|4@1+ (1,0) [0|3] "" XXX
- SG_ HDA_ICON : 212|4@1+ (1,0) [0|3] "" XXX
+ SG_ vSetDis : 200|8@1+ (1,0) [0|255] "" XXX
+ SG_ SETSPEED : 208|4@1+ (1,0) [0|7] "" XXX
+ SG_ HDA_ICON : 212|3@1+ (1,0) [0|7] "" XXX
SG_ SLA_ICON : 216|4@1+ (1,0) [0|15] "" XXX
- SG_ NAV_ICON : 220|4@1+ (1,0) [0|3] "" XXX
- SG_ LFA_ICON : 224|4@1+ (1,0) [0|3] "" XXX
- SG_ LCA_LEFT_ICON : 228|4@1+ (1,0) [0|15] "" XXX
- SG_ LCA_RIGHT_ICON : 232|4@1+ (1,0) [0|15] "" XXX
+ SG_ NAV_ICON : 220|3@1+ (1,0) [0|7] "" XXX
+ SG_ LFA_ICON : 224|3@1+ (1,0) [0|7] "" XXX
+ SG_ LCA_LEFT_ICON : 228|3@1+ (1,0) [0|7] "" XXX
+ SG_ LCA_RIGHT_ICON : 232|3@1+ (1,0) [0|7] "" XXX
SG_ BACKGROUND : 236|4@1+ (1,0) [0|15] "" XXX
SG_ DAW_ICON : 240|3@1+ (1,0) [0|7] "" XXX
SG_ CAR_CIRCLE : 243|3@1+ (1,0) [0|7] "" XXX
- SG_ ZEROS_8 : 246|2@1+ (1,0) [0|3] "" XXX
- SG_ ZEROS_9 : 248|8@1+ (1,0) [0|255] "" XXX
BO_ 354 CCNC_0x162: 32 CCNC
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
@@ -232,35 +297,25 @@ BO_ 354 CCNC_0x162: 32 CCNC
SG_ SPEEDLIMIT : 32|8@1+ (1,0) [0|255] "" XXX
SG_ SIGNS : 40|8@1+ (1,0) [0|15] "" XXX
SG_ SPEEDLIMIT_WEATHER : 48|4@1+ (1,0) [0|15] "" XXX
- SG_ VIBRATE : 52|3@1+ (1,0) [0|7] "" XXX
- SG_ ZEROS_1 : 55|1@0+ (1,0) [0|1] "" XXX
- SG_ ZEROS_2 : 56|8@1+ (1,0) [0|255] "" XXX
- SG_ LEAD : 64|5@1+ (1,0) [0|31] "" XXX
- SG_ LEAD_DISTANCE : 69|11@1+ (0.1,0) [0|204.7] "m" XXX
- SG_ LEAD_LATERAL : 80|7@1+ (0.1,0) [0|127] "m" XXX
- SG_ ZEROS_3 : 87|1@0+ (1,0) [0|1] "" XXX
- SG_ LEAD_ALT : 88|5@1+ (1,0) [0|31] "" XXX
- SG_ LEAD_ALT_DISTANCE : 93|11@1+ (0.1,0) [0|204.7] "m" XXX
- SG_ LEAD_ALT_LATERAL : 104|7@1+ (0.1,0) [0|127] "m" XXX
- SG_ ZEROS_4 : 111|1@0+ (1,0) [0|1] "" XXX
- SG_ LEAD_LEFT : 112|5@1+ (1,0) [0|31] "" XXX
- SG_ LEAD_LEFT_DISTANCE : 117|11@1+ (0.1,0) [0|204.7] "m" XXX
- SG_ LEAD_LEFT_LATERAL : 128|7@1+ (0.1,0) [0|127] "m" XXX
- SG_ ZEROS_5 : 135|1@0+ (1,0) [0|1] "" XXX
- SG_ LEAD_RIGHT : 136|5@1+ (1,0) [0|31] "" XXX
- SG_ LEAD_RIGHT_DISTANCE : 141|11@1+ (0.1,0) [0|204.7] "m" XXX
- SG_ LEAD_RIGHT_LATERAL : 152|7@1+ (0.1,0) [0|127] "m" XXX
- SG_ ZEROS_6 : 159|1@0+ (1,0) [0|1] "" XXX
- SG_ ZEROS_7 : 162|3@0+ (1,0) [0|7] "" XXX
- SG_ LEAD_LEFT_REAR_STATUS : 167|5@0+ (1,0) [0|31] "" XXX
- SG_ LEAD_LEFT_REAR_DISTANCE : 175|8@0+ (0.1,0) [0|255] "m" XXX
- SG_ LEAD_LEFT_REAR_LATERAL : 182|7@0+ (0.1,0) [0|127] "m" XXX
- SG_ ZEROS_8 : 183|1@0+ (1,0) [0|1] "" XXX
- SG_ ZEROS_9 : 191|8@0+ (1,0) [0|255] "" XXX
- SG_ LEAD_RIGHT_REAR_STATUS : 196|5@0+ (1,0) [0|31] "" XXX
- SG_ LEAD_RIGHT_REAR_DISTANCE : 197|8@1+ (0.1,0) [0|255] "m" XXX
- SG_ LEAD_RIGHT_REAR_LATERAL : 205|7@1+ (0.1,0) [0|127] "m" XXX
- SG_ ZEROS_10 : 212|1@0+ (1,0) [0|1] "" XXX
+ SG_ VIBRATE : 52|1@0+ (1,0) [0|1] "" XXX
+ SG_ FF_DETECT : 64|5@1+ (1,0) [0|31] "" XXX
+ SG_ FF_DISTANCE : 69|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ FF_LATERAL : 80|7@1+ (0.1,0) [0|127] "m" XXX
+ SG_ FF_DETECT_ALT : 88|5@1+ (1,0) [0|31] "" XXX
+ SG_ FF_DISTANCE_ALT : 93|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ FF_LATERAL_ALT : 104|7@1+ (0.1,0) [0|127] "m" XXX
+ SG_ LF_DETECT : 112|5@1+ (1,0) [0|31] "" XXX
+ SG_ LF_DETECT_DISTANCE : 117|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LF_DETECT_LATERAL : 128|7@1+ (0.1,0) [0|127] "m" XXX
+ SG_ RF_DETECT : 136|5@1+ (1,0) [0|31] "" XXX
+ SG_ RF_DETECT_DISTANCE : 141|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ RF_DETECT_LATERAL : 152|7@1+ (0.1,0) [0|127] "m" XXX
+ SG_ LR_DETECT : 163|5@1+ (1,0) [0|31] "" XXX
+ SG_ LR_DETECT_DISTANCE : 175|8@0+ (0.1,0) [0|255] "" XXX
+ SG_ LR_DETECT_LATERAL : 176|7@1+ (0.1,0) [0|127] "" XXX
+ SG_ RR_DETECT : 192|5@1+ (1,0) [0|31] "" XXX
+ SG_ RR_DETECT_DISTANCE : 197|8@1+ (0.1,0) [0|255] "" XXX
+ SG_ RR_DETECT_LATERAL : 205|7@1+ (0.1,0) [0|127] "" XXX
SG_ FAULT_FSS : 213|3@1+ (1,0) [0|7] "" XXX
SG_ FAULT_FCA : 216|3@1+ (1,0) [0|7] "" XXX
SG_ FAULT_LSS : 219|3@1+ (1,0) [0|7] "" XXX
@@ -274,7 +329,6 @@ BO_ 354 CCNC_0x162: 32 CCNC
SG_ FAULT_HDP : 243|3@1+ (1,0) [0|7] "" XXX
SG_ FAULT_DAS : 246|3@1+ (1,0) [0|7] "" XXX
SG_ FAULT_ESS : 249|3@1+ (1,0) [0|7] "" XXX
- SG_ ZEROS_11 : 252|4@1+ (1,0) [0|15] "" XXX
BO_ 357 SPAS1: 24 APRK
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
@@ -291,56 +345,95 @@ BO_ 373 TCS: 24 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_4 : 24|7@1+ (1,0) [0|127] "" XXX
+ SG_ NEW_SIGNAL_9 : 31|1@0+ (1,0) [0|1] "" XXX
SG_ aBasis : 32|11@1+ (0.01,-10.23) [0|7] "m/s^2" XXX
+ SG_ NEW_SIGNAL_1 : 47|5@0+ (1,0) [0|31] "" XXX
SG_ ACCEL_REF_ACC : 48|11@1- (1,0) [0|1023] "" XXX
- SG_ EQUIP_MAYBE : 64|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_2 : 63|5@0+ (1,0) [0|31] "" XXX
+ SG_ SCC_OptTyp : 64|2@1+ (1,0) [0|0] "" AWD,EMS,FR_CMR,HCU,H_U_MM,TCU,VCU,vBDM
SG_ ACCEnable : 67|2@0+ (1,0) [0|3] "" XXX
SG_ ACC_REQ : 68|1@0+ (1,0) [0|1] "" XXX
- SG_ NEW_SIGNAL_5 : 72|1@0+ (1,0) [0|1] "" XXX
- SG_ NEW_SIGNAL_2 : 74|1@0+ (1,0) [0|1] "" XXX
- SG_ NEW_SIGNAL_3 : 76|1@0+ (1,0) [0|1] "" XXX
- SG_ NEW_SIGNAL_1 : 80|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_3 : 69|1@0+ (1,0) [0|1] "" XXX
+ SG_ SCC_ReqLimSta : 70|2@1+ (1,0) [0|0] "" ADAS_DRV,AWD,Dummy,EMS,FR_CMR,H_U_MM,TCU,vBDM
+ SG_ ESC_StdStillVal : 72|2@1+ (1,0) [0|3] "" ADAS_DRV,AWD,Dummy,EMS,FR_CMR,H_U_MM,TCU,vBDM
+ SG_ BrakeLight : 74|2@1+ (1,0) [0|3] "" XXX
+ SG_ ESC_DclEnblReq : 76|2@1+ (1,0) [0|3] "" AWD,Dummy,EMS,FR_CMR,H_U_MM,TCU,vBDM
+ SG_ NEW_SIGNAL_5 : 79|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 80|1@0+ (1,0) [0|1] "" XXX
SG_ DriverBraking : 81|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_20 : 82|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_11 : 83|1@0+ (1,0) [0|1] "" XXX
SG_ DriverBrakingLowSens : 84|1@1+ (1,0) [0|1] "" XXX
- SG_ AEB_EQUIP_MAYBE : 96|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_10 : 85|1@0+ (1,0) [0|1] "" XXX
+ SG_ ESC_PrkBrkActvSta : 86|2@1+ (1,0) [0|3] "" ADAS_DRV,AWD,Dummy,EMS,FR_CMR,H_U_MM,RR_C_RDR,TCU,vBDM
+ SG_ NEW_SIGNAL_12 : 95|8@0+ (1,0) [0|255] "" XXX
+ SG_ FCA_EquipSta : 96|2@1+ (1,0) [0|3] "" ADAS_DRV,FR_CMR,H_U_MM,vBDM
+ SG_ FCA_AvlblSta : 98|2@1+ (1,0) [0|3] "" ADAS_DRV,AFCU_DRV,CLU,Dummy,FR_CMR,H_U_MM,vBDM
+ SG_ NEW_SIGNAL_13 : 103|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 111|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 119|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_16 : 127|8@0+ (1,0) [0|255] "" XXX
SG_ NEW_SIGNAL_6 : 128|4@1+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_17 : 133|2@0+ (1,0) [0|3] "" XXX
SG_ NEW_SIGNAL_7 : 135|2@0+ (1,0) [0|3] "" XXX
SG_ PROBABLY_EQUIP : 136|2@1+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_18 : 143|6@0+ (1,0) [0|63] "" XXX
+ SG_ NEW_SIGNAL_19 : 151|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_8 : 183|16@0+ (1,0) [0|65535] "" XXX
+
+BO_ 384 CAM_0x180: 32 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 385 CAM_0x181: 32 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 386 CAM_0x182: 32 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 387 CAM_0x183: 32 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 388 CAM_0x184: 32 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 389 CAM_0x185: 8 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
BO_ 416 SCC_CONTROL: 32 ADRV
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ ACC_ObjDist : 24|11@1+ (0.1,0) [0|204.7] "m" XXX
- SG_ ACC_ObjRelSpd : 35|9@1+ (0.1,-16.4) [-16.4|34.7] "m/s" XXX
- SG_ SET_ME_3 : 45|2@0+ (1,0) [0|3] "" XXX
- SG_ ObjValid : 46|1@0+ (1,0) [0|3] "" XXX
- SG_ SET_ME_TMP_64 : 55|8@0+ (1,0) [0|63] "" XXX
+ SG_ ACC_ObjRelSpd : 35|12@1+ (0.1,-170) [-16.4|34.7] "m/s" XXX
+ SG_ ACC_ObjLatPos : 47|9@1- (0.1,-20) [0|511] "" XXX
SG_ ZEROS_7 : 63|8@0+ (1,0) [0|255] "" XXX
- SG_ NEW_SIGNAL_1 : 64|2@1+ (1,0) [0|3] "" XXX
+ SG_ SysFailState : 64|2@1+ (1,0) [0|3] "" XXX
SG_ MainMode_ACC : 66|1@1+ (1,0) [0|1] "" XXX
SG_ ACCMode : 68|3@1+ (1,0) [0|7] "" XXX
- SG_ ZEROS_9 : 71|5@1+ (1,0) [0|15] "" XXX
- SG_ CRUISE_STANDSTILL : 76|1@1+ (1,0) [0|1] "" XXX
- SG_ ZEROS_5 : 77|11@1+ (1,0) [0|2047] "" XXX
- SG_ DISTANCE_SETTING : 88|3@1+ (1,0) [0|3] "" XXX
- SG_ ZEROS_8 : 95|5@0+ (1,0) [0|31] "" XXX
+ SG_ TakeOverReq : 73|2@0+ (1,0) [0|3] "" XXX
+ SG_ InfoDisplay : 74|3@1+ (1,0) [0|7] "" XXX
+ SG_ DriverAlert : 77|2@1+ (1,0) [0|3] "" XXX
+ SG_ ObjDistLevel : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ DISTANCE_SETTING : 88|4@1+ (1,0) [0|15] "" XXX
SG_ VSetDis : 103|8@0+ (1,0) [0|255] "km/h or mph" XXX
- SG_ NEW_SIGNAL_6 : 104|1@0+ (1,0) [0|1] "" XXX
- SG_ SET_ME_2 : 105|3@1+ (1,0) [0|7] "" XXX
- SG_ SCC_ObjSta : 108|3@1+ (1,0) [0|7] "" CLU,CGW
- SG_ ZEROS_10 : 111|2@0+ (1,0) [0|3] "" XXX
- SG_ ZEROS_6 : 119|16@0+ (1,0) [0|65535] "" XXX
+ SG_ NSCCOper : 104|2@1+ (1,0) [0|3] "" XXX
+ SG_ NSCCOnOff : 106|2@1+ (1,0) [0|3] "" XXX
+ SG_ HUD_LEAD_INFO : 108|3@1+ (1,0) [0|7] "" XXX
+ SG_ DriveMode : 112|3@1+ (1,0) [0|7] "" XXX
SG_ aReqValue : 128|11@1+ (0.01,-10.23) [-10.23|10.24] "m/s^2" XXX
SG_ aReqRaw : 140|11@1+ (0.01,-10.23) [-10.23|10.24] "m/s^2" XXX
SG_ JerkUpperLimit : 158|7@0+ (0.1,0) [0|0] "" XXX
SG_ JerkLowerLimit : 166|7@0+ (0.1,0) [0|12.7] "m/s^3" XXX
- SG_ NEW_SIGNAL_2 : 168|2@1+ (1,0) [0|3] "" XXX
- SG_ NEW_SIGNAL_8 : 170|4@1+ (1,0) [0|15] "" XXX
- SG_ OBJ_STATUS : 176|3@1+ (1,0) [0|7] "" XXX
- SG_ ZEROS_4 : 183|4@0+ (1,0) [0|63] "" XXX
- SG_ StopReq : 184|1@0+ (1,0) [0|1] "" XXX
- SG_ ZEROS_3 : 191|7@0+ (1,0) [0|127] "" XXX
- SG_ NEW_SIGNAL_15 : 192|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ AccelLimitBandUpper : 173|6@0+ (0.02,0) [0|63] "" XXX
+ SG_ AccelLimitBandLower : 181|6@0+ (0.02,0) [0|63] "" XXX
+ SG_ StopReq : 185|2@0+ (1,0) [0|3] "" XXX
+ SG_ CRUSE_INFO_SET_2 : 189|2@0+ (1,0) [0|3] "" XXX
+ SG_ TARGET_DISTANCE : 192|11@1+ (0.1,0) [0|204.7] "m" XXX
SG_ ZEROS_2 : 207|5@0+ (1,0) [0|63] "" XXX
SG_ ZEROS : 215|48@0+ (1,0) [0|281474976710655] "" XXX
@@ -354,7 +447,7 @@ BO_ 426 CRUISE_BUTTONS_ALT: 16 XXX
SG_ ADAPTIVE_CRUISE_MAIN_BTN : 34|1@1+ (1,0) [0|1] "" XXX
SG_ NEW_SIGNAL_3 : 35|1@1+ (1,0) [0|1] "" XXX
SG_ CRUISE_BUTTONS : 36|3@1+ (1,0) [0|4] "" XXX
- SG_ LDA_BTN : 39|1@1+ (1,0) [0|1] "" XXX
+ SG_ LFA_BTN : 39|1@1+ (1,0) [0|1] "" XXX
SG_ NEW_SIGNAL_4 : 40|1@1+ (1,0) [0|1] "" XXX
SG_ NORMAL_CRUISE_MAIN_BTN : 41|1@1+ (1,0) [0|1] "" XXX
SG_ NEW_SIGNAL_5 : 42|2@1+ (1,0) [0|3] "" XXX
@@ -362,7 +455,7 @@ BO_ 426 CRUISE_BUTTONS_ALT: 16 XXX
SG_ NEW_SIGNAL_6 : 47|1@1+ (1,0) [0|1] "" XXX
SG_ BYTE6 : 48|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE7 : 56|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE8 : 64|8@1+ (1,0) [0|255] "" XXX
+ SG_ CLU_SPEED : 64|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE9 : 72|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE10 : 80|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE11 : 88|8@1+ (1,0) [0|255] "" XXX
@@ -371,38 +464,55 @@ BO_ 426 CRUISE_BUTTONS_ALT: 16 XXX
SG_ BYTE14 : 112|8@1+ (1,0) [0|255] "" XXX
SG_ BYTE15 : 120|8@1+ (1,0) [0|255] "" XXX
-BO_ 437 FR_CMR_03_50ms: 32 FR_CMR
- SG_ FR_CMR_Crc3Val : 0|16@1+ (1,0) [0|65535] "" RR_C_RDR,CGW
- SG_ FR_CMR_AlvCnt3Val : 16|8@1+ (1,0) [0|255] "" RR_C_RDR,CGW
- SG_ Info_LftLnQualSta : 24|3@1+ (1,0) [0|7] "" RR_C_RDR,CGW
- SG_ Info_LftLnDptSta : 27|2@1+ (1,0) [0|3] "" RR_C_RDR,CGW
- SG_ Info_LftLnPosVal : 29|14@1- (0.0039625,0) [-32.4608|32.4568375] "m" RR_C_RDR,CGW
- SG_ Info_LftLnHdingAnglVal : 43|10@1- (0.000976563,0) [-0.500000256|0.499023693] "rad" RR_C_RDR,CGW
- SG_ Info_LftLnCvtrVal : 64|16@1- (1e-06,0) [-0.032768|0.032767] "1/m" CGW
- SG_ Info_LftLnCrvtrDrvtvVal : 80|16@1- (4e-09,0) [-0.000131072|0.000131068] "1/m2" CGW
- SG_ Info_RtLnQualSta : 96|3@1+ (1,0) [0|7] "" RR_C_RDR,CGW
- SG_ Info_RtLnDptSta : 99|2@1+ (1,0) [0|3] "" RR_C_RDR,CGW
- SG_ Info_RtLnPosVal : 101|14@1- (0.0039625,0) [-32.4608|32.4568375] "m" RR_C_RDR,CGW
- SG_ Info_RtLnHdingAnglVal : 115|10@1- (0.000976563,0) [-0.500000256|0.499023693] "rad" RR_C_RDR,CGW
- SG_ Info_RtLnCvtrVal : 128|16@1- (1e-06,0) [-0.032768|0.032767] "1/m" CGW
- SG_ Info_RtLnCrvtrDrvtvVal : 144|16@1- (4e-09,0) [-0.000131072|0.000131068] "1/m2" CGW
- SG_ ID_CIPV : 192|8@1+ (1,0) [0|255] "" XXX
- SG_ Relative_Velocity : 200|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
- SG_ Longitudinal_Distance : 212|12@1+ (0.05,0) [0|204.75] "m" XXX
+BO_ 437 CCNC_0x1B5: 32 CCNC
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ LEFT_QUAL : 24|3@1+ (1,0) [0|7] "" XXX
+ SG_ LEFT_LDW : 27|2@1+ (1,0) [0|3] "" XXX
+ SG_ LEFT_POSITION : 29|14@1- (0.0039625,0) [-32.4608|32.4568375] "m" XXX
+ SG_ LEFT_HEADING : 43|10@1- (0.000976563,0) [-0.500000256|0.499023693] "rad" XXX
+ SG_ LEFT_CURVATURE : 64|16@1- (1e-06,0) [-0.032768|0.032767] "1/m" XXX
+ SG_ LEFT_CURVATURE_DERIVATIVE : 80|16@1- (4e-09,0) [-0.000131072|0.000131068] "1/m2" XXX
+ SG_ RIGHT_QUAL : 96|3@1+ (1,0) [0|7] "" XXX
+ SG_ RIGHT_LDW : 99|2@1+ (1,0) [0|3] "" XXX
+ SG_ RIGHT_POSITION : 101|14@1- (0.0039625,0) [-32.4608|32.4568375] "m" XXX
+ SG_ RIGHT_HEADING : 115|10@1- (0.000976563,0) [-0.500000256|0.499023693] "rad" XXX
+ SG_ RIGHT_CURVATURE : 128|16@1- (1e-06,0) [-0.032768|0.032767] "1/m" XXX
+ SG_ RIGHT_CURVATURE_DERIVATIVE : 144|16@1- (4e-09,0) [-0.000131072|0.000131068] "1/m2" XXX
+ SG_ LEAD : 192|7@1+ (1,0) [0|127] "" XXX
+ SG_ LEAD_SPEED : 200|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ LEAD_DISTANCE : 212|12@1+ (0.05,0) [0|204.75] "m" XXX
+
+BO_ 438 CAM_0x1b6: 32 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 439 CAM_0x1b7: 32 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 440 CAM_0x1b8: 32 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 441 CAM_0x1b9: 32 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
BO_ 442 BLINDSPOTS_REAR_CORNERS: 24 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ LEFT_BLOCKED : 24|1@0+ (1,0) [0|1] "" XXX
- SG_ LEFT_MB : 30|1@0+ (1,0) [0|3] "" XXX
- SG_ MORE_LEFT_PROB : 32|1@1+ (1,0) [0|3] "" XXX
+ SG_ INDICATOR_LEFT_TWO : 30|1@0+ (1,0) [0|3] "" XXX
+ SG_ INDICATOR_RIGHT_TWO : 32|1@1+ (1,0) [0|3] "" XXX
SG_ FL_INDICATOR : 46|6@0+ (1,0) [0|1] "" XXX
SG_ FR_INDICATOR : 54|6@0+ (1,0) [0|63] "" XXX
SG_ RIGHT_BLOCKED : 64|1@0+ (1,0) [0|1] "" XXX
SG_ COLLISION_AVOIDANCE_ACTIVE : 68|1@0+ (1,0) [0|1] "" XXX
- SG_ NEW_SIGNAL_2 : 96|1@0+ (1,0) [0|1] "" XXX
- SG_ FL_INDICATOR_ALT : 138|1@0+ (1,0) [0|1] "" XXX
- SG_ FR_INDICATOR_ALT : 141|1@0+ (1,0) [0|1] "" XXX
+ SG_ INDICATOR_LEFT_THREE : 128|1@0+ (1,0) [0|1] "" XXX
+ SG_ INDICATOR_RIGHT_THREE : 130|1@0+ (1,0) [0|1] "" XXX
+ SG_ INDICATOR_LEFT_FOUR : 138|1@0+ (1,0) [0|1] "" XXX
+ SG_ INDICATOR_RIGHT_FOUR : 141|1@0+ (1,0) [0|1] "" XXX
BO_ 463 CRUISE_BUTTONS: 8 XXX
SG_ _CHECKSUM : 0|8@1+ (1,0) [0|65535] "" XXX
@@ -410,10 +520,11 @@ BO_ 463 CRUISE_BUTTONS: 8 XXX
SG_ CRUISE_BUTTONS : 16|3@1+ (1,0) [0|3] "" XXX
SG_ ADAPTIVE_CRUISE_MAIN_BTN : 19|1@1+ (1,0) [0|1] "" XXX
SG_ NORMAL_CRUISE_MAIN_BTN : 21|1@1+ (1,0) [0|1] "" XXX
- SG_ LDA_BTN : 23|1@1+ (1,0) [0|1] "" XXX
+ SG_ LFA_BTN : 23|1@1+ (1,0) [0|1] "" XXX
SG_ RIGHT_PADDLE : 25|1@1+ (1,0) [0|1] "" XXX
SG_ LEFT_PADDLE : 27|1@1+ (1,0) [0|1] "" XXX
SG_ SET_ME_1 : 29|1@1+ (1,0) [0|1] "" XXX
+ SG_ SET_ME_1_ : 40|1@0+ (1,0) [0|1] "" XXX
BO_ 474 ADRV_0x1da: 32 ADRV
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
@@ -421,16 +532,20 @@ BO_ 474 ADRV_0x1da: 32 ADRV
SG_ SET_ME_22 : 31|8@0+ (1,0) [0|255] "" XXX
SG_ SET_ME_41 : 47|8@0+ (1,0) [0|255] "" XXX
-BO_ 480 LFAHDA_CLUSTER: 16 ADRV
+BO_ 480 LFAHDA_CLUSTER: 16 FR_CMR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
- SG_ NEW_SIGNAL_4 : 24|1@0+ (1,0) [0|1] "" XXX
- SG_ NEW_SIGNAL_5 : 25|1@0+ (1,0) [0|1] "" XXX
- SG_ NEW_SIGNAL_2 : 30|1@0+ (1,0) [0|1] "" XXX
- SG_ HDA_ICON : 31|1@1+ (1,0) [0|1] "" XXX
- SG_ NEW_SIGNAL_1 : 32|3@1+ (1,0) [0|7] "" XXX
- SG_ LFA_ICON : 47|2@1+ (1,0) [0|3] "" XXX
- SG_ NEW_SIGNAL_3 : 49|1@0+ (1,0) [0|1] "" XXX
+ SG_ HDA_OptUsmSta : 24|3@1+ (1,0) [0|0] "" CGW
+ SG_ LFA_OptUsmSta : 27|3@1+ (1,0) [0|0] "" CGW
+ SG_ HDA_CntrlModSta : 30|2@1+ (1,0) [0|0] "" CGW
+ SG_ HDA_InfoPUDis : 32|3@1+ (1,0) [0|0] "" CGW
+ SG_ HDA_AutoSetSpdSta : 35|2@1+ (1,0) [0|0] "" CGW
+ SG_ HDA_AutoSetSpdUpdtSta : 37|2@1+ (1,0) [0|0] "" CGW
+ SG_ HDA_AutoSetSpdVal : 39|8@1+ (1,0) [0|0] "km/h" CGW
+ SG_ HDA_LFA_SymSta : 47|2@1+ (1,0) [0|0] "" CGW
+ SG_ HDA_LFA_WrnSnd : 49|2@1+ (1,0) [0|0] "" Dummy
+ SG_ HDA_InfoPUDis1 : 51|3@1+ (1,0) [0|7] "" CLU,CGW
+ SG_ HDA_TDMRMDclReq : 54|2@1+ (1,0) [0|3] "" Dummy
BO_ 485 BLINDSPOTS_FRONT_CORNER_1: 16 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
@@ -448,61 +563,55 @@ BO_ 485 BLINDSPOTS_FRONT_CORNER_1: 16 XXX
BO_ 490 ADRV_0x1ea: 32 ADRV
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
- SG_ SET_ME_1C : 31|8@0+ (1,0) [0|255] "" XXX
- SG_ NEW_SIGNAL_1 : 32|2@1+ (1,0) [0|3] "" XXX
- SG_ NEW_SIGNAL_2 : 47|2@0+ (1,0) [0|3] "" XXX
- SG_ NEW_SIGNAL_3 : 55|8@0+ (1,0) [0|255] "" XXX
- SG_ NEW_SIGNAL_4 : 64|6@1+ (1,0) [0|31] "" XXX
- SG_ NEW_SIGNAL_5 : 72|2@1+ (1,0) [0|3] "" XXX
- SG_ NEW_SIGNAL_6 : 75|5@1+ (1,0) [0|31] "" XXX
- SG_ NEW_SIGNAL_7 : 80|5@1+ (1,0) [0|31] "" XXX
- SG_ NEW_SIGNAL_8 : 88|7@1+ (1,0) [0|127] "" XXX
- SG_ NEW_SIGNAL_9 : 96|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_4 : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_3 : 26|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_2 : 27|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_1 : 28|1@0+ (1,0) [0|1] "" XXX
+ SG_ LEFT_BLINK_HOLD : 29|1@0+ (1,0) [0|1] "" XXX
+ SG_ RIGHT_BLINK_HOLD : 30|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_5 : 31|1@0+ (1,0) [0|1] "" XXX
+ SG_ HDA_MODE2 : 32|3@1+ (1,0) [0|3] "" XXX
+ SG_ LANE_LEFT : 36|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_6 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ LANE_RIGHT : 41|2@0+ (1,0) [0|3] "" XXX
+ SG_ LANE_CHANGING : 45|3@0+ (1,0) [0|1] "" XXX
+ SG_ LF_DETECT_DISTANCE : 46|11@1+ (0.1,0) [0|2047] "" XXX
+ SG_ LF_DETECT_LATERAL : 70|7@0+ (0.1,0) [0|127] "" XXX
+ SG_ LF_DETECT : 74|3@0+ (1,0) [0|7] "" XXX
+ SG_ RF_DETECT_DISTANCE : 75|11@1+ (0.1,0) [0|2047] "" XXX
+ SG_ RF_DETECT_LATERAL : 94|7@0+ (0.1,0) [0|127] "" XXX
+ SG_ RF_DETECT : 98|3@0+ (1,0) [0|7] "" XXX
SG_ SET_ME_FF : 120|8@1+ (1,0) [0|255] "" XXX
- SG_ NEW_SIGNAL_10 : 143|5@0+ (1,0) [0|31] "" XXX
- SG_ NEW_SIGNAL_11 : 144|3@1+ (1,0) [0|7] "" XXX
- SG_ NEW_SIGNAL_12 : 152|6@1+ (1,0) [0|63] "" XXX
- SG_ NEW_SIGNAL_13 : 160|1@0+ (1,0) [0|1] "" XXX
- SG_ NEW_SIGNAL_14 : 163|5@1+ (1,0) [0|31] "" XXX
- SG_ NEW_SIGNAL_16 : 168|3@1+ (1,0) [0|7] "" XXX
- SG_ NEW_SIGNAL_15 : 175|4@0+ (1,0) [0|63] "" XXX
- SG_ NEW_SIGNAL_17 : 176|2@1+ (1,0) [0|3] "" XXX
- SG_ NEW_SIGNAL_18 : 184|1@0+ (1,0) [0|1] "" XXX
- SG_ NEW_SIGNAL_19 : 208|3@1+ (1,0) [0|7] "" XXX
- SG_ NEW_SIGNAL_20 : 212|1@0+ (1,0) [0|1] "" XXX
- SG_ SET_ME_TMP_F : 232|5@1+ (1,0) [0|31] "" XXX
- SG_ SET_ME_TMP_F_2 : 240|5@1+ (1,0) [0|31] "" XXX
+ SG_ LR_DETECT_DISTANCE : 139|8@1+ (0.1,0) [0|511] "m" XXX
+ SG_ LR_DETECT_LATERAL : 152|6@1+ (0.1,0) [0|63] "" XXX
+ SG_ LR_DETECT : 162|3@0+ (1,0) [0|1] "" XXX
+ SG_ RR_DETECT_DISTANCE : 163|8@1+ (0.1,0) [0|511] "m" XXX
+ SG_ RR_DETECT_LATERAL : 172|6@1+ (0.1,0) [0|63] "" XXX
+ SG_ RR_DETECT : 186|3@0+ (1,0) [0|1] "" XXX
+ SG_ AUTOLANECHANGE_MSG : 207|4@0+ (1,0) [0|3] "" XXX
+ SG_ LANELINE_CURVATURE : 208|4@1+ (1,0) [0|31] "" XXX
+ SG_ LANELINE_CURVATURE_DIRECTION : 212|1@0+ (1,0) [0|1] "" XXX
+ SG_ LANELINE_LEFT_POSITION : 239|8@0+ (1,0) [0|255] "" XXX
+ SG_ LANELINE_RIGHT_POSITION : 247|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 248|1@0+ (1,0) [0|1] "" XXX
-BO_ 506 FR_CMR_02_100ms: 32 FR_CMR
- SG_ FR_CMR_Crc2Val : 0|16@1+ (1,0) [0|65535] "" CGW
- SG_ FR_CMR_AlvCnt2Val : 16|8@1+ (1,0) [0|255] "" CGW
- SG_ ISLW_OptUsmSta : 24|2@1+ (1,0) [0|3] "" CLU,CGW
- SG_ ISLW_SysSta : 26|2@1+ (1,0) [0|3] "" CLU,CGW
- SG_ ISLW_NoPassingInfoDis : 28|3@1+ (1,0) [0|7] "" CLU,CGW
- SG_ ISLW_OvrlpSignDis : 31|2@1+ (1,0) [0|3] "" CLU,CGW
- SG_ ISLW_SpdCluMainDis : 33|8@1+ (1,0) [0|255] "" CLU,CGW
- SG_ ISLW_SpdNaviMainDis : 41|8@1+ (1,0) [0|255] "" CGW
- SG_ ISLW_SubCondinfoSta1 : 49|4@1+ (1,0) [0|15] "" CLU,CGW
- SG_ ISLW_SubCondinfoSta2 : 53|4@1+ (1,0) [0|15] "" CLU,CGW
- SG_ ISLW_SpdCluSubMainDis : 64|8@1+ (1,0) [0|255] "" CLU
- SG_ ISLW_SpdCluDisSubCond1 : 72|8@1+ (1,0) [0|255] "" CLU,CGW
- SG_ ISLW_SpdCluDisSubCond2 : 80|8@1+ (1,0) [0|255] "" CLU,CGW
- SG_ ISLW_SpdNaviSubMainDis : 88|8@1+ (1,0) [0|255] "" CLU
- SG_ ISLW_SpdNaviDisSubCond1 : 96|8@1+ (1,0) [0|255] "" CLU,CGW
- SG_ ISLW_SpdNaviDisSubCond2 : 104|8@1+ (1,0) [0|255] "" CLU,CGW
- SG_ ISLA_SpdwOffst : 112|8@1+ (1,0) [0|255] "" CLU,CGW
- SG_ ISLA_SwIgnoreReq : 120|2@1+ (1,0) [0|3] "" CGW
- SG_ ISLA_SpdChgReq : 122|2@1+ (1,0) [0|3] "" CGW
- SG_ ISLA_SpdWrn : 124|2@1+ (1,0) [0|3] "" CLU,CGW
- SG_ ISLA_IcyWrn : 126|2@1+ (1,0) [0|3] "" CLU,CGW
- SG_ ISLA_SymFlashMod : 128|3@1+ (1,0) [0|7] "" CLU,CGW
- SG_ ISLA_Popup : 131|3@1+ (1,0) [0|7] "" CLU
- SG_ ISLA_OptUsmSta : 136|3@1+ (1,0) [0|7] "" CLU,CGW
- SG_ ISLA_OffstUsmSta : 139|3@1+ (1,0) [0|7] "" CLU,CGW
- SG_ ISLA_AutoUsmSta : 142|2@1+ (1,0) [0|3] "" CLU,CGW
- SG_ ISLA_Cntry : 144|4@1+ (1,0) [0|15] "" CLU,CGW
- SG_ ISLA_AddtnlSign : 149|5@1+ (1,0) [0|31] "" CLU,CGW
- SG_ ISLA_SchoolZone : 154|2@1+ (1,0) [0|3] "" CLU,CGW
+BO_ 506 CLUSTER_SPEED_LIMIT: 32 CAM
+ SG_ SPEED_LIMIT_1 : 39|7@0+ (1,0) [0|255] "" XXX
+ SG_ SPEED_LIMIT_2 : 47|7@0+ (1,0) [0|255] "" XXX
+ SG_ SECONDARY_LIMIT_1 : 79|8@0+ (1,0) [0|127] "" XXX
+ SG_ SECONDARY_LIMIT_2 : 103|8@0+ (1,0) [0|127] "" XXX
+ SG_ SPEED_LIMIT_3 : 119|8@0+ (1,0) [0|255] "" XXX
+ SG_ ARROW_DOWN : 120|1@0+ (1,0) [0|1] "" XXX
+ SG_ ARROW_UP : 121|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_2 : 122|3@1+ (1,0) [0|7] "" XXX
+ SG_ SPEED_CHANGE_BLINKING : 129|1@1+ (1,0) [0|3] "" XXX
+ SG_ CHIME_1 : 133|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_4 : 143|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_3 : 146|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_1 : 147|7@1+ (1,0) [0|127] "" XXX
+ SG_ SCHOOL_ZONE : 155|1@0+ (1,0) [0|1] "" XXX
+ SG_ SPEED_LIMIT_4 : 215|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_5 : 223|8@0+ (1,0) [0|255] "" XXX
BO_ 507 CAM_0x1fb: 32 CAMERA
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
@@ -512,54 +621,158 @@ BO_ 512 ADRV_0x200: 8 ADRV
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
SG_ SET_ME_E1 : 24|8@1+ (1,0) [0|255] "" XXX
- SG_ SET_ME_3A : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ TauGapSet : 32|3@1+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_2 : 35|2@1+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_1 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ TauGapSet_ : 42|3@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_3 : 47|5@0+ (1,0) [0|31] "" XXX
+
+BO_ 513 RADAR_0x201: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 528 RADAR_0x210: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 529 RADAR_0x211: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 530 RADAR_0x212: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 531 RADAR_0x213: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 532 RADAR_0x214: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 533 RADAR_0x215: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 534 RADAR_0x216: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 535 RADAR_0x217: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 536 RADAR_0x218: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 537 RADAR_0x219: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 538 RADAR_0x21a: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 539 RADAR_0x21b: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 540 RADAR_0x21c: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 541 RADAR_0x21d: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 542 RADAR_0x21e: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 543 RADAR_0x21f: 32 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 560 HCU_STATUS_230: 32 XXX
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HYBRID_POWER_FLOW_MODE : 170|4@1+ (1,0) [0|15] "" XXX
+
+CM_ BO_ 560 "Hyundai/Kia CAN-FD hybrid power-flow status observed on ECAN at 10 Hz; ACAN 0x230/DLC16 is an unrelated radar frame.";
+CM_ SG_ 560 HYBRID_POWER_FLOW_MODE "Reverse-engineered enum; observed values 1, 2, and 6 correspond to the OEM EV indicator being on.";
+
+BO_ 576 RADAR_0x240: 16 FRONT_RADAR
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
BO_ 593 RADAR_0x251: 16 FRONT_RADAR
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
-BO_ 687 HOD_FD_01_100ms: 8 XXX
- SG_ HOD_Dir_Status : 18|3@0+ (1,0) [0|7] "" XXX
- SG_ NEW_SIGNAL_2 : 32|8@1+ (1,0) [0|255] "" XXX
- SG_ NEW_SIGNAL_3 : 40|8@1+ (1,0) [0|255] "" XXX
- SG_ HOD_Option : 48|2@1+ (1,0) [0|255] "" XXX
+BO_ 674 CAM_0x2a2: 32 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
-BO_ 698 FR_CMR_04_40ms: 32 FR_CMR
- SG_ FR_CMR_Crc4Val : 0|16@1+ (1,0) [0|65535] "" Dummy
- SG_ FR_CMR_AlvCnt4Val : 16|8@1+ (1,0) [0|255] "" Dummy
- SG_ IFSref_FR_CMR_Sta : 24|2@1+ (1,0) [0|3] "" CGW
- SG_ IFSref_VehNumVal : 26|4@1+ (1,0) [0|15] "" CGW
- SG_ IFSref_ILLAmbtSta : 30|2@1+ (0.1,0) [0|0.3] "" CGW
- SG_ IFSref_VehLftAngl1Val : 32|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehRtAngl1Val : 41|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehLftAngl2Val : 50|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehDst1Val : 59|4@1+ (1,0) [0|15] "" CGW
- SG_ IFSref_VehRtAngl2Val : 64|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehLftAngl3Val : 73|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehRtAngl3Val : 82|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehLftAngl4Val : 91|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehRtAngl4Val : 100|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehLftAngl5Val : 109|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehRtAngl5Val : 118|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehLftAngl6Val : 128|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehRtAngl6Val : 137|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehLftAngl7Val : 146|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehRtAngl7Val : 155|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehLftAngl8Val : 164|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehRtAngl8Val : 173|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehLftAngl9Val : 182|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehRtAngl9Val : 192|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehLftAngl10Val : 201|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehRtAngl10Val : 210|9@1+ (0.1,-25) [-25|26.1] "Deg" CGW
- SG_ IFSref_VehDst2Val : 219|4@1+ (1,0) [0|15] "" CGW
- SG_ IFSref_VehDst3Val : 223|4@1+ (1,0) [0|15] "" CGW
- SG_ IFSref_VehDst4Val : 227|4@1+ (1,0) [0|15] "" CGW
- SG_ IFSref_VehDst5Val : 231|4@1+ (1,0) [0|15] "" CGW
- SG_ IFSref_VehDst6Val : 235|4@1+ (1,0) [0|15] "" CGW
- SG_ IFSref_VehDst7Val : 239|4@1+ (1,0) [0|15] "" CGW
- SG_ IFSref_VehDst8Val : 243|4@1+ (1,0) [0|15] "" CGW
- SG_ IFSref_VehDst9Val : 247|4@1+ (1,0) [0|15] "" CGW
- SG_ IFSref_VehDst10Val : 251|4@1+ (1,0) [0|15] "" CGW
+BO_ 675 CAM_0x2a3: 32 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 676 CAM_0x2a4: 24 XXX
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ LEFT_LANE_PROB : 31|8@0+ (1,0) [0|255] "" XXX
+ SG_ RIGHT_LANE_PROB : 39|8@0+ (1,0) [0|255] "" XXX
+ SG_ LEFT_LANE_TYPE : 43|4@0+ (1,0) [0|15] "" XXX
+ SG_ RIGHT_LANE_TYPE : 47|4@0+ (1,0) [0|15] "" XXX
+ SG_ LEFT_LANE_COLOR : 48|4@1+ (1,0) [0|15] "" XXX
+ SG_ RIGHT_LANE_COLOR : 52|4@1+ (1,0) [0|15] "" XXX
+ SG_ LEFT_LANE_LINE : 56|2@1+ (1,0) [0|3] "" XXX
+ SG_ SET_ME_0 : 58|2@1+ (1,0) [0|3] "" XXX
+ SG_ RIGHT_LANE_LINE : 60|2@1+ (1,0) [0|3] "" XXX
+ SG_ SET_ME_0_2 : 62|2@1+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_2 : 67|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_1 : 71|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_4 : 75|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_3 : 79|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 80|10@1- (1,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_6 : 96|10@1- (1,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_7 : 112|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_8 : 128|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_9 : 144|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_10 : 160|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_11 : 176|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_12 : 192|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_13 : 208|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_14 : 224|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_15 : 240|16@1+ (1,0) [0|65535] "" XXX
+
+BO_ 687 STEER_TOUCH_2AF: 8 XXX
+ SG_ CHECKSUM_ : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ COUNTER_ : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ TOUCH_DETECT : 23|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_2 : 31|8@0+ (1,0) [0|255] "" XXX
+ SG_ TOUCH1 : 39|8@0+ (1,0) [0|255] "" XXX
+ SG_ TOUCH2 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_3 : 55|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_4 : 63|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 699 CAM_0x2bb: 32 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 700 CAM_0x2bc: 32 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 701 CAM_0x2bd: 32 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+
+BO_ 702 CAM_0x2be: 32 CAMERA
+ SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
+ SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
BO_ 736 MANUAL_SPEED_LIMIT_ASSIST: 32 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
@@ -577,42 +790,45 @@ BO_ 837 ADRV_0x345: 8 ADRV
BO_ 866 CAM_0x362: 32 CAMERA
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE3 : 24|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE4 : 32|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE5 : 40|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE6 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ LEFT_LANE_PROB : 31|8@0+ (1,0) [0|255] "" XXX
+ SG_ RIGHT_LANE_PROB : 39|8@0+ (1,0) [0|255] "" XXX
+ SG_ LEFT_LANE_TYPE : 43|4@0+ (1,0) [0|15] "" XXX
+ SG_ RIGHT_LANE_TYPE : 47|4@0+ (1,0) [0|15] "" XXX
+ SG_ LEFT_LANE_COLOR : 48|4@1+ (1,0) [0|15] "" XXX
+ SG_ RIGHT_LANE_COLOR : 52|4@1+ (1,0) [0|15] "" XXX
SG_ LEFT_LANE_LINE : 56|2@1+ (1,0) [0|3] "" XXX
SG_ SET_ME_0 : 58|2@1+ (1,0) [0|3] "" XXX
SG_ RIGHT_LANE_LINE : 60|2@1+ (1,0) [0|3] "" XXX
SG_ SET_ME_0_2 : 62|2@1+ (1,0) [0|3] "" XXX
- SG_ BYTE8 : 64|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE9 : 72|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE10 : 80|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE11 : 88|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE12 : 96|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE13 : 104|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE14 : 112|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE15 : 120|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE16 : 128|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE17 : 136|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE18 : 144|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE19 : 152|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE20 : 160|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE21 : 168|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE22 : 176|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE23 : 184|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE24 : 192|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE25 : 200|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE26 : 208|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE27 : 216|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE28 : 224|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE29 : 232|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE30 : 240|8@1+ (1,0) [0|255] "" XXX
- SG_ BYTE31 : 248|8@1+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_2 : 67|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_1 : 71|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_4 : 75|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_3 : 79|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 80|10@1- (1,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_6 : 96|10@1- (1,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_7 : 112|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_8 : 128|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_9 : 144|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_10 : 160|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_11 : 176|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_12 : 192|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_13 : 208|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_14 : 224|16@1+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_15 : 240|16@1+ (1,0) [0|65535] "" XXX
BO_ 874 BLINDSPOTS_FRONT_CORNER_2: 16 XXX
SG_ CHECKSUM : 0|16@1+ (1,0) [0|65535] "" XXX
SG_ COUNTER : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ RIGHT_BSD : 27|1@0+ (1,0) [0|1] "" XXX
+ SG_ LEFT_BSD : 28|1@0+ (1,0) [0|1] "" XXX
+
+BO_ 928 TPMS: 16 XXX
+ SG_ PRESSURE_FL : 39|8@0+ (1,0) [0|255] "" XXX
+ SG_ PRESSURE_FR : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ PRESSURE_RL : 55|8@0+ (1,0) [0|255] "" XXX
+ SG_ PRESSURE_RR : 63|8@0+ (1,0) [0|255] "" XXX
+ SG_ STATUS_TPMS : 66|3@0+ (1,0) [0|3] "" XXX
+ SG_ UNIT : 68|2@0+ (1,0) [0|3] "" XXX
BO_ 961 BLINKER_STALKS: 8 XXX
SG_ CHECKSUM_MAYBE : 7|8@0+ (1,0) [0|255] "" XXX
@@ -623,6 +839,16 @@ BO_ 961 BLINKER_STALKS: 8 XXX
SG_ LEFT_BLINKER : 30|1@0+ (1,0) [0|1] "" XXX
SG_ RIGHT_BLINKER : 32|1@0+ (1,0) [0|1] "" XXX
+BO_ 995 BLINKERS_ALT: 16 XXX
+ SG_ LEFT_BLINKER : 74|1@0+ (1,0) [0|1] "" XXX
+ SG_ RIGHT_BLINKER : 76|1@0+ (1,0) [0|1] "" XXX
+ SG_ LEFT_LAMP_ALT : 89|1@0+ (1,0) [0|1] "" XXX
+ SG_ LEFT_LAMP : 90|1@0+ (1,0) [0|1] "" XXX
+ SG_ RIGHT_LAMP_ALT : 91|1@0+ (1,0) [0|1] "" XXX
+ SG_ RIGHT_LAMP : 92|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_2 : 95|1@0+ (1,0) [0|1] "" XXX
+ SG_ BLINKER_ACTIVE : 97|1@0+ (1,0) [0|1] "" XXX
+
BO_ 1041 DOORS_SEATBELTS: 8 XXX
SG_ CHECKSUM_MAYBE : 7|8@0+ (1,0) [0|65535] "" XXX
SG_ COUNTER_ALT : 15|4@0+ (1,0) [0|15] "" XXX
@@ -643,6 +869,12 @@ BO_ 1043 BLINKERS: 8 XXX
SG_ RIGHT_LAMP_ALT : 61|1@0+ (1,0) [0|1] "" XXX
SG_ USE_ALT_LAMP : 62|1@0+ (1,0) [0|1] "" XXX
+BO_ 1052 LIGHT_SENSOR: 8 XXX
+ SG_ CHECKSUM_MAYBE : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ COUNTER_ALT : 15|4@0+ (1,0) [0|15] "" XXX
+ SG_ IS_DARK : 19|1@0+ (1,0) [0|1] "" XXX
+ SG_ LIGHT_LEVEL : 24|10@1+ (1,0) [0|1023] "" XXX
+
BO_ 1144 DRIVE_MODE: 8 XXX
SG_ DRIVE_MODE : 0|16@1+ (1,-61611) [0|61611] "" XXX
SG_ DRIVE_MODE2 : 28|3@1+ (1,0) [1|3] "" XXX
@@ -660,6 +892,47 @@ BO_ 1151 HVAC_TOUCH_BUTTONS: 8 XXX
SG_ RECIRC_BUTTON : 48|1@0+ (1,0) [0|1] "" XXX
SG_ HEAT_BUTTON : 52|1@0+ (1,0) [0|1] "" XXX
+BO_ 1187 HDA_INFO_4A3: 8 XXX
+ SG_ LinkClass : 0|3@1+ (1,0) [0|7] "" XXX
+ SG_ Frwinfo : 3|3@1+ (1,0) [0|7] "" XXX
+ SG_ SpeedUnit : 6|2@1+ (1,0) [0|3] "" XXX
+ SG_ SPEED_LIMIT : 15|8@0+ (1,0) [0|255] "" XXX
+ SG_ CountryCode : 16|10@1+ (1,0) [0|1023] "" XXX
+ SG_ MapSource : 27|3@1+ (1,0) [0|7] "" XXX
+ SG_ TollExist : 30|2@1+ (1,0) [0|3] "" XXX
+ SG_ TunnelExist : 38|2@1+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_6 : 47|24@0+ (1,0) [0|16777215] "" XXX
+
+BO_ 1204 NEW_MSG_4B4: 8 XXX
+ SG_ NEW_SIGNAL_1 : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_8 : 15|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_2 : 23|16@0+ (1,0) [0|65535] "" XXX
+ SG_ NEW_SIGNAL_7 : 35|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_3 : 39|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_4 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_5 : 55|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_6 : 63|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 1209 NEW_MSG_4B9: 8 XXX
+ SG_ BYTE_1 : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ BYTE_2 : 15|8@0+ (1,0) [0|255] "" XXX
+ SG_ BYTE_3 : 23|8@0+ (1,0) [0|255] "" XXX
+ SG_ BYTE_4 : 31|8@0+ (1,0) [0|255] "" XXX
+ SG_ BYTE_5 : 39|8@0+ (1,0) [0|255] "" XXX
+ SG_ BYTE_6 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ BYTE_7 : 55|8@0+ (1,0) [0|255] "" XXX
+ SG_ BYTE_8 : 63|8@0+ (1,0) [0|255] "" XXX
+
+BO_ 1214 NEW_MSG_4BE: 8 XXX
+ SG_ BYTE_1 : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ BYTE_2 : 15|8@0+ (1,0) [0|255] "" XXX
+ SG_ BYTE_3 : 23|8@0+ (1,0) [0|255] "" XXX
+ SG_ BYTE_4 : 31|8@0+ (1,0) [0|255] "" XXX
+ SG_ BYTE_5 : 39|8@0+ (1,0) [0|255] "" XXX
+ SG_ BYTE_6 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ BYTE_7 : 55|8@0+ (1,0) [0|255] "" XXX
+ SG_ BYTE_8 : 63|8@0+ (1,0) [0|255] "" XXX
+
BO_ 1240 CLUSTER_INFO: 8 XXX
SG_ DISTANCE_UNIT : 0|1@1+ (1,0) [0|1] "" XXX
@@ -673,166 +946,41 @@ BO_ 1264 LOCAL_TIME: 8 XXX
SG_ HOURS : 12|5@0+ (1,0) [0|31] "" XXX
SG_ MINUTES : 21|6@0+ (1,0) [0|63] "" XXX
SG_ SECONDS : 31|8@0+ (1,0) [0|59] "" XXX
+ SG_ MONTH : 37|4@0+ (1,0) [0|15] "" XXX
+ SG_ YEAR : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ DATE : 48|5@1+ (1,0) [0|31] "" XXX
+CM_ SG_ 80 HAS_LANE_SAFETY "If 0, hides LKAS 'Lane Safety' menu from vehicle settings";
CM_ SG_ 96 BRAKE_PRESSURE "User applied brake pedal pressure. Ramps from computer applied pressure on falling edge of cruise. Cruise cancels if !=0";
CM_ SG_ 101 BRAKE_POSITION "User applied brake pedal position, max is ~700. Signed on some vehicles";
-CM_ SG_ 203 ADAS_ActvACISta "ADAS Active AngleControlInterface State";
-CM_ SG_ 203 ADAS_ActvACILvl2Sta "ADAS Active AngleControlInterface Level 2 State";
-CM_ SG_ 203 ADAS_StrAnglReqVal "(LFA) ADAS Steering Angle Request Value; Capped at 119.9;";
-CM_ SG_ 203 ADAS_ACIAnglTqRedcGainVal "(LFA) ADAS AngleControlInterface Angle Torque Reduction Gain Value";
-CM_ SG_ 203 FCA_ESA_ActvSta "FCA_ESA Active State";
-CM_ SG_ 203 FCA_ESA_TqBstGainVal "FCA_ESA Torque Boost Gain Value";
-CM_ BO_ 272 "Alternative LKAS message, used on cars such as 2023 Ioniq 6, 2nd gen Kona. Matches LKAS except size is 32 bytes";
-CM_ SG_ 272 LKA_AVAILABLE "Angle control cars: 3 when LKA is generally available, goes to 0 during changes with LFA";
-CM_ SG_ 272 ADAS_StrAnglReqVal "(LKAS) ADAS Steering Angle Request Value; Capped at 176.7; tracks MDPS->STEERING_ANGLE when not engaged, not STEERING_SENSORS->STEERING_ANGLE";
-CM_ SG_ 272 ADAS_ACIAnglTqRedcGainVal "(LKAS) ADAS AngleControlInterface Angle Torque Reduction Gain Value";
-CM_ BO_ 282 "Sent by the camera containing DAW (Driver Attention Warning) information and information about HBA (High Beam Assist).";
-CM_ SG_ 282 FR_CMR_Crc1Val "The data area for CRC calculation is based on the data length (DLC) of the message DB. The CRC shall be calculated over the entire data block (excluding the CRC bytes) including the user data, alive counter and Data ID - CRC Polynomial (0x1021) , In";
-CM_ SG_ 282 FR_CMR_AlvCnt1Val "For the first transmission request for a data element the counter shall be initialized with 0 and shall be incremented by 1 for every subsequent send request. When the counter reaches the maximum value(0xFF), then it shall restart with 0 for the next s";
-CM_ SG_ 282 HBA_SysOptSta "HBA System Option Information to Lamp Controller";
-CM_ SG_ 282 HBA_SysSta "This signal indicates the status of High Beam Assist system.";
-CM_ SG_ 282 HBA_IndLmpReq "HBA System Indicator Lamp Status";
-CM_ SG_ 282 FCA_Equip_MFC "FCA Sensor Type";
-CM_ SG_ 282 HBA_OptUsmSta "HBA Option USM Status";
-CM_ SG_ 282 DAW_LVDA_PUDis "Message for displaying LVDA(Leading Vehicle Departure Alert) Warning";
-CM_ SG_ 282 DAW_LVDA_OptUsmSta "LVDA USM state";
-CM_ SG_ 282 DAW_OptUsmSta "This signal represents the lastest DAW ON/OFF value of USM.";
-CM_ SG_ 282 DAW_SysSta "This signal represents Attention Assist System Status or Attention Level.";
-CM_ SG_ 282 DAW_WrnMsgSta "0x1 value requests DAW Rest recommend warning message popup at CLU. 0x2 value requests HDA/LFA Hands-Off call at TMS.";
-CM_ SG_ 282 DAW_TimeRstReq "This signal requests CLU 'Last Break Time' Reset. DAW send '0x1' when detecting driver's rest.";
-CM_ SG_ 282 DAW_SnstvtyModRetVal "This signal represents the feedback value of the current ADAS warning timing.";
-CM_ SG_ 282 FR_CMR_SCCEquipSta "This signal indicates equipment for SCC";
-CM_ SG_ 282 FR_CMR_ReqADASMapMsgVal "This signal indicates an ADAS map message request from FR_CMR to H_U. Each bit indicates the request messages as follows. - Bit 0 : H_U_NAVI_V2_STUB_E - Bit 1 : HU_NAVI_V2_PROSHORT_E_00 (곡률) - Bit 2 : HU_NAVI_V2_PROSHORT_E_00 (곡률 외 정보)";
-CM_ SG_ 282 FR_CMR_SwVer1Val "This signal indicates a major version of FR_CMR software. If FR_CMR software version is A.00, 'A' and '00' mean major and minor version respectively.";
-CM_ SG_ 282 FR_CMR_SwVer2Val "This signal indicates a minor version of FR_CMR software. If FR_CMR software version is A.00, 'A' and '00' mean major and minor version respectively.";
-CM_ SG_ 298 NEW_SIGNAL_4 "todo: figure out why always set to 9";
+CM_ SG_ 272 LKAS_ANGLE_CMD "tracks MDPS->STEERING_ANGLE when not engaged, not STEERING_SENSORS->STEERING_ANGLE";
CM_ SG_ 352 SET_ME_9 "has something to do with AEB settings";
CM_ SG_ 373 ACCEnable "Likely a copy of CAN's TCS13->ACCEnable";
CM_ SG_ 373 DriverBraking "Likely derived from BRAKE->BRAKE_POSITION";
CM_ SG_ 373 DriverBrakingLowSens "Higher threshold version of DriverBraking";
CM_ SG_ 373 PROBABLY_EQUIP "aeb equip?";
CM_ SG_ 416 VSetDis "set speed in display units";
-CM_ BO_ 437 "Sent by the camera containing lane and lead information.";
-CM_ SG_ 437 FR_CMR_Crc3Val "The data area for CRC calculation is based on the data length (DLC) of the message DB. The CRC shall be calculated over the entire data block (excluding the CRC bytes) including the user data, alive counter and Data ID - CRC Polynomial (0x1021) , In";
-CM_ SG_ 437 FR_CMR_AlvCnt3Val "For the first transmission request for a data element the counter shall be initialized with 0 and shall be incremented by 1 for every subsequent send request. When the counter reaches the maximum value(0xFF), then it shall restart with 0 for the next s";
-CM_ SG_ 437 Info_LftLnQualSta "This signal indicates the quality of left line.";
-CM_ SG_ 437 Info_LftLnDptSta "This signal indicates the lane departure status of left line.";
-CM_ SG_ 437 Info_LftLnPosVal "This signal outputs the position of left line from camera center.";
-CM_ SG_ 437 Info_LftLnHdingAnglVal "This signal outputs the heading angle of left line.";
-CM_ SG_ 437 Info_LftLnCvtrVal "This signal outputs the curvature of left line.";
-CM_ SG_ 437 Info_RtLnQualSta "This signal indicates the quality of right line.";
-CM_ SG_ 437 Info_RtLnDptSta "This signal indicates the lane departure status of right line.";
-CM_ SG_ 437 Info_RtLnPosVal "This signal outputs the position of right line from camera center.";
-CM_ SG_ 437 Info_RtLnHdingAnglVal "This signal outputs the heading angle of right line.";
-CM_ SG_ 437 Info_RtLnCvtrVal "This signal outputs the curvature of right line.";
-CM_ SG_ 437 ID_CIPV "Valid Object = 1 to 255 - ID detected by front camera can vary depending on vehicle environment. - Additional logic would be required to apply this signal for ISG.";
-CM_ SG_ 437 Relative_Velocity "+ : Preceding, - : Oncoming - Velocity detected by front camera can vary depending on vehicle environment. - Additional logic would be required to apply this signal for ISG. - Confirmaiton by Autonomous Driving Engineering Team is required to use ID_C";
-CM_ SG_ 416 SCC_ObjSta "state of in-path object and information of controllable state.";
-CM_ SG_ 480 NEW_SIGNAL_5 "todo: figure out why always set to 1";
-CM_ BO_ 506 "Sent by the camera containing speed limit information. ISLW stands for Intelligent Speed Limit Warning, and ISLA is Intelligent Speed Limit Assist. it also contains road sign information.";
-CM_ SG_ 506 FR_CMR_Crc2Val "The data area for CRC calculation is based on the data length (DLC) of the message DB.The CRC shall be calculated over the entire data block (excluding the CRC bytes) including the user data, alive counter and Data ID - CRC Polynomial (0x1021) , In";
-CM_ SG_ 506 FR_CMR_AlvCnt2Val "For the first transmission request for a data element the counter shall be initialized with 0 and shall be incremented by 1 for every subsequent send request. When the counter reaches the maximum value(0xFF), then it shall restart with 0 for the next s";
-CM_ SG_ 506 ISLW_OptUsmSta "ISLW option information";
-CM_ SG_ 506 ISLW_SysSta "Validity of ISLW information";
-CM_ SG_ 506 ISLW_NoPassingInfoDis "This signal indicates additional information of ISLW. For example no passing.";
-CM_ SG_ 506 ISLW_OvrlpSignDis "indicates presence of Overlap sign";
-CM_ SG_ 506 ISLW_SpdCluMainDis "Main Speed Information for cluster display in main page(0x1~0xFCH: 1*(HEX VALUE) [KPH or MPH :Reference signal is CF_Clu_SPEED_UNIT of CLU])";
-CM_ SG_ 506 ISLW_SpdNaviMainDis "Main Speed information for navigation display in main page(0x1~0xFCH: 1*(HEX VALUE) [KPH or MPH :Reference signal is Navi_ISLW_SpdUnit of Navigation)";
-CM_ SG_ 506 ISLW_SubCondinfoSta1 "Indicates 1st conditional traffic sign status";
-CM_ SG_ 506 ISLW_SubCondinfoSta2 "Indicates 2nd conditional traffic sign status";
-CM_ SG_ 506 ISLW_SpdCluSubMainDis "Main Speed Information for cluster display in ISLW detail page";
-CM_ SG_ 506 ISLW_SpdCluDisSubCond1 "Indicates conditional speed limit/no passing of 1st conditional traffic sign for Cluster in ISLW Detail page";
-CM_ SG_ 506 ISLW_SpdCluDisSubCond2 "Indicates conditional speed limit/no passing of 2nd conditional traffic sign for Cluster in ISLW Detail page";
-CM_ SG_ 506 ISLW_SpdNaviSubMainDis "Main Speed Information for NAVI display in ISLW detail page";
-CM_ SG_ 506 ISLW_SpdNaviDisSubCond1 "Indicates conditional speed limit/no passing of 1st conditional traffic sign for NAVI in ISLW Detail page";
-CM_ SG_ 506 ISLW_SpdNaviDisSubCond2 "Indicates conditional speed limit/no passing of 2nd conditional traffic sign for NAVI in ISLW Detail page";
-CM_ SG_ 506 ISLA_SpdwOffst "This is a ISLA speed with offset to change the set speed of MSLA/CC/SCC.Unit (kph or mph) refers to cluster signal: CLU_SpdUnitTyp@CLU_01_20ms";
-CM_ SG_ 506 ISLA_SwIgnoreReq "This is a signal requesting to ignore the -(SET) or +(SET) switch input of the driver.";
-CM_ SG_ 506 ISLA_SpdChgReq "This is a signal requesting to change the set speed of MSLA/CC/SCC to the ISLA speed.";
-CM_ SG_ 506 ISLA_SpdWrn "This is a warning signal when VANZ exceeds the speed limit.";
-CM_ SG_ 506 ISLA_IcyWrn "This is a warning signal when the snow or ice sign is recognized when it is less than 4 'C.";
-CM_ SG_ 506 ISLA_SymFlashMod "This is a signal for the flashing mode of the symbol.";
-CM_ SG_ 506 ISLA_Popup "This is a signal for ISLA pop-up.";
-CM_ SG_ 506 ISLA_OptUsmSta "This is a ISLA option USM signal set by the driver.";
-CM_ SG_ 506 ISLA_OffstUsmSta "This is a signal for offset speed set by the driver. Unit (kph or mph) refers to cluster signal: CLU_SpdUnitTyp@CLU_01_20ms";
-CM_ SG_ 506 ISLA_AutoUsmSta "This is a signal for ISLA AUTO USM set by the driver.";
-CM_ SG_ 506 ISLA_Cntry "This is a signal for categorizing countries";
-CM_ SG_ 506 ISLA_AddtnlSign "This is a signal for additional sign";
-CM_ SG_ 506 ISLA_SchoolZone "This is a signal for School Zone";
-CM_ SG_ 687 HOD_Dir_Status "This signal indicates the status of hands on/off";
-CM_ BO_ 698 "Sent by the camera containing information about vehicles in front of us. IFS stands for Intelligent Front-lighting System, and this signal provides the information necessary for it to operate.";
-CM_ SG_ 698 FR_CMR_Crc4Val "The data area for CRC calculation is based on the data length (DLC) of the message DB. The CRC shall be calculated over the entire data block (excluding the CRC bytes) including the user data, alive counter and Data ID - CRC Polynomial (0x1021) , In";
-CM_ SG_ 698 FR_CMR_AlvCnt4Val "For the first transmission request for a data element the counter shall be initialized with 0 and shall be incremented by 1 for every subsequent send request. When the counter reaches the maximum value(0xFF), then it shall restart with 0 for the next s";
-CM_ SG_ 698 IFSref_FR_CMR_Sta "This is IFS system status needed for operate the IFS function of headlamp highbeam";
-CM_ SG_ 698 IFSref_VehNumVal "This is number of vehicles detected from camera";
-CM_ SG_ 698 IFSref_ILLAmbtSta "This signal is status of the ambient brightness 0x0 is bright condition (HighBeam off), 0x1 is dark condition (None)";
-CM_ SG_ 698 IFSref_VehLftAngl1Val "This is left angle of vehicle 1 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehRtAngl1Val "This is right angle of vehicle 1 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehLftAngl2Val "This is left angle of vehicle 2 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehDst1Val "IFSref_VehicleDistance1Value";
-CM_ SG_ 698 IFSref_VehRtAngl2Val "This is right angle of vehicle 2 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehLftAngl3Val "This is left angle of vehicle 3 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehRtAngl3Val "This is right angle of vehicle 3 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehLftAngl4Val "This is left angle of vehicle 4 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehRtAngl4Val "This is right angle of vehicle 4 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehLftAngl5Val "This is left angle of vehicle 5 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehRtAngl5Val "This is right angle of vehicle 5 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehLftAngl6Val "This is left angle of vehicle 6 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehRtAngl6Val "This is right angle of vehicle 6 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehLftAngl7Val "This is left angle of vehicle 7 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehRtAngl7Val "This is right angle of vehicle 7 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehLftAngl8Val "This is left angle of vehicle 8 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehRtAngl8Val "This is right angle of vehicle 8 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehLftAngl9Val "This is left angle of vehicle 9 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehRtAngl9Val "This is right angle of vehicle 9 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehLftAngl10Val "This is left angle of vehicle 10 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehRtAngl10Val "This is right angle of vehicle 10 Deg = (HEX)*0.1-25";
-CM_ SG_ 698 IFSref_VehDst2Val "IFSref_VehicleDistance2Value";
-CM_ SG_ 698 IFSref_VehDst3Val "IFSref_VehicleDistance3Value";
-CM_ SG_ 698 IFSref_VehDst4Val "IFSref_VehicleDistance4Value";
-CM_ SG_ 698 IFSref_VehDst5Val "IFSref_VehicleDistance5Value";
-CM_ SG_ 698 IFSref_VehDst6Val "IFSref_VehicleDistance6Value";
-CM_ SG_ 698 IFSref_VehDst7Val "IFSref_VehicleDistance7Value";
-CM_ SG_ 698 IFSref_VehDst8Val "IFSref_VehicleDistance8Value";
-CM_ SG_ 698 IFSref_VehDst9Val "IFSref_VehicleDistance9Value";
-CM_ SG_ 698 IFSref_VehDst10Val "IFSref_VehicleDistance10Value";
+CM_ SG_ 676 LEFT_LANE_LINE "Left lane line confidence";
+CM_ SG_ 676 RIGHT_LANE_LINE "Right lane line confidence";
CM_ SG_ 736 MAX_SPEED "Display units. Restricts car from driving above this speed unless accelerator pedal is depressed beyond pressure point";
-CM_ BO_ 866 "Contains signals with detailed lane line information. Used by ADAS ECU on HDA 2 vehicles to operate LFA. Used on cars that use message 272.";
CM_ SG_ 866 LEFT_LANE_LINE "Left lane line confidence";
CM_ SG_ 866 RIGHT_LANE_LINE "Right lane line confidence";
CM_ SG_ 961 COUNTER_ALT "only increments on change";
CM_ SG_ 1041 COUNTER_ALT "only increments on change";
-CM_ BO_ 1043 "Lamp signals do not seem universal on cars that use LKAS_ALT, but stalk signals do.";
CM_ SG_ 1043 COUNTER_ALT "only increments on change";
CM_ SG_ 1043 USE_ALT_LAMP "likely 1 on cars that use alt lamp signals";
VAL_ 53 GEAR 0 "P" 5 "D" 6 "N" 7 "R";
-VAL_ 64 GEAR 0 "P" 5 "D" 6 "N" 7 "R";
+VAL_ 64 GEAR 0 "P" 5 "D" 6 "N" 7 "R" 4 "T";
VAL_ 69 GEAR 0 "P" 5 "D" 6 "N" 7 "R";
+VAL_ 80 LKA_MODE 1 "warning only" 2 "assist" 6 "off";
+VAL_ 80 LKA_ICON 0 "hidden" 1 "grey" 2 "green" 3 "flashing green";
VAL_ 96 TRACTION_AND_STABILITY_CONTROL 0 "On" 5 "Limited" 1 "Off";
VAL_ 112 GEAR 0 "P" 5 "D" 6 "N" 7 "R";
-VAL_ 203 ADAS_ActvACISta 0 "INIT" 1 "INACTIVE" 2 "ACTIVE35(ACTIVE)" 3 "ACTIVE33(Redundancy)" 4 "RESERVED" 5 "RESERVED" 6 "RESERVED" 7 "RESERVED" 8 "RESERVED" 9 "RESERVED" 10 "RESERVED" 11 "RESERVED" 12 "RESERVED" 13 "RESERVED" 14 "RESERVED" 15 "RESERVED";
-VAL_ 203 ADAS_ActvACILvl2Sta 0 "INIT" 1 "INACTIVE" 2 "ACTIVE35(ACTIVE)" 3 "RESERVED" 4 "RESERVED" 5 "RESERVED" 6 "RESERVED" 7 "RESERVED" 8 "RESERVED" 9 "RESERVED" 10 "RESERVED" 11 "RESERVED" 12 "RESERVED" 13 "RESERVED" 14 "RESERVED" 15 "RESERVED";
-VAL_ 203 ADAS_StrAnglReqVal 0 "0x0x000~0x3FFF:Real Values" 16383 "0x0x000~0x3FFF:Real Values";
-VAL_ 203 ADAS_ACIAnglTqRedcGainVal 0 "0x0x00~0xFA:Real Values" 250 "0x0x00~0xFA:Real Values" 251 "RESERVED" 252 "RESERVED" 253 "RESERVED" 254 "RESERVED" 255 "RESERVED";
-VAL_ 203 FCA_ESA_ActvSta 0 "Inactive" 1 "Active" 2 "RESERVED" 3 "RESERVED";
-VAL_ 203 FCA_ESA_TqBstGainVal 0 "0x0x00~0xFA:Real Values" 250 "0x0x00~0xFA:Real Values" 251 "RESERVED" 252 "RESERVED" 253 "RESERVED" 254 "RESERVED" 255 "RESERVED";
VAL_ 234 LKA_FAULT 0 "ok" 1 "lka fault";
+VAL_ 267 CRUISE_BUTTONS 8 "CRUISE_MAIN" 4 "CANCEL" 1 "RES" 2 "SET" 3 "GAP";
VAL_ 272 LKA_MODE 1 "warning only" 2 "assist" 6 "off";
VAL_ 272 LKA_ICON 0 "hidden" 1 "grey" 2 "green" 3 "flashing green";
-VAL_ 272 LKAS_ANGLE_ACTIVE 0 "off" 1 "not active" 2 "active";
-VAL_ 282 HBA_SysOptSta 0 "None HBA Option (Default)" 1 "HBA Option" 2 "Reserved" 3 "Error indicator";
-VAL_ 282 HBA_SysSta 0 "HBA Disable" 1 "HBA Enable & High Beam Off" 2 "HBA Enable & High Beam On" 3 "Reserved" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "System Fail";
-VAL_ 282 HBA_IndLmpReq 0 "HBA Indicator Lamp Off" 1 "HBA Indicator Lamp On" 2 "Reserved" 3 "Error indicator";
-VAL_ 282 FCA_Equip_MFC 0 "No Coding" 1 "Sensor Fusion FCA" 2 "Camera only FCA" 3 "No FCA Option" 4 "ADAS_DRV Option" 5 "Reserved" 6 "Not used" 7 "Error indicator";
-VAL_ 282 HBA_OptUsmSta 0 "None HBA Option (Default)" 1 "HBA Function Off" 2 "HBA Function On" 3 "Invalid (Fail)";
-VAL_ 282 DAW_LVDA_PUDis 0 "Default" 1 "Display “Leading vehicle departure alert”" 2 "Reserved" 3 "Error indicator";
-VAL_ 282 DAW_LVDA_OptUsmSta 0 "No Option (default)" 1 "Off" 2 "On" 3 "Error Indicator";
-VAL_ 282 DAW_OptUsmSta 0 "None DAW Option (Default)" 1 "System Off" 2 "System On" 3 "Reserved" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Invalid (Gray)";
-VAL_ 282 DAW_SysSta 0 "System Off" 1 "Attention Level 1" 2 "Attention Level 2" 3 "Attention Level 3" 4 "Attention Level 4" 5 "Attention Level 5" 6 "Reserved" 7 "Reserved" 8 "Reserved" 9 "Reserved" 10 "Reserved" 11 "Reserved" 12 "Reserved" 13 "Reserved" 14 "System Standby" 15 "System Fail";
-VAL_ 282 DAW_WrnMsgSta 0 "No Warning" 1 "Rest Recommend Warning" 2 "Hands-Off TMS call request" 3 "Reserved" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Error indicator";
-VAL_ 282 DAW_TimeRstReq 0 "No signal" 1 "Time reset" 2 "Reserved" 3 "Error indicator";
-VAL_ 282 DAW_SnstvtyModRetVal 0 "Default" 1 "Late" 2 "Normal" 3 "Reserved" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Invalid";
-VAL_ 282 FR_CMR_SCCEquipSta 0 "Not Applied" 1 "Applied" 2 "Not used" 3 "Error Indicator";
+VAL_ 272 LKAS_ANGLE_ACTIVE 1 "not active" 2 "active";
VAL_ 298 LKA_MODE 1 "warning only" 2 "assist" 6 "off";
VAL_ 298 LKA_ICON 0 "hidden" 1 "grey" 2 "green" 3 "flashing green";
VAL_ 304 PARK_BUTTON 1 "Pressed" 2 "Not Pressed";
@@ -858,7 +1006,7 @@ VAL_ 353 LANE_RIGHT 0 "HIDDEN" 1 "GREEN";
VAL_ 353 LANE_ZOOM 0 "ZOOM" 1 "HIDDEN";
VAL_ 353 ALERTS_1 0 "HIDDEN" 1 "WARNING_ONLY_CAR_CENTER" 2 "WARNING_ONLY_CAR_LEFT" 3 "WARNING_ONLY_CAR_RIGHT" 4 "WARNING_ONLY_LEFT" 5 "WARNING_ONLY_RIGHT" 11 "EMERGENCY_BRAKING_CAR_CENTER" 12 "EMERGENCY_BRAKING_CAR_LEFT" 13 "EMERGENCY_BRAKING_CAR_RIGHT" 14 "EMERGENCY_BRAKING_LEFT" 15 "EMERGENCY_BRAKING_RIGHT" 21 "EMERGENCY_STEERING_CAR_LEFT" 22 "EMERGENCY_STEERING_CAR_RIGHT" 23 "EMERGENCY_STEERING_CAR_LEFT_AWAY" 24 "EMERGENCY_STEERING_CAR_RIGHT_AWAY" 25 "EMERGENCY_STEERING_REAR_LEFT" 26 "EMERGENCY_STEERING_REAR_RIGHT" 33 "DRIVE_CAREFULLY";
VAL_ 353 ALERTS_2 0 "HIDDEN" 1 "KEEP_HANDS_ON_STEERING_WHEEL" 2 "KEEP_HANDS_ON_STEERING_WHEEL_RED" 3 "LANE_FOLLOWING_ASSIST_DEACTIVATED" 4 "HIGHWAY_DRIVING_ASSIST_DEACTIVATED" 5 "CONSIDER_TAKING_A_BREAK" 6 "PRESS_OK_BUTTON_TO_ENABLE_LANE_CHANGE_ASSIST" 7 "COLLISION_RISK_VEHICLE_TAKING_EMERGENCY_CONTROL" 8 "TAKE_CONTROL_OF_THE_VEHICLE_IMMEDIATELY_VEHICLE_IS_STOPPING" 9 "TAKE_CONTROL_OF_THE_VEHICLE_IMMEDIATELY" 11 "HIGHWAY_DRIVING_PILOT_SYSTEM_DEACTIVATED_AUDIBLE" 12 "KEEP_YOUR_EYES_ON_THE_ROAD" 13 "HIGHWAY_DRIVING_PILOT_CONDITIONS_NOT_MET_AUDIBLE" 14 "COLLISION_RISK_VEHICLE_TAKING_EMERGENCY_CONTROL" 15 "SET_THE_WIPER_AND_LIGHT_CONTROLS_TO_AUTO" 16 "BE_PREPARED_TO_TAKE_CONTROL_OF_THE_VEHICLE_AT_ANY_TIME" 21 "TAKE_CONTROL_OF_THE_VEHICLE_IMMEDIATELY_VEHICLE_IS_STOPPING" 10 "TAKE_CONTROL_OF_THE_VEHICLE_IMMEDIATELY";
-VAL_ 353 ALERTS_3 1 "AUTOMATICALLY_ADJUSTING_TO_THE_POSTED_SPEED_LIMIT" 2 "SET_SPEED_CHANGED" 3 "AUTOMATICALLY_ADJUSTING_TO_THE_POSTED_SPEED_LIMIT" 4 "SET_SPEED_CHANGED" 7 "DISTANCE_1" 8 "DISTANCE_2" 9 "DISTANCE_3" 10 "DISTANCE_4" 17 "DRIVE_CAREFULLY" 18 "CHECK_SURROUNDINGS" 19 "CONDITIONS_NOT_MET" 20 "LANES_NOT_DETECTED" 21 "CURVE_TOO_SHARP" 22 "LANE_TOO_NARROW" 23 "ROAD_TYPE_NOT_SUPPORTED" 24 "UNAVAILABLE_WITH_HAZARD_LIGHTS_ON" 25 "VEHICLE_SPEED_IS_TOO_LOW" 26 "KEEP_HANDS_ON_STEERING_WHEEL" 27 "LANE_TYPE_NOT_SUPPORTED" 28 "LANE_ASSIST_CANCELED_STEERING_INPUT_DETECTED" 0 "HIDDEN";
+VAL_ 353 ALERTS_3 0 "HIDDEN" 1 "AUTOMATICALLY_ADJUSTING_TO_THE_POSTED_SPEED_LIMIT" 2 "SET_SPEED_CHANGED" 3 "AUTOMATICALLY_ADJUSTING_TO_THE_POSTED_SPEED_LIMIT" 4 "SET_SPEED_CHANGED" 7 "DISTANCE_1" 8 "DISTANCE_2" 9 "DISTANCE_3" 10 "DISTANCE_4" 17 "DRIVE_CAREFULLY" 18 "CHECK_SURROUNDINGS" 19 "CONDITIONS_NOT_MET" 20 "LANES_NOT_DETECTED" 21 "CURVE_TOO_SHARP" 22 "LANE_TOO_NARROW" 23 "ROAD_TYPE_NOT_SUPPORTED" 24 "UNAVAILABLE_WITH_HAZARD_LIGHTS_ON" 25 "VEHICLE_SPEED_IS_TOO_LOW" 26 "KEEP_HANDS_ON_STEERING_WHEEL" 27 "LANE_TYPE_NOT_SUPPORTED" 28 "LANE_ASSIST_CANCELED_STEERING_INPUT_DETECTED";
VAL_ 353 ALERTS_4 0 "HIDDEN" 1 "TAKE_FOOT_OFF_THE_ACCELERATOR_PEDAL" 2 "TAKE_FOOT_OFF_THE_BRAKE_PEDAL" 3 "UNAVAILABLE_WHILE_HIGHWAY_DRIVING_PILOT_SYSTEM_IS_ACTIVE" 4 "TO_EXIT_HDP_GRASP_THE_STEERING_WHEEL_THEN_PRESS_AND_HOLD_THE_HDP_BUTTON" 5 "ACCELERATOR_PEDAL_OPERATION_LIMITED_FOR_SAFETY" 6 "TURN_OFF_HAZARD_WARNING_LIGHTS_AND_TURN_SIGNAL" 7 "KEEP_THE_DRIVERS_SEAT_IN_A_SAFE_DRIVING_POSITION" 16 "SET_SPEED_CHANGED" 17 "ACTIVATING_WINDSHIELD_DEFOG_TO_MAINTAIN_THE_DRIVERS_VIEW" 18 "SET_THE_WIPER_AND_LIGHT_CONTROLS_TO_AUTO" 19 "VEHICLE_SPEED_REDUCED_FOR_SAFETY_MERGING_LANES_AHEAD" 20 "SPEED_REDUCED_FOR_SAFETY_CONSTRUCTION_ZONE_DETECTED" 21 "VEHICLE_SPEED_LIMITED_SENSOR_DETECTION_RANGE_LIMITED" 22 "PREPARE_TO_TAKE_CONTROL_UNSUPPORTED_ROAD_TYPE_AHEAD" 23 "PREPARE_TO_TAKE_CONTROL_ENTRANCE_AND_EXIT_RAMPS_AHEAD" 24 "PREPARE_TO_TAKE_CONTROL_TOLLGATE_AHEAD" 25 "PREPARE_TO_TAKE_CONTROL_ROAD_EVENT_AHEAD" 26 "CLEARING_PATH_FOR_EMERGENCY_VEHICLE" 27 "VEHICLE_IS_TOO_SLOW_COMPARED_TO_TRAFFIC_FLOW" 28 "AFTER_SUNSET_HDP_IS_AVAILABLE_IN_AN_INSIDE_LANE_BEHIND_A_LEADING_VEHICLE" 29 "VEHICLE_SPEED_LIMITED_MERGING_LANES_AHEAD" 30 "VEHICLE_SPEED_LIMITED_CONSTRUCTION_ZONE_DETECTED" 31 "VEHICLE_SPEED_TEMPORARILY_LIMITED_FOR_SAFETY" 32 "PRESS_AND_HOLD_THE_BUTTON_TO_ACTIVATE_HIGHWAY_DRIVING_PILOT" 40 "HIGHWAY_DRIVING_PILOT_SYSTEM_IS_AVAILABLE" 64 "RESTART_VEHICLE_AFTER_EMERGENCY_STOP" 65 "CONNECTED_SERVICES_UNAVAILABLE" 66 "AVAILABLE_AFTER_VEHICLE_SOFTWARE_IS_UPDATED" 67 "ROAD_TYPE_NOT_SUPPORTED" 68 "ONLY_AVAILABLE_WHILE_DRIVING_ON_HIGHWAY_LANES" 69 "UNAVAILABLE_WHILE_OTHER_WARNINGS_ARE_ACTIVE" 70 "CANNOT_ACTIVATE_AT_ENTRANCE_EXIT_RAMPS" 71 "LANE_UNSUPPORTED" 72 "NOT_AVAILABLE_IN_THIS_COUNTRY" 79 "CHECKING_THE_DETECTION_RANGE_OF_THE_SENSOR" 80 "SHIFT_TO_D" 81 "ENGINE_STOPPED_BY_AUTO_STOP" 82 "INCREASE_DISTANCE_FROM_VEHICLE_AHEAD" 83 "VEHICLE_SPEED_IS_TOO_HIGH" 84 "CENTER_VEHICLE_IN_THE_LANE" 85 "PARKING_ASSIST_IS_ACTIVE" 86 "ESC_ACTIVIATION_REQUIRED" 87 "UNFOLD_SIDE_VIEW_MIRRORS" 88 "UNAVAILABLE_IN_THE_OUTER_LANE_AFTER_SUNSET" 89 "VEHICLE_SPEED_LIMITED_AFTER_SUNSET_FOR_SAFETY" 90 "LEADING_VEHICLE_NOT_DETECTED" 104 "AGGRESSIVE_BRAKING_OR_STEERING_DETECTED" 110 "SENSOR_AUTO_CALIBRATION_IN_PROGRESS_THIS_MAY_TAKE_SEVERAL_MINUTES" 111 "HIGHWAY_DRIVING_PILOT_WILL_BE_AVAILABLE_SHORTLY" 112 "IF_STEERING_WHEEL_IS_USED_HDP_WILL_BE_DEACTIVATED" 120 "IMPACT_DETECTED" 128 "UNSUITABLE_USE_OF_ACCELERATOR_PEDAL_DETECTED" 129 "GEAR_SHIFTER_USE_DETECTED" 130 "UNSUITABLE_BRAKE_PEDAL_USE_DETECTED" 131 "VEHICLE_START_BUTTON_PRESSED" 132 "VEHICLE_HAS_BEEN_STOPPED_FOR_TOO_LONG" 141 "TRAFFIC_CONGESTION_HAS_CLEARED" 142 "ENTRANCE_AND_EXIT_RAMPS_AHEAD" 143 "UNSUPPORTED_LANE_AHEAD" 144 "UNSUPPORTED_ROAD_TYPE_AHEAD" 145 "LANE_DEPARTURE_DETECTED" 146 "MAXIMUM_SPEED_EXCEEDED" 147 "HIGHWAY_DRIVING_PILOT_LIMITED_ABNORMAL_VEHICLE_CONTROLLER_STATUS" 148 "WIPER_LIGHT_CONTROL_SETTINGS_ARE_UNSUITABLE_FOR_USE_WITH_HDP" 149 "WINDSHIELD_DEFOG_SYSTEM_STATUS_IS_UNSUITABLE_FOR_USE_WITH_HDP" 150 "HAZARD_WARNING_LIGHTS_OR_TURN_SIGNAL_OPERATION_DETECTED" 151 "PERFORMING_EVASIVE_STEERING_OBSTACLES_DETECTED_AHEAD" 152 "HIGHWAY_DRIVING_PILOT_LIMITED_SENSOR_DETECTION_RANGE_LIMITED" 160 "CHECK_HIGHWAY_DRIVING_PILOT_SYSTEM" 161 "SAFETY_FUNCTION_ACTIVATED" 176 "CAMERA_OBSCURED" 177 "RADAR_BLOCKED" 178 "LIDAR_BLOCKED" 179 "AIRBAG_WARNING_LIGHT_IS_ON" 180 "ATTACHED_TRAILED_DETECTED" 181 "HIGH_OUTSIDE_TEMPERATURE" 182 "LOW_OUTSIDE_TEMPERATURE" 190 "UNAVAILABLE_DUE_TO_THE_ROAD_EVENT_INFORMATION_RECEIVED" 191 "UNAVAILABLE_NEAR_TOLLGATES" 192 "DRIVERS_SEAT_IS_NOT_IN_A_SAFE_DRIVING_POSITION" 193 "VEHICLE_DRIVING_THE_WRONG_WAY_DETECTED_AHEAD" 194 "EMERGENCY_VEHICLE_DETECTED" 195 "OBSTACLE_DETECTED_AHEAD" 196 "SENSOR_BLOCKED_DUE_TO_RAIN_SNOW_OR_ROAD_DEBRIS" 197 "SLIPPERY_ROAD_SURFACE_DETECTED" 198 "CONSTRUCTION_ZONE_DETECTED_AHEAD" 199 "PEDESTRIAN_DETECTED_AHEAD" 200 "UNSUITABLE_DRIVERS_SEAT_POSITION_DETECTED" 201 "FOLDED_SIDE_VIEW_MIRRORS_DETECTED" 208 "VEHICLE_POSITION_NOT_DETECTED" 209 "LANE_NOT_DETECTED" 210 "DRIVER_NOT_DETECTED" 211 "KEEP_YOUR_EYES_ON_THE_ROAD" 212 "LEADING_VEHICLE_REQUIRED_AFTER_SUNSET" 213 "TBD" 240 "LOW_FUEL" 241 "LOW_TIRE_PRESSURE" 242 "DOOR_OPEN" 243 "TRUNK_OPEN" 244 "HOOD_OPEN" 245 "SEAT_BELT_NOT_FASTENED" 246 "PARKING_BRAKE_ACTIVATED" 247 "LOW_EV_BATTERY" 248 "HDP_DEACTIVATION_DELAYED_RISK_OF_COLLISION_DETECTED" 249 "LIFTGATE_OPENED";
VAL_ 353 ALERTS_5 0 "HIDDEN" 1 "DRIVERS_GRASP_NOT_DETECTED_DRIVING_SPEED_WILL_BE_LIMITED" 2 "WATCH_FOR_SURROUNDING_VEHICLES" 3 "SMART_CRUISE_CONTROL_DEACTIVATED" 4 "SMART_CRUISE_CONTROL_CONDITIONS_NOT_MET" 5 "USE_SWITCH_OR_PEDAL_TO_ACCELERATE" 6 "DRIVER_ASSISTNCE_SYSTEM_LIMITED_TRAILER_ATTACHED" 7 "DRIVER_ASSISTNCE_SYSTEM_LIMITED_DRIVER_FULL_FACE_NOT_VISIBLE" 11 "LEADING_VEHICLE_IS_DRIVING_AWAY" 12 "STOP_VEHICLE_THEN_TRY_AGAIN" 19 "ACTIVATING_HIGHWAY_DRIVING_PILOT_SYSTEM" 20 "CONTINUING_USE_OF_HIGHWAY_DRIVING_PILOT_WILL_RESULT_IN_DEVIATION_FROM_THE_NAVIGATION_ROUTE" 21 "HIGHWAY_DRIVING_PILOT_SYSTEM_DEACTIVATED_SILENT" 22 "HIGHWAY_DRIVING_PILOT_SYSTEM_NOT_APPLIED" 23 "HIGHWAY_DRIVING_PILOT_CONDITIONS_NOT_MET_SILENT";
VAL_ 353 MUTE 0 "NONE" 1 "MUTED";
@@ -868,7 +1016,7 @@ VAL_ 353 SOUNDS_3 0 "NONE" 3 "SOFT CHIME" 5 "SINGLE CHIME";
VAL_ 353 SOUNDS_4 0 "NONE" 2 "DOUBLE CHIME";
VAL_ 353 SETSPEED_HUD 0 "HIDDEN" 1 "GRAY" 2 "GREEN" 3 "WHITE" 5 "CYAN";
VAL_ 353 DISTANCE_LEAD 0 "HIDDEN" 1 "GRAY" 2 "WHITE";
-VAL_ 353 DISTANCE_CAR 0 "HIDDEN" 1 "GRAY" 2 "WHITE" 3 "CYAN A";
+VAL_ 353 DISTANCE_CAR 0 "HIDDEN" 1 "GRAY" 2 "WHITE" 3 "CYAN";
VAL_ 353 DISTANCE_SPACING 0 "HIDDEN" 1 "BLUE" 3 "WHITE" 5 "CYAN";
VAL_ 353 SETSPEED 0 "HIDDEN" 1 "GRAY" 2 "GREEN" 3 "WHITE" 6 "CYAN";
VAL_ 353 HDA_ICON 0 "HIDDEN" 1 "GRAY" 2 "GREEN" 3 "WHITE" 5 "CYAN HDP";
@@ -885,10 +1033,12 @@ VAL_ 354 SPEEDLIMIT_FLASH 0 "HIDDEN" 1 "ERROR" 2 "NORMAL" 4 "RED";
VAL_ 354 SIGNS 0 "HIDDEN" 1 "PEDESTRIAN_CROSSING" 2 "SCHOOL_CROSSWALK" 8 "STOP" 9 "YIELD" 16 "DO_NOT_PASS" 19 "DO_NOT_ENTER" 24 "ROUNDABOUT" 26 "RIGHT_CURVE_AHEAD" 27 "LEFT_CURVE_AHEAD" 28 "SLIGHT_RIGHT_CURVE_AHEAD" 29 "SLIGHT_LEFT_CURVE_AHEAD";
VAL_ 354 SPEEDLIMIT_WEATHER 0 "HIDDEN" 1 "RAIN" 2 "SNOW" 3 "RAIN+SNOW" 4 "TRAILER";
VAL_ 354 VIBRATE 0 "NONE" 1 "VIBRATE";
-VAL_ 354 LEAD 0 "HIDDEN" 1 "GRAY BOX" 2 "WHITE BOX" 3 "GRAY CAR" 4 "WHITE CAR" 5 "GRAY TRUCK" 6 "WHITE TRUCK" 7 "GRAY PERSON" 8 "WHITE PERSON" 9 "GRAY BICYCLE" 10 "WHITE BICYCLE" 11 "GRAY MOTORCYCLE" 12 "WHITE MOTORCYCLE" 13 "DARK CONE" 14 "ORANGE CONE";
-VAL_ 354 LEAD_ALT 0 "HIDDEN" 1 "GRAY BOX" 2 "WHITE BOX" 3 "DIM CONE" 4 "ORANGE CONE";
-VAL_ 354 LEAD_LEFT 0 "HIDDEN" 1 "GRAY BOX" 2 "WHITE BOX" 3 "GRAY CAR" 4 "WHITE CAR" 5 "GRAY TRUCK" 6 "WHITE TRUCK" 7 "GRAY PERSON" 8 "WHITE PERSON" 9 "GRAY BICYCLE" 10 "WHITE BICYCLE" 11 "GRAY MOTORCYCLE" 12 "WHITE MOTORCYCLE" 13 "DARK CONE" 14 "ORANGE CONE";
-VAL_ 354 LEAD_RIGHT 0 "HIDDEN" 1 "GRAY BOX" 2 "WHITE BOX" 3 "GRAY CAR" 4 "WHITE CAR" 5 "GRAY TRUCK" 6 "WHITE TRUCK" 7 "GRAY PERSON" 8 "WHITE PERSON" 9 "GRAY BICYCLE" 10 "WHITE BICYCLE" 11 "GRAY MOTORCYCLE" 12 "WHITE MOTORCYCLE" 13 "DARK CONE" 14 "ORANGE CONE";
+VAL_ 354 FF_DETECT 0 "HIDDEN" 1 "GRAY BOX" 2 "WHITE BOX" 3 "GRAY CAR" 4 "WHITE CAR" 5 "GRAY TRUCK" 6 "WHITE TRUCK" 7 "GRAY PERSON" 8 "WHITE PERSON" 9 "GRAY BICYCLE" 10 "WHITE BICYCLE" 11 "GRAY MOTORCYCLE" 12 "WHITE MOTORCYCLE" 13 "DARK CONE" 14 "ORANGE CONE";
+VAL_ 354 FF_DETECT_ALT 0 "HIDDEN" 1 "GRAY BOX" 2 "WHITE BOX" 3 "DIM CONE" 4 "ORANGE CONE";
+VAL_ 354 LF_DETECT 0 "HIDDEN" 1 "GRAY BOX" 2 "WHITE BOX" 3 "GRAY CAR" 4 "WHITE CAR" 5 "GRAY TRUCK" 6 "WHITE TRUCK" 7 "GRAY PERSON" 8 "WHITE PERSON" 9 "GRAY BICYCLE" 10 "WHITE BICYCLE" 11 "GRAY MOTORCYCLE" 12 "WHITE MOTORCYCLE" 13 "DARK CONE" 14 "ORANGE CONE";
+VAL_ 354 RF_DETECT 0 "HIDDEN" 1 "GRAY BOX" 2 "WHITE BOX" 3 "GRAY CAR" 4 "WHITE CAR" 5 "GRAY TRUCK" 6 "WHITE TRUCK" 7 "GRAY PERSON" 8 "WHITE PERSON" 9 "GRAY BICYCLE" 10 "WHITE BICYCLE" 11 "GRAY MOTORCYCLE" 12 "WHITE MOTORCYCLE" 13 "DARK CONE" 14 "ORANGE CONE";
+VAL_ 354 LR_DETECT 0 "HIDDEN" 1 "GRAY BOX" 2 "WHITE BOX" 3 "GRAY CAR" 4 "WHITE CAR" 5 "GRAY TRUCK" 6 "WHITE TRUCK" 7 "GRAY PERSON" 8 "WHITE PERSON" 9 "GRAY BICYCLE" 10 "WHITE BICYCLE" 11 "GRAY MOTORCYCLE" 12 "WHITE MOTORCYCLE" 13 "DARK CONE" 14 "ORANGE CONE";
+VAL_ 354 RR_DETECT 0 "HIDDEN" 1 "GRAY BOX" 2 "WHITE BOX" 3 "GRAY CAR" 4 "WHITE CAR" 5 "GRAY TRUCK" 6 "WHITE TRUCK" 7 "GRAY PERSON" 8 "WHITE PERSON" 9 "GRAY BICYCLE" 10 "WHITE BICYCLE" 11 "GRAY MOTORCYCLE" 12 "WHITE MOTORCYCLE" 13 "DARK CONE" 14 "ORANGE CONE";
VAL_ 354 FAULT_FSS 0 "HIDDEN" 1 "CHECK_FORWARD_SAFETY_SYSTEM" 2 "FORWARD_SAFETY_SYSTEM_LIMITED_CAMERA_OBSCURED" 3 "FORWARD_SAFETY_SYSTEM_LIMITED_RADAR_BLOCKED";
VAL_ 354 FAULT_FCA 0 "HIDDEN" 1 "CHECK_FORWARD_SIDE_SAFETY_SYSTEM" 2 "FORWARD_SIDE_SAFETY_SYSTEM_LIMITED_CAMERA_OBSCURED" 3 "FORWARD_SIDE_SAFETY_SYSTEM_LIMITED_RADAR_BLOCKED";
VAL_ 354 FAULT_LSS 0 "HIDDEN" 1 "CHECK_LANE_SAFETY_SYSTEM" 2 "LANE_SAFETY_SYSTEM_DISABLED_CAMERA_OBSCURED";
@@ -903,80 +1053,46 @@ VAL_ 354 FAULT_HDP 0 "HIDDEN" 1 "CHECK_HIGHWAY_DRIVING_PILOT_SYSTEM" 2 "HIGHWAY_
VAL_ 354 FAULT_DAS 0 "HIDDEN" 1 "CHECK_DRIVER_ASSISTANCE_SYSTEM" 2 "DRIVER_ASSISTANCE_SYSTEM_LIMITED_CAMERA_OBSCURED" 3 "DRIVER_ASSISTANCE_SYSTEM_LIMITED_RADAR_BLOCKED" 4 "DRIVER_ASSISTANCE_SYSTEM_LIMITED_CAMERA_OBSCURED_AND_RADAR_BLOCKED";
VAL_ 354 FAULT_ESS 0 "HIDDEN" 1 "CHECK_EMERGENCY_STOPPING_FUNCTION" 2 "EMERGENCY_STOPPING_FUNCTION_DISABLED_CAMERA_OBSCURED" 3 "EMERGENCY_STOPPING_FUNCTION_DISABLED_RADAR_BLOCKED";
VAL_ 362 BLINKER_CONTROL 1 "hazards" 2 "hazards button backlight" 3 "left blinkers" 4 "right blinkers";
+VAL_ 373 SCC_OptTyp 0 "SCC is not equipped" 1 "SCC is equipped" 2 "Not used" 3 "Error Indicator";
VAL_ 373 ACCEnable 0 "SCC ready" 1 "SCC temp fault" 2 "SCC permanent fault" 3 "SCC permanent fault, communication issue";
+VAL_ 373 SCC_ReqLimSta 0 "No request" 1 "Limited No Limitation" 2 "Acceleration Limited" 3 "Deceleration Limited";
+VAL_ 373 ESC_StdStillVal 0 "No stand still detected" 1 "stand still detected" 2 "Not used" 3 "Error Indicator";
+VAL_ 373 ESC_DclEnblReq 0 "Disable deceleration control" 1 "Enable deceleration control" 2 "Not used" 3 "Error Indicator";
+VAL_ 373 ESC_PrkBrkActvSta 0 "Parking brake is not activated" 1 "Parking brake is activated" 2 "Not used" 3 "Error Indicator";
+VAL_ 373 FCA_EquipSta 0 "FCA is not equipped" 1 "FCA is equipped" 2 "Not used" 3 "Error Indicator";
+VAL_ 373 FCA_AvlblSta 0 "Available" 1 "Temporarily not available" 2 "Permanently not available" 3 "FCA Communication Error";
VAL_ 416 ACCMode 0 "off" 1 "enabled" 2 "driver_override" 3 "off_maybe_fault" 4 "cancelled";
-VAL_ 416 SCC_ObjSta 0 "No in-path object detected" 1 "In-path object detected (uncontrollable)" 2 "In-path object detected (controllable:longitudinal)" 3 "Reserved" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Reserved";
VAL_ 426 CRUISE_BUTTONS 0 "none" 1 "res_accel" 2 "set_decel" 3 "gap_distance" 4 "pause_resume";
-VAL_ 437 Info_LftLnQualSta 0 "Very Low Quality" 1 "Low Quality" 2 "High Quality" 3 "Very High Quality" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Error indicator";
-VAL_ 437 Info_LftLnDptSta 0 "No Left Line Departure" 1 "Left Line Departure" 2 "Reserved" 3 "Error Indicator";
-VAL_ 437 Info_RtLnQualSta 0 "Very Low Quality" 1 "Low Quality" 2 "High Quality" 3 "Very High Quality" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Error indicator";
-VAL_ 437 Info_RtLnDptSta 0 "No Right Line Departure" 1 "Right Line Departure" 2 "Reserved" 3 "Error Indicator";
-VAL_ 437 Info_RtLnCvtrVal 65534 "Reserved" 65535 "Error indicator";
VAL_ 463 CRUISE_BUTTONS 0 "none" 1 "res_accel" 2 "set_decel" 3 "gap_distance" 4 "pause_resume";
VAL_ 463 RIGHT_PADDLE 0 "Not Pulled" 1 "Pulled";
VAL_ 463 LEFT_PADDLE 0 "Not Pulled" 1 "Pulled";
-VAL_ 506 ISLW_OptUsmSta 0 "None ISLW Option (Default)" 1 "System Disabled by USM" 2 "System Enable by USM" 3 "Invalid";
-VAL_ 506 ISLW_SysSta 0 "Normal (Default)" 1 "System Fail" 2 "ISLW Temporary Unavailable" 3 "Reserved";
-VAL_ 506 ISLW_NoPassingInfoDis 0 "None Display (Default)" 1 "LHD No Passing Zone Display" 2 "RHD No Passing Zone Display" 3 "Reserved" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Invalid";
-VAL_ 506 ISLW_OvrlpSignDis 0 "None (Default)" 1 "Overlap Sign" 2 "Reserved" 3 "Error indicator";
-VAL_ 506 ISLW_SpdCluMainDis 0 "No Recognition (Default)" 253 "Unlimited Speed" 254 "Reserved" 255 "Invalid";
-VAL_ 506 ISLW_SpdNaviMainDis 0 "No Recognition (Default)" 253 "Unlimited Speed" 254 "Reserved" 255 "Invalid";
-VAL_ 506 ISLW_SubCondinfoSta1 0 "None (Default)" 1 "Rain" 2 "Snow" 3 "Snow&Rain" 4 "Trailer" 5 "Reserved" 6 "Reserved" 7 "Reserved" 8 "Reserved" 9 "Reserved" 10 "Reserved" 11 "Reserved" 12 "Reserved" 13 "Reserved" 14 "Generic" 15 "Invalid";
-VAL_ 506 ISLW_SubCondinfoSta2 0 "None (Default)" 1 "Rain" 2 "Snow" 3 "Snow&Rain" 4 "Trailer" 5 "Reserved" 6 "Reserved" 7 "Reserved" 8 "Reserved" 9 "Reserved" 10 "Reserved" 11 "Reserved" 12 "Reserved" 13 "Reserved" 14 "Generic" 15 "Invalid";
-VAL_ 506 ISLW_SpdCluSubMainDis 0 "No Recognition (Default)" 253 "Unlimited Speed" 254 "Reserved" 255 "Invalid";
-VAL_ 506 ISLW_SpdCluDisSubCond1 0 "No Recognition (Default)" 253 "LHD Conditional No Passing ZONE" 254 "RHD Conditional No Passing ZONE" 255 "Invalid";
-VAL_ 506 ISLW_SpdCluDisSubCond2 0 "No Recognition (Default)" 253 "LHD Conditional No Passing ZONE" 254 "RHD Conditional No Passing ZONE" 255 "Invalid";
-VAL_ 506 ISLW_SpdNaviSubMainDis 0 "No Recognition (Default)" 253 "Unlimited Speed" 254 "Reserved" 255 "Invalid";
-VAL_ 506 ISLW_SpdNaviDisSubCond1 0 "No Recognition (Default)" 253 "LHD Conditional No Passing ZONE" 254 "RHD Conditional No Passing ZONE" 255 "Invalid";
-VAL_ 506 ISLW_SpdNaviDisSubCond2 0 "No Recognition (Default)" 253 "LHD Conditional No Passing ZONE" 254 "RHD Conditional No Passing ZONE" 255 "Invalid";
-VAL_ 506 ISLA_SpdwOffst 0 "No Recognition" 253 "Unlimited Speed" 254 "Reserved" 255 "Invalid";
-VAL_ 506 ISLA_SwIgnoreReq 0 "Allow All Switch Inputs (default)" 1 "-(SET) Switch Input Ignore" 2 "+(SET) Switch Input Ignore" 3 "-(SET) & +(SET) Switch Inputs Ignore";
-VAL_ 506 ISLA_SpdChgReq 0 "Default" 1 "Speed Change Request" 2 "Reserved" 3 "Reserved";
-VAL_ 506 ISLA_SpdWrn 0 "No Warning" 1 "Warning" 2 "Reserved" 3 "Reserved";
-VAL_ 506 ISLA_IcyWrn 0 "No Warning" 1 "Warning" 2 "Reserved" 3 "Reserved";
-VAL_ 506 ISLA_SymFlashMod 0 "No Flasing" 1 "Flashing Sign" 2 "Flashing - Arrow Symbol" 3 "Flashing + Arrow Symbol" 4 "Flashing Auto Symbol" 5 "Reserved" 6 "Reserved" 7 "Reserved";
-VAL_ 506 ISLA_Popup 0 "No Popup" 1 "MSLA Speed will Change" 2 "MSLA Speed has Changed" 3 "CC_SCC Speed will Change" 4 "CC_SCC Speed has Changed" 5 "Reserved" 6 "Reserved" 7 "Reserved";
-VAL_ 506 ISLA_OptUsmSta 0 "None ISLA Option (속도 제한 메뉴 삭제)" 1 "Off" 2 "Warning" 3 "Assist" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Invalid (GRAY)";
-VAL_ 506 ISLA_OffstUsmSta 0 "None Offset Function" 1 "-10kph or -5mph" 2 "-5kph or -3mph" 3 "0kph or 0mph" 4 "+5kph or +3mph" 5 "+10kph or +5mph" 6 "Reserved" 7 "Invalid (GRAY)";
-VAL_ 506 ISLA_AutoUsmSta 0 "None Auto Function (Delete Menu)" 1 "Auto Off" 2 "Auto On" 3 "Invalid (GRAY)";
-VAL_ 506 ISLA_Cntry 0 "Europe/Russia/Australia" 1 "Domestic" 2 "China" 3 "USA" 4 "Canada" 5 "Australia" 6 "Reserved" 7 "Reserved" 8 "Reserved" 9 "Reserved" 10 "Reserved" 11 "Reserved" 12 "Reserved" 13 "Reserved" 14 "Reserved" 15 "Initial Value (default)";
-VAL_ 506 ISLA_AddtnlSign 0 "No Recognition (default)" 1 "School Crossing" 16 "Do Not Pass" 17 "Reserved" 18 "Reserved" 19 "Reserved" 20 "Reserved" 21 "Reserved" 22 "Reserved" 23 "Reserved" 24 "Exit" 25 "Roundabout" 26 "Right Curve" 27 "Left Curve" 28 "Winding Road" 29 "Reserved" 30 "Reserved" 31 "Reserved" 2 "Pedestrian Crossing" 3 "Bicycle Crossing" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Reserved" 8 "Stop" 9 "Yield" 10 "Stop Ahead" 11 "Yield Ahead" 12 "Road Construction Ahead" 13 "Lane Reduction" 14 "Reserved" 15 "Reserved";
-VAL_ 506 ISLA_SchoolZone 0 "No School Zone" 1 "School Zone" 2 "Reserved" 3 "Reserved";
-VAL_ 687 HOD_Dir_Status 0 "HANDS OFF" 1 "HAND TOUCH (SOFT)" 2 "HAND TOUCH (STRONG)" 3 "HAND GRIP (SOFT)" 4 "HAND GRIP (STRONG)" 5 "RESERVED" 6 "RESERVED";
-VAL_ 698 IFSref_FR_CMR_Sta 0 "None Option (Default)" 1 "Normal" 2 "Blockage Status" 3 "Error Indicator";
-VAL_ 698 IFSref_VehNumVal 0 "No vehicle" 1 "Number of vehicles" 2 "Number of vehicles" 3 "Number of vehicles" 4 "Number of vehicles" 5 "Number of vehicles" 6 "Number of vehicles" 7 "Number of vehicles" 8 "Number of vehicles" 9 "Number of vehicles" 10 "Number of vehicles" 11 "Over than 10 vehicles" 12 "Reserved" 13 "Reserved" 14 "Default" 15 "Error indicator";
-VAL_ 698 IFSref_ILLAmbtSta 0 "Bright" 1 "Dark" 2 "Not used" 3 "Error indicator";
-VAL_ 698 IFSref_VehLftAngl1Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehRtAngl1Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehLftAngl2Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehDst1Val 0 "No Value" 1 "1~10m" 2 "11~20m" 3 "21~30m" 4 "31~40m" 5 "41~50m" 6 "51~60m" 7 "61~70m" 8 "71~80m" 9 "81~90m" 10 "91~100m" 11 "101~200m" 12 "201~300m" 13 "301~400m" 14 "401m~" 15 "Error indicator";
-VAL_ 698 IFSref_VehRtAngl2Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehLftAngl3Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehRtAngl3Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehLftAngl4Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehRtAngl4Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehLftAngl5Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehRtAngl5Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehLftAngl6Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehRtAngl6Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehLftAngl7Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehRtAngl7Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehLftAngl8Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehRtAngl8Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehLftAngl9Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehRtAngl9Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehLftAngl10Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehRtAngl10Val 501 "Not used" 502 "Not used" 503 "Not used" 504 "Not used" 505 "Not used" 506 "Not used" 507 "Not used" 508 "Not used" 509 "Not used" 510 "Default" 511 "Error indicator";
-VAL_ 698 IFSref_VehDst2Val 0 "No Value" 1 "1~10m" 2 "11~20m" 3 "21~30m" 4 "31~40m" 5 "41~50m" 6 "51~60m" 7 "61~70m" 8 "71~80m" 9 "81~90m" 10 "91~100m" 11 "101~200m" 12 "201~300m" 13 "301~400m" 14 "401m~" 15 "Error indicator";
-VAL_ 698 IFSref_VehDst3Val 0 "No Value" 1 "1~10m" 2 "11~20m" 3 "21~30m" 4 "31~40m" 5 "41~50m" 6 "51~60m" 7 "61~70m" 8 "71~80m" 9 "81~90m" 10 "91~100m" 11 "101~200m" 12 "201~300m" 13 "301~400m" 14 "401m~" 15 "Error indicator";
-VAL_ 698 IFSref_VehDst4Val 0 "No Value" 1 "1~10m" 2 "11~20m" 3 "21~30m" 4 "31~40m" 5 "41~50m" 6 "51~60m" 7 "61~70m" 8 "71~80m" 9 "81~90m" 10 "91~100m" 11 "101~200m" 12 "201~300m" 13 "301~400m" 14 "401m~" 15 "Error indicator";
-VAL_ 698 IFSref_VehDst5Val 0 "No Value" 1 "1~10m" 2 "11~20m" 3 "21~30m" 4 "31~40m" 5 "41~50m" 6 "51~60m" 7 "61~70m" 8 "71~80m" 9 "81~90m" 10 "91~100m" 11 "101~200m" 12 "201~300m" 13 "301~400m" 14 "401m~" 15 "Error indicator";
-VAL_ 698 IFSref_VehDst6Val 0 "No Value" 1 "1~10m" 2 "11~20m" 3 "21~30m" 4 "31~40m" 5 "41~50m" 6 "51~60m" 7 "61~70m" 8 "71~80m" 9 "81~90m" 10 "91~100m" 11 "101~200m" 12 "201~300m" 13 "301~400m" 14 "401m~" 15 "Error indicator";
-VAL_ 698 IFSref_VehDst7Val 0 "No Value" 1 "1~10m" 2 "11~20m" 3 "21~30m" 4 "31~40m" 5 "41~50m" 6 "51~60m" 7 "61~70m" 8 "71~80m" 9 "81~90m" 10 "91~100m" 11 "101~200m" 12 "201~300m" 13 "301~400m" 14 "401m~" 15 "Error indicator";
-VAL_ 698 IFSref_VehDst8Val 0 "No Value" 1 "1~10m" 2 "11~20m" 3 "21~30m" 4 "31~40m" 5 "41~50m" 6 "51~60m" 7 "61~70m" 8 "71~80m" 9 "81~90m" 10 "91~100m" 11 "101~200m" 12 "201~300m" 13 "301~400m" 14 "401m~" 15 "Error indicator";
-VAL_ 698 IFSref_VehDst9Val 0 "No Value" 1 "1~10m" 2 "11~20m" 3 "21~30m" 4 "31~40m" 5 "41~50m" 6 "51~60m" 7 "61~70m" 8 "71~80m" 9 "81~90m" 10 "91~100m" 11 "101~200m" 12 "201~300m" 13 "301~400m" 14 "401m~" 15 "Error indicator";
-VAL_ 698 IFSref_VehDst10Val 0 "No Value" 1 "1~10m" 2 "11~20m" 3 "21~30m" 4 "31~40m" 5 "41~50m" 6 "51~60m" 7 "61~70m" 8 "71~80m" 9 "81~90m" 10 "91~100m" 11 "101~200m" 12 "201~300m" 13 "301~400m" 14 "401m~" 15 "Error indicator";
+VAL_ 480 HDA_OptUsmSta 0 "Not Applied" 1 "Function Off" 2 "Function On" 3 "Reserved" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Invalid (Fail)";
+VAL_ 480 LFA_OptUsmSta 0 "Not Applied" 1 "Function Off" 2 "Function On" 3 "Reserved" 4 "Reserved" 5 "Reserved" 6 "Reserved" 7 "Invalid (Fail)";
+VAL_ 480 HDA_CntrlModSta 0 "System Deactive (Default)" 1 "System Ready" 2 "System Active" 3 "Reserved";
+VAL_ 480 HDA_InfoPUDis 0 "No pop-up" 1 "system start pop-up" 2 "system auto disengaged pop-up by highway off" 3 "system auto disengaged pop-up" 4 "system Fail pop-up" 5 "Hands-off pop up" 6 "Hands-off pop up w/ sound" 7 "System Automatic off";
+VAL_ 480 HDA_AutoSetSpdSta 0 "Auto Set Speed Off" 1 "Auto Set Speed On" 2 "Reserved" 3 "Error indicator";
+VAL_ 480 HDA_AutoSetSpdUpdtSta 0 "Auto Set Speed Update Off" 1 "Auto Set Speed Update On" 2 "Reserved" 3 "Error indicator";
+VAL_ 480 HDA_LFA_SymSta 0 "Off" 1 "Gray" 2 "Green" 3 "Green blink";
+VAL_ 480 HDA_LFA_WrnSnd 0 "Off" 1 "Additional Warning Sound" 2 "Reserved" 3 "Error indicator";
+VAL_ 480 HDA_InfoPUDis1 0 "No Pop-up" 1 "System Automatic off (LFA)" 2 "System Automatic off (HDA)" 3 "Reserved" 4 "Reserved" 5 "Reserved" 6 "Not Used" 7 "Error Indicator";
+VAL_ 480 HDA_TDMRMDclReq 0 "Not automatically deactivated state of LFA (default)" 1 "Automatically deactivated state of LFA" 2 "Reserved" 3 "Reserved";
+VAL_ 490 HDA_MODE2 1 "Lane change icon gray" 2 "lane green + lane change icon green" 3 "lane green + lane change icon green (both blinking)" 4 "lane white + lane change icon white (both blinking rapidly)" 5 "Lane Change Assist system check warning";
+VAL_ 490 LANE_LEFT 0 "IDLE" 1 "ON_SOURCE" 2 "ON_TARGET";
+VAL_ 490 LANE_RIGHT 0 "IDLE" 1 "ON_SOURCE" 2 "ON_TARGET";
+VAL_ 490 LANE_CHANGING 0 "IDLE" 1 "LEFT_CHECK" 3 "LEFT_CHANGING" 2 "RIGHT_CHECK" 4 "RIGHT_CHANGING";
+VAL_ 490 LF_DETECT 0 "none" 1 "gray" 2 "white" 3 "white" 4 "hide";
+VAL_ 490 RF_DETECT 0 "none" 1 "gray" 2 "white" 3 "white" 4 "hide";
+VAL_ 490 LR_DETECT 0 "none" 1 "gray" 2 "white" 3 "white" 4 "hide";
+VAL_ 490 RR_DETECT 0 "none" 1 "gray" 2 "white" 3 "white" 4 "hide";
+VAL_ 490 AUTOLANECHANGE_MSG 1 "Check surrounding conditions" 2 "Operating conditions not met" 3 "Analyzing driving lane" 4 "Sharp curve ahead" 5 "Current lane is too narrow" 6 "Not an operational section" 7 "Hazard lights are on" 8 "Vehicle speed is too low" 9 "Please hold the steering wheel" 10 "Not an operable lane" 11 "Steering input detected" 12 "Press the OK button to activate lane change assist";
+VAL_ 490 LANELINE_CURVATURE_DIRECTION 0 "LEFT" 1 "RIGHT";
+VAL_ 676 LEFT_LANE_COLOR 0 "Not Detected" 1 "White" 2 "Yellow" 3 "Blue";
+VAL_ 676 RIGHT_LANE_COLOR 0 "Not Detected" 1 "White" 2 "Yellow" 3 "Blue";
+VAL_ 676 LEFT_LANE_LINE 0 "Not Detected" 1 "Low Confidence" 2 "Medium Confidence" 3 "High Confidence";
+VAL_ 676 RIGHT_LANE_LINE 0 "Not Detected" 1 "Low Confidence" 2 "Medium Confidence" 3 "High Confidence";
VAL_ 736 MSLA_STATUS 0 "disabled" 1 "active" 2 "paused";
+VAL_ 866 LEFT_LANE_COLOR 0 "Not Detected" 1 "White" 2 "Yellow" 3 "Blue";
+VAL_ 866 RIGHT_LANE_COLOR 0 "Not Detected" 1 "White" 2 "Yellow" 3 "Blue";
VAL_ 866 LEFT_LANE_LINE 0 "Not Detected" 1 "Low Confidence" 2 "Medium Confidence" 3 "High Confidence";
VAL_ 866 RIGHT_LANE_LINE 0 "Not Detected" 1 "Low Confidence" 2 "Medium Confidence" 3 "High Confidence";
VAL_ 1041 DRIVER_DOOR 0 "Closed" 1 "Opened";
@@ -985,5 +1101,7 @@ VAL_ 1041 PASSENGER_SEATBELT 0 "Unlatched" 1 "Latched";
VAL_ 1041 DRIVER_SEATBELT 0 "Unlatched" 1 "Latched";
VAL_ 1041 DRIVER_REAR_DOOR 0 "Closed" 1 "Opened";
VAL_ 1041 PASSENGER_REAR_DOOR 0 "Closed" 1 "Opened";
+VAL_ 1079 TRAILER_CONNECTED 1 "CONNECTED" 0 "DISCONNECTED";
+
VAL_ 1144 DRIVE_MODE2 3 "Set Sport" 1 "Set Normal" 2 "Set Eco";
VAL_ 1240 DISTANCE_UNIT 1 "Miles" 0 "Kilometers";
diff --git a/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_180.dbc b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_180.dbc
new file mode 100644
index 0000000..a78803a
--- /dev/null
+++ b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_180.dbc
@@ -0,0 +1,140 @@
+VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ ENVVAR_TYPE_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ VAL_TABLE_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX RADAR
+
+BA_DEF_ BO_ "GenMsgCycleTime" INT 0 100000;
+BA_DEF_DEF_ "GenMsgCycleTime" 0;
+
+BO_ 384 CORNER_RADAR_180_OBJECTS_180: 32 RADAR
+ SG_ SLOT1_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ SLOT1_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ SLOT1_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ SLOT1_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ SLOT1_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ SLOT1_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ SLOT1_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+ SG_ SLOT2_QUAL_LEVEL : 152|7@1+ (1,0) [0|100] "%" XXX
+ SG_ SLOT2_AGE : 160|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_OBJECT_ID : 172|7@1+ (1,0) [0|127] "" XXX
+ SG_ SLOT2_REL_POS_X : 192|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ SLOT2_REL_POS_Y : 206|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ SLOT2_REL_VEL_X : 219|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ SLOT2_REL_VEL_Y : 232|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ SLOT2_REL_ACCEL_X : 243|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 384 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 384 30;
+
+BO_ 385 CORNER_RADAR_180_OBJECTS_181: 32 RADAR
+ SG_ SLOT1_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ SLOT1_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ SLOT1_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ SLOT1_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ SLOT1_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ SLOT1_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ SLOT1_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+ SG_ SLOT2_QUAL_LEVEL : 152|7@1+ (1,0) [0|100] "%" XXX
+ SG_ SLOT2_AGE : 160|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_OBJECT_ID : 172|7@1+ (1,0) [0|127] "" XXX
+ SG_ SLOT2_REL_POS_X : 192|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ SLOT2_REL_POS_Y : 206|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ SLOT2_REL_VEL_X : 219|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ SLOT2_REL_VEL_Y : 232|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ SLOT2_REL_ACCEL_X : 243|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 385 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 385 30;
+
+BO_ 386 CORNER_RADAR_180_OBJECTS_182: 32 RADAR
+ SG_ SLOT1_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ SLOT1_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ SLOT1_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ SLOT1_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ SLOT1_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ SLOT1_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ SLOT1_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+ SG_ SLOT2_QUAL_LEVEL : 152|7@1+ (1,0) [0|100] "%" XXX
+ SG_ SLOT2_AGE : 160|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_OBJECT_ID : 172|7@1+ (1,0) [0|127] "" XXX
+ SG_ SLOT2_REL_POS_X : 192|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ SLOT2_REL_POS_Y : 206|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ SLOT2_REL_VEL_X : 219|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ SLOT2_REL_VEL_Y : 232|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ SLOT2_REL_ACCEL_X : 243|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 386 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 386 30;
+
+BO_ 387 CORNER_RADAR_180_OBJECTS_183: 32 RADAR
+ SG_ SLOT1_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ SLOT1_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ SLOT1_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ SLOT1_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ SLOT1_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ SLOT1_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ SLOT1_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+ SG_ SLOT2_QUAL_LEVEL : 152|7@1+ (1,0) [0|100] "%" XXX
+ SG_ SLOT2_AGE : 160|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_OBJECT_ID : 172|7@1+ (1,0) [0|127] "" XXX
+ SG_ SLOT2_REL_POS_X : 192|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ SLOT2_REL_POS_Y : 206|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ SLOT2_REL_VEL_X : 219|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ SLOT2_REL_VEL_Y : 232|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ SLOT2_REL_ACCEL_X : 243|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 387 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 387 30;
+
+BO_ 388 CORNER_RADAR_180_OBJECTS_184: 32 RADAR
+ SG_ SLOT1_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ SLOT1_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ SLOT1_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ SLOT1_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ SLOT1_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ SLOT1_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ SLOT1_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+ SG_ SLOT2_QUAL_LEVEL : 152|7@1+ (1,0) [0|100] "%" XXX
+ SG_ SLOT2_AGE : 160|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_OBJECT_ID : 172|7@1+ (1,0) [0|127] "" XXX
+ SG_ SLOT2_REL_POS_X : 192|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ SLOT2_REL_POS_Y : 206|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ SLOT2_REL_VEL_X : 219|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ SLOT2_REL_VEL_Y : 232|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ SLOT2_REL_ACCEL_X : 243|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 388 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 388 30;
diff --git a/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_180.py b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_180.py
new file mode 100755
index 0000000..d7bf650
--- /dev/null
+++ b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_180.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+import os
+
+
+HEADER = """VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ ENVVAR_TYPE_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ VAL_TABLE_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX RADAR
+
+"""
+
+
+def write_object_msg(f, addr):
+ name = f"CORNER_RADAR_180_OBJECTS_{addr:x}"
+ f.write(f"""
+BO_ {addr} {name}: 32 RADAR
+ SG_ SLOT1_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ SLOT1_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ SLOT1_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ SLOT1_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ SLOT1_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ SLOT1_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ SLOT1_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+ SG_ SLOT2_QUAL_LEVEL : 152|7@1+ (1,0) [0|100] "%" XXX
+ SG_ SLOT2_AGE : 160|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_OBJECT_ID : 172|7@1+ (1,0) [0|127] "" XXX
+ SG_ SLOT2_REL_POS_X : 192|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ SLOT2_REL_POS_Y : 206|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ SLOT2_REL_VEL_X : 219|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ SLOT2_REL_VEL_Y : 232|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ SLOT2_REL_ACCEL_X : 243|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+""")
+
+ f.write(f"""CM_ BO_ {addr} "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ {addr} 30;
+""")
+
+
+if __name__ == "__main__":
+ dbc_name = os.path.basename(__file__).replace(".py", ".dbc")
+ out_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), dbc_name)
+ with open(out_path, "w", encoding="ascii") as f:
+ f.write(HEADER)
+ f.write('BA_DEF_ BO_ "GenMsgCycleTime" INT 0 100000;\n')
+ f.write('BA_DEF_DEF_ "GenMsgCycleTime" 0;\n')
+ for addr in range(0x180, 0x185):
+ write_object_msg(f, addr)
diff --git a/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_235.dbc b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_235.dbc
new file mode 100644
index 0000000..f622a76
--- /dev/null
+++ b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_235.dbc
@@ -0,0 +1,278 @@
+VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX RADAR
+
+BA_DEF_ BO_ "GenMsgCycleTime" INT 0 100000;
+BA_DEF_DEF_ "GenMsgCycleTime" 0;
+
+BO_ 565 CORNER_RADAR_235_OBJECTS_235: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 565 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 565 30;
+
+BO_ 566 CORNER_RADAR_235_OBJECTS_236: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 566 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 566 30;
+
+BO_ 567 CORNER_RADAR_235_OBJECTS_237: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 567 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 567 30;
+
+BO_ 568 CORNER_RADAR_235_OBJECTS_238: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 568 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 568 30;
+
+BO_ 569 CORNER_RADAR_235_OBJECTS_239: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 569 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 569 30;
+
+BO_ 570 CORNER_RADAR_235_OBJECTS_23a: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 570 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 570 30;
+
+BO_ 571 CORNER_RADAR_235_OBJECTS_23b: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 571 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 571 30;
+
+BO_ 572 CORNER_RADAR_235_OBJECTS_23c: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 572 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 572 30;
+
+BO_ 573 CORNER_RADAR_235_OBJECTS_23d: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 573 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 573 30;
+
+BO_ 574 CORNER_RADAR_235_OBJECTS_23e: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 574 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 574 30;
+
+BO_ 575 CORNER_RADAR_235_OBJECTS_23f: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 575 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 575 30;
+
+BO_ 576 CORNER_RADAR_235_OBJECTS_240: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 576 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 576 30;
+
+BO_ 577 CORNER_RADAR_235_OBJECTS_241: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 577 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 577 30;
+
+BO_ 578 CORNER_RADAR_235_OBJECTS_242: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 578 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 578 30;
+
+BO_ 579 CORNER_RADAR_235_OBJECTS_243: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 579 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 579 30;
+
+BO_ 580 CORNER_RADAR_235_OBJECTS_244: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 580 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 580 30;
+
+BO_ 581 CORNER_RADAR_235_OBJECTS_245: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 581 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 581 30;
+
+BO_ 582 CORNER_RADAR_235_OBJECTS_246: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 582 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 582 30;
+
+BO_ 583 CORNER_RADAR_235_OBJECTS_247: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 583 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 583 30;
+
+BO_ 584 CORNER_RADAR_235_OBJECTS_248: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+CM_ BO_ 584 "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ 584 30;
diff --git a/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_235.py b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_235.py
new file mode 100755
index 0000000..6092d0d
--- /dev/null
+++ b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_235.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python3
+import os
+
+
+HEADER = """VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX RADAR
+
+"""
+
+
+def write_object_msg(f, addr):
+ name = f"CORNER_RADAR_235_OBJECTS_{addr:x}"
+ f.write(f"""
+BO_ {addr} {name}: 32 RADAR
+ SG_ OBJ_QUAL_LEVEL : 24|7@1+ (1,0) [0|100] "%" XXX
+ SG_ OBJ_AGE : 32|8@1+ (1,0) [0|255] "" XXX
+ SG_ OBJ_OBJECT_ID : 44|7@1+ (1,0) [0|127] "" XXX
+ SG_ OBJ_REL_POS_X : 64|13@1+ (0.05,0) [0|409.55] "m" XXX
+ SG_ OBJ_REL_POS_Y : 78|12@1+ (0.05,-102.4) [-102.4|102.35] "m" XXX
+ SG_ OBJ_REL_VEL_X : 91|12@1+ (0.05,-100) [-100|104.75] "m/s" XXX
+ SG_ OBJ_REL_VEL_Y : 104|10@1+ (0.05,-25) [-25|26.15] "m/s" XXX
+ SG_ OBJ_REL_ACCEL_X : 115|9@1- (0.05,0) [-12.8|12.75] "m/s^2" XXX
+""")
+
+ f.write(f"""CM_ BO_ {addr} "Corner radar object payload on bus 1. Only signals consumed by Hyundai radar_interface are defined.";
+BA_ "GenMsgCycleTime" BO_ {addr} 30;
+""")
+
+
+if __name__ == "__main__":
+ dbc_name = os.path.basename(__file__).replace(".py", ".dbc")
+ out_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), dbc_name)
+ with open(out_path, "w", encoding="ascii") as f:
+ f.write(HEADER)
+ f.write('BA_DEF_ BO_ "GenMsgCycleTime" INT 0 100000;\n')
+ f.write('BA_DEF_DEF_ "GenMsgCycleTime" 0;\n')
+ for addr in range(0x235, 0x249):
+ write_object_msg(f, addr)
diff --git a/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_430.dbc b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_430.dbc
new file mode 100644
index 0000000..528b741
--- /dev/null
+++ b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_430.dbc
@@ -0,0 +1,614 @@
+VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX RADAR
+
+BA_DEF_ BO_ "GenMsgCycleTime" INT 0 100000;
+BA_DEF_DEF_ "GenMsgCycleTime" 0;
+
+BO_ 1072 CORNER_RADAR_430_OBJECTS_430: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1072 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1072 30;
+
+BO_ 1073 CORNER_RADAR_430_OBJECTS_431: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1073 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1073 30;
+
+BO_ 1074 CORNER_RADAR_430_OBJECTS_432: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1074 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1074 30;
+
+BO_ 1075 CORNER_RADAR_430_OBJECTS_433: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1075 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1075 30;
+
+BO_ 1076 CORNER_RADAR_430_OBJECTS_434: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1076 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1076 30;
+
+BO_ 1077 CORNER_RADAR_430_OBJECTS_435: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1077 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1077 30;
+
+BO_ 1078 CORNER_RADAR_430_OBJECTS_436: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1078 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1078 30;
+
+BO_ 1079 CORNER_RADAR_430_OBJECTS_437: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1079 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1079 30;
+
+BO_ 1088 CORNER_RADAR_430_OBJECTS_440: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1088 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1088 30;
+
+BO_ 1089 CORNER_RADAR_430_OBJECTS_441: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1089 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1089 30;
+
+BO_ 1090 CORNER_RADAR_430_OBJECTS_442: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1090 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1090 30;
+
+BO_ 1091 CORNER_RADAR_430_OBJECTS_443: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1091 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1091 30;
+
+BO_ 1092 CORNER_RADAR_430_OBJECTS_444: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1092 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1092 30;
+
+BO_ 1093 CORNER_RADAR_430_OBJECTS_445: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1093 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1093 30;
+
+BO_ 1094 CORNER_RADAR_430_OBJECTS_446: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1094 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1094 30;
+
+BO_ 1095 CORNER_RADAR_430_OBJECTS_447: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_DISTANCE_RAW : 32|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT1_META_13_15 : 45|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT1_META_BYTE_2 : 48|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT1_META_BYTE_3 : 56|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_DISTANCE_RAW : 64|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT2_META_13_15 : 77|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT2_META_BYTE_2 : 80|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT2_META_BYTE_3 : 88|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_DISTANCE_RAW : 96|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT3_META_13_15 : 109|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT3_META_BYTE_2 : 112|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT3_META_BYTE_3 : 120|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_DISTANCE_RAW : 128|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT4_META_13_15 : 141|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT4_META_BYTE_2 : 144|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT4_META_BYTE_3 : 152|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_DISTANCE_RAW : 160|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT5_META_13_15 : 173|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT5_META_BYTE_2 : 176|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT5_META_BYTE_3 : 184|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_DISTANCE_RAW : 192|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT6_META_13_15 : 205|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT6_META_BYTE_2 : 208|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT6_META_BYTE_3 : 216|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_DISTANCE_RAW : 224|13@1+ (1,0) [0|8191] "" XXX
+ SG_ SLOT7_META_13_15 : 237|3@1+ (1,0) [0|7] "" XXX
+ SG_ SLOT7_META_BYTE_2 : 240|8@1+ (1,0) [0|255] "" XXX
+ SG_ SLOT7_META_BYTE_3 : 248|8@1+ (1,0) [0|255] "" XXX
+CM_ BO_ 1095 "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ 1095 30;
diff --git a/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_430.py b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_430.py
new file mode 100755
index 0000000..d663db7
--- /dev/null
+++ b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_corner_radar_430.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python3
+import os
+
+
+HEADER = """VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX RADAR
+
+"""
+
+
+def write_object_msg(f, addr):
+ name = f"CORNER_RADAR_430_OBJECTS_{addr:x}"
+ f.write(f"""
+BO_ {addr} {name}: 32 RADAR
+ SG_ HEADER_BYTE_0 : 0|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_1 : 8|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_2 : 16|8@1+ (1,0) [0|255] "" XXX
+ SG_ HEADER_BYTE_3 : 24|8@1+ (1,0) [0|255] "" XXX
+""")
+ for slot in range(7):
+ bit = 32 + slot * 32
+ prefix = f"SLOT{slot + 1}"
+ f.write(f""" SG_ {prefix}_DISTANCE_RAW : {bit}|13@1+ (1,0) [0|8191] "" XXX
+ SG_ {prefix}_META_13_15 : {bit + 13}|3@1+ (1,0) [0|7] "" XXX
+ SG_ {prefix}_META_BYTE_2 : {bit + 16}|8@1+ (1,0) [0|255] "" XXX
+ SG_ {prefix}_META_BYTE_3 : {bit + 24}|8@1+ (1,0) [0|255] "" XXX
+""")
+ f.write(f"""CM_ BO_ {addr} "IONIQ 9 candidate corner radar bin container. 0x430-0x437 correlate with left side and 0x440-0x447 with right side. Bytes 4-31 appear as seven 4-byte slots; lower 13 bits are a distance candidate at 0.05 m scale. This DBC intentionally exposes only raw candidate fields until lateral and velocity fields are validated.";
+BA_ "GenMsgCycleTime" BO_ {addr} 30;
+""")
+
+
+if __name__ == "__main__":
+ dbc_name = os.path.basename(__file__).replace(".py", ".dbc")
+ out_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), dbc_name)
+ with open(out_path, "w", encoding="ascii") as f:
+ f.write(HEADER)
+ f.write('BA_DEF_ BO_ "GenMsgCycleTime" INT 0 100000;\n')
+ f.write('BA_DEF_DEF_ "GenMsgCycleTime" 0;\n')
+ for addr in range(0x430, 0x438):
+ write_object_msg(f, addr)
+ for addr in range(0x440, 0x448):
+ write_object_msg(f, addr)
diff --git a/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_radar.dbc b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_radar.dbc
new file mode 100644
index 0000000..46c3032
--- /dev/null
+++ b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_radar.dbc
@@ -0,0 +1,1178 @@
+
+VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ VAL_TABLE_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX
+
+BO_ 528 RADAR_TRACK_210: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 529 RADAR_TRACK_211: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 530 RADAR_TRACK_212: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 531 RADAR_TRACK_213: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 532 RADAR_TRACK_214: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 533 RADAR_TRACK_215: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 534 RADAR_TRACK_216: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 535 RADAR_TRACK_217: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 536 RADAR_TRACK_218: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 537 RADAR_TRACK_219: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 538 RADAR_TRACK_21a: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 539 RADAR_TRACK_21b: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 540 RADAR_TRACK_21c: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 541 RADAR_TRACK_21d: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 542 RADAR_TRACK_21e: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 543 RADAR_TRACK_21f: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 933 RADAR_TRACK_3a5: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 934 RADAR_TRACK_3a6: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 935 RADAR_TRACK_3a7: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 936 RADAR_TRACK_3a8: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 937 RADAR_TRACK_3a9: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 938 RADAR_TRACK_3aa: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 939 RADAR_TRACK_3ab: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 940 RADAR_TRACK_3ac: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 941 RADAR_TRACK_3ad: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 942 RADAR_TRACK_3ae: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 943 RADAR_TRACK_3af: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 944 RADAR_TRACK_3b0: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 945 RADAR_TRACK_3b1: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 946 RADAR_TRACK_3b2: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 947 RADAR_TRACK_3b3: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 948 RADAR_TRACK_3b4: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 949 RADAR_TRACK_3b5: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 950 RADAR_TRACK_3b6: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 951 RADAR_TRACK_3b7: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 952 RADAR_TRACK_3b8: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 953 RADAR_TRACK_3b9: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 954 RADAR_TRACK_3ba: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 955 RADAR_TRACK_3bb: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 956 RADAR_TRACK_3bc: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 957 RADAR_TRACK_3bd: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 958 RADAR_TRACK_3be: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 959 RADAR_TRACK_3bf: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 960 RADAR_TRACK_3c0: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 961 RADAR_TRACK_3c1: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 962 RADAR_TRACK_3c2: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 963 RADAR_TRACK_3c3: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 964 RADAR_TRACK_3c4: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+
+BO_ 1024 RADAR_TRACK_400: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1025 RADAR_TRACK_401: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1026 RADAR_TRACK_402: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1027 RADAR_TRACK_403: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1028 RADAR_TRACK_404: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1029 RADAR_TRACK_405: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1030 RADAR_TRACK_406: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1031 RADAR_TRACK_407: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1032 RADAR_TRACK_408: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1033 RADAR_TRACK_409: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1034 RADAR_TRACK_40a: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1035 RADAR_TRACK_40b: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1036 RADAR_TRACK_40c: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1037 RADAR_TRACK_40d: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1038 RADAR_TRACK_40e: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1039 RADAR_TRACK_40f: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1040 RADAR_TRACK_410: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1041 RADAR_TRACK_411: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1042 RADAR_TRACK_412: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1043 RADAR_TRACK_413: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1044 RADAR_TRACK_414: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1045 RADAR_TRACK_415: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1046 RADAR_TRACK_416: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1047 RADAR_TRACK_417: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1048 RADAR_TRACK_418: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1049 RADAR_TRACK_419: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1050 RADAR_TRACK_41a: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1051 RADAR_TRACK_41b: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1052 RADAR_TRACK_41c: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
+BO_ 1053 RADAR_TRACK_41d: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+
\ No newline at end of file
diff --git a/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_radar.py b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_radar.py
new file mode 100755
index 0000000..f3abf2e
--- /dev/null
+++ b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_canfd_radar.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python3
+import os
+
+if __name__ == "__main__":
+ dbc_name = os.path.basename(__file__).replace(".py", ".dbc")
+ hyundai_path = os.path.dirname(os.path.realpath(__file__))
+ with open(os.path.join(hyundai_path, dbc_name), "w", encoding='utf-8') as f:
+ f.write("""
+VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ VAL_TABLE_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX
+ """)
+
+ for a in range(0x210, 0x210 + 16):
+ f.write(f"""
+BO_ {a} RADAR_TRACK_{a:x}: 32 RADAR
+ SG_ NEW_SIGNAL_25 : 26|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_24 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_21 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_20 : 39|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT1 : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_15 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_14 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_5 : 63|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST1 : 64|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST1 : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED1 : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_16 : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED1 : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL1 : 118|10@1- (0.05,0) [0|1023] "" XXX
+ SG_ NEW_SIGNAL_27 : 154|3@0+ (1,0) [0|7] "" XXX
+ SG_ NEW_SIGNAL_26 : 156|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_23 : 164|5@0+ (1,0) [0|31] "" XXX
+ SG_ NEW_SIGNAL_22 : 167|3@0+ (1,0) [0|7] "" XXX
+ SG_ VALID_CNT2 : 175|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_13 : 179|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_12 : 183|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_11 : 191|8@0- (1,0) [0|255] "" XXX
+ SG_ LONG_DIST2 : 192|12@1+ (0.05,0) [0|4095] "" XXX
+ SG_ LAT_DIST2 : 204|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED2 : 216|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ NEW_SIGNAL_17 : 231|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED2 : 232|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL2 : 246|10@1- (0.05,0) [0|1023] "" XXX
+ """)
+ for a in range(0x3a5, 0x3a5 + 32):
+ f.write(f"""
+BO_ {a} RADAR_TRACK_{a:x}: 24 RADAR
+ SG_ VALID : 25|2@0+ (1,0) [0|3] "" XXX
+ SG_ VALID2 : 28|2@0+ (1,0) [0|3] "" XXX
+ SG_ PROB : 30|10@1+ (1,0) [0|1023] "" XXX
+ SG_ VALID_CNT : 47|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_7 : 51|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_6 : 55|4@0+ (1,0) [0|15] "" XXX
+ SG_ NEW_SIGNAL_2 : 62|7@0- (1,0) [0|127] "" XXX
+ SG_ LONG_DIST : 63|13@1+ (0.05,0) [0|8191] "" XXX
+ SG_ LAT_DIST : 76|12@1- (0.05,0) [0|4095] "" XXX
+ SG_ REL_SPEED : 88|14@1- (0.01,0) [0|16383] "" XXX
+ SG_ IN_MYLANE : 103|2@0+ (1,0) [0|3] "" XXX
+ SG_ LAT_SPEED : 104|13@1- (0.01,0) [0|8191] "" XXX
+ SG_ REL_ACCEL : 118|10@1- (0.05,0) [0|1023] "" XXX
+ """)
+
+ # Group 3 radar object list:
+ # 30 one-object messages at 20 Hz, with an empty distance sentinel of 0x7ff.
+ for a in range(0x400, 0x400 + 30):
+ f.write(f"""
+BO_ {a} RADAR_TRACK_{a:x}: 24 RADAR
+ SG_ OBJECT_LENGTH : 41|7@1+ (0.1,0) [0|12.7] "m" XXX
+ SG_ LONG_DIST : 64|11@1+ (0.1,0) [0|204.7] "m" XXX
+ SG_ LAT_DIST : 75|12@1- (0.05,0) [-102.4|102.35] "m" XXX
+ SG_ REL_SPEED : 87|11@1- (0.1,0) [-102.4|102.3] "m/s" XXX
+ """)
diff --git a/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_kia_denso_front_radar.py b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_kia_denso_front_radar.py
new file mode 100755
index 0000000..d00e5d3
--- /dev/null
+++ b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_kia_denso_front_radar.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+import os
+
+
+if __name__ == "__main__":
+ dbc_name = os.path.basename(__file__).replace(".py", ".dbc")
+ hyundai_path = os.path.dirname(os.path.realpath(__file__))
+ with open(os.path.join(hyundai_path, dbc_name), "w", encoding="utf-8") as f:
+ f.write("""
+VERSION ""
+
+
+NS_ :
+ NS_DESC_
+ CM_
+ BA_DEF_
+ BA_
+ VAL_
+ CAT_DEF_
+ CAT_
+ FILTER
+ BA_DEF_DEF_
+ EV_DATA_
+ ENVVAR_DATA_
+ SGTYPE_
+ SGTYPE_VAL_
+ BA_DEF_SGTYPE_
+ BA_SGTYPE_
+ SIG_TYPE_REF_
+ VAL_TABLE_
+ SIG_GROUP_
+ SIG_VALTYPE_
+ SIGTYPE_VALTYPE_
+ BO_TX_BU_
+ BA_DEF_REL_
+ BA_REL_
+ BA_DEF_DEF_REL_
+ BU_SG_REL_
+ BU_EV_REL_
+ BU_BO_REL_
+ SG_MUL_VAL_
+
+BS_:
+
+BU_: XXX
+""")
+
+ # EN: The Denso DNMWR006 radar in the 2018-2019 Kia Sorento UM publishes
+ # eight stable tracked objects at 20 Hz from 0x500 through 0x507.
+ # Do not decode 0x508+ distance-sorted raw detections as stable tracks.
+ # KO: 2018-2019 Kia Sorento UM의 Denso DNMWR006 레이더는 0x500~0x507에서
+ # 안정적인 추적 객체 8개를 20Hz로 전송함. 0x508 이후의 거리순 raw
+ # detection은 안정적인 트랙으로 디코딩하지 않음.
+ for address in range(0x500, 0x508):
+ f.write(f"""
+BO_ {address} RADAR_TRACK_{address:x}: 8 RADAR
+ SG_ COUNTER : 7|8@0+ (1,0) [0|255] "" XXX
+ SG_ LONG_DIST : 15|16@0+ (0.00625,0) [0|409.59375] "m" XXX
+ SG_ LAT_DIST : 31|11@0- (0.0625,0) [-64|63.9375] "m" XXX
+ SG_ OBJECT_FLAGS_1 : 36|5@0+ (1,0) [0|31] "" XXX
+ SG_ OBJECT_FLAG_2 : 47|1@0+ (1,0) [0|1] "" XXX
+ SG_ REL_SPEED : 46|12@0- (0.015625,0) [-32|31.984375] "m/s" XXX
+ SG_ OBJECT_STATE : 50|3@0+ (1,0) [0|7] "" XXX
+ SG_ OBJECT_DETAIL : 63|8@0+ (1,0) [0|255] "" XXX
+""")
diff --git a/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_palisade_2023.dbc b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_palisade_2023.dbc
index 68f5d60..b8ecca7 100644
--- a/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_palisade_2023.dbc
+++ b/iqdbc_repo/iqdbc/dbc/generator/hyundai/hyundai_palisade_2023.dbc
@@ -1,4 +1,4 @@
-CM_ "IMPORT _hyundai_canfd_common.dbc";
+CM_ "IMPORT _hyundai_common.dbc";
BO_ 67 DATC13: 8 XXX
SG_ CF_Datc_AcDisp : 22|2@1+ (1,0) [0|0] "" XXX
diff --git a/iqdbc_repo/iqdbc/dbc/hyundai_kia_generic.dbc b/iqdbc_repo/iqdbc/dbc/hyundai_kia_generic.dbc
index 6a67700..b3bde5f 100644
--- a/iqdbc_repo/iqdbc/dbc/hyundai_kia_generic.dbc
+++ b/iqdbc_repo/iqdbc/dbc/hyundai_kia_generic.dbc
@@ -1341,6 +1341,17 @@ BO_ 273 TCU11: 8 TCU
BO_ 16 ACU13: 8 ACU
SG_ CF_Acu_CshAct : 0|1@1+ (1.0,0.0) [0.0|1.0] "" CUBIS,IBOX,ODS
+BO_ 1007 CRUISE_BUTTON_ALT: 8 XXX
+ SG_ SET_ME_1 : 52|1@0+ (1,0) [0|1] "" XXX
+ SG_ CruiseSwMain : 58|1@0+ (1,0) [0|1] "" XXX
+ SG_ CruiseSwState : 60|3@1+ (1,0) [0|7] "" XXX
+
+BO_ 1046 CRUISE_BUTTON_LFA: 8 XXX
+ SG_ NEW_SIGNAL_2 : 49|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_1 : 54|1@0+ (1,0) [0|1] "" XXX
+ SG_ NEW_SIGNAL_3 : 57|1@0+ (1,0) [0|1] "" XXX
+ SG_ CruiseSwLfa : 58|1@0+ (1,0) [0|1] "" XXX
+
BO_ 1040 CGW_USM1: 8 BCM
SG_ CF_Gway_ATTurnRValue : 0|2@1+ (1.0,0.0) [0.0|3.0] "" CLU
SG_ CF_Gway_PTGMRValue : 2|2@1+ (1.0,0.0) [0.0|3.0] "" CLU
@@ -1384,6 +1395,8 @@ BO_ 1290 SCC13: 8 SCC
SG_ SCC_Equip : 3|1@1+ (1,0) [0|1] "" ESC
SG_ AebDrvSetStatus : 4|3@1+ (1,0) [0|7] "" CLU,ESC
SG_ Lead_Veh_Dep_Alert_USM : 13|2@0+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_1 : 23|8@0+ (1,0) [0|255] "" XXX
+ SG_ NEW_SIGNAL_2 : 31|8@0+ (1,0) [0|255] "" XXX
BO_ 1287 TCS15: 4 ESC
SG_ ABS_W_LAMP : 0|1@1+ (1.0,0.0) [0.0|1.0] "" _4WD,CLU,CUBIS,IBOX
@@ -1478,18 +1491,21 @@ BO_ 905 SCC14: 8 SCC
SG_ ComfortBandLower : 6|6@1+ (0.02,0) [0|1.26] "m/s^2" ESC
SG_ JerkUpperLimit : 12|7@1+ (0.1,0) [0|12.7] "m/s^3" ESC
SG_ JerkLowerLimit : 19|7@1+ (0.1,0) [0|12.7] "m/s^3" ESC
+ SG_ NEW_SIGNAL_1 : 26|6@1+ (1,0) [0|63] "" XXX
SG_ ACCMode : 32|3@1+ (1,0) [0|7] "" CLU,HUD,LDWS_LKAS,ESC
- SG_ ObjGap : 56|8@1+ (1,0) [0|255] "" CLU,HUD,ESC
SG_ ObjDistStat : 42|2@1+ (1,0) [0|3] "" XXX
+ SG_ NEW_SIGNAL_2 : 55|8@0+ (1,0) [0|255] "" XXX
+ SG_ ObjGap : 56|8@1+ (1,0) [0|255] "" CLU,HUD,ESC
-BO_ 1157 LFAHDA_MFC: 4 XXX
+BO_ 1157 LFAHDA_MFC: 8 XXX
SG_ HDA_USM : 0|2@1+ (1,0) [0|3] "" XXX
SG_ HDA_Active : 2|1@1+ (1,0) [0|1] "" XXX
SG_ HDA_Icon_State : 3|2@1+ (1,0) [0|3] "" XXX
SG_ HDA_Chime : 7|1@1+ (1,0) [0|1] "" XXX
SG_ HDA_VSetReq : 8|8@1+ (1,0) [0|255] "km/h" XXX
SG_ LFA_SysWarning : 16|3@1+ (1,0) [0|7] "" XXX
- SG_ NEW_SIGNAL_1 : 20|3@1+ (1,0) [0|7] "" XXX
+ SG_ HDA_Icon_Wheel : 20|1@1+ (1,0) [0|1] "" XXX
+ SG_ HDA_LdwSysState : 21|2@1+ (1,0) [0|3] "" XXX
SG_ LFA_Icon_State : 24|2@1+ (1,0) [0|3] "" XXX
SG_ LFA_USM : 27|2@1+ (1,0) [0|3] "" XXX
SG_ HDA_SysWarning : 29|2@1+ (1,0) [0|3] "" XXX
@@ -1497,11 +1513,10 @@ BO_ 1157 LFAHDA_MFC: 4 XXX
BO_ 913 BCM_PO_11: 8 Vector__XXX
SG_ BCM_Door_Dri_Status : 5|1@0+ (1,0) [0|1] "" PT_ESC_ABS
SG_ BCM_Shift_R_MT_SW_Status : 39|2@0+ (1,0) [0|3] "" PT_ESC_ABS
- SG_ LDA_BTN : 4|1@0+ (1,0) [0|1] "" XXX
+ SG_ LFA_Pressed : 4|1@0+ (1,0) [0|1] "" XXX
BO_ 1426 LABEL11: 8 XXX
SG_ CC_React : 34|1@1+ (1,0) [0|1] "" XXX
- SG_ CC_ACT : 35|1@1+ (1,0) [0|1] "" XXX
BO_ 910 WHL_SPD12_FS: 5 iBAU
SG_ CRC : 0|8@1+ (1,0) [0|0] "" Vector__XXX
@@ -1522,7 +1537,10 @@ BO_ 865 ADAS_PRK_11: 8 ADAS_PRK
SG_ PCA_CHECK_SUM : 48|8@1+ (1,0) [0|0] "" Vector__XXX
BO_ 882 ELECT_GEAR: 8 XXX
- SG_ Elect_Gear_Shifter : 16|4@1+ (1,0) [0|7] "" CLU
+ SG_ Elect_Gear_Shifter : 16|4@1+ (1,0) [0|7] "" CLU
+ SG_ Elect_Gear_Shifter_NEXO : 16|16@1+ (1,0) [0|65535] "" CLU
+ SG_ Elect_Gear_Step : 22|3@0+ (1,0) [0|7] "" XXX
+ SG_ Elect_Motor_Speed : 0|8@1+ (1,0) [0|255] "" XXX
SG_ SLC_ON : 31|1@0+ (1,0) [0|1] "" CLU
SG_ SLC_SET_SPEED : 32|8@1+ (1,0) [0|255] "" CLU
@@ -1534,14 +1552,12 @@ BO_ 881 E_EMS11: 8 XXX
SG_ Cruise_Limit_Target : 23|8@1+ (1,0) [0|15] "" XXX
SG_ Accel_Pedal_Pos : 31|8@1+ (1,0) [0|254] "" XXX
SG_ CR_Vcu_AccPedDep_Pos : 56|8@1+ (1,0) [0|254] "" XXX
+ SG_ Engine_Run : 14|1@0+ (1,0) [0|1] "" XXX
+ SG_ N : 18|13@1+ (1,0) [0|15] "" XXX
BO_ 1355 EV_PC6: 8 CGW
SG_ CF_Vcu_SbwWarnMsg : 16|3@1+ (1,0) [0|7] "" Vector__XXX
-BO_ 1429 E_CRUISE_CONTROL: 8 XXX
- SG_ CRUISE_LAMP_M : 50|1@0+ (1,0) [0|1] "" XXX
- SG_ CRUISE_LAMP_S : 51|1@0+ (1,0) [0|1] "" XXX
-
BO_ 1430 EV_PC2: 8 CGW
SG_ CR_Ldc_ActVol_LS_V : 32|8@1+ (0.1,0) [0|0] "V" Vector__XXX
@@ -1584,7 +1600,7 @@ BO_ 352 AHB1: 8 iBAU
SG_ CF_Ahb_Bzzr : 26|1@1+ (1,0) [0|1] "" Vector__XXX
SG_ CF_Ahb_ChkSum : 56|8@1+ (1,0) [0|255] "" Vector__XXX
-BO_ 1191 MFC_4a7: 8 XXX
+BO_ 1191 MFC_4a7: 2 XXX
SG_ PAINT1 : 0|1@0+ (1,0) [0|1] "" XXX
BO_ 1162 BCA11: 8 BCW
@@ -1658,33 +1674,22 @@ BO_ 1348 Navi_HU: 8 XXX
SG_ SpeedLim_Nav_General : 29|1@0+ (1,0) [0|1] "" XXX
SG_ SpeedLim_Nav_Cam : 30|1@0+ (1,0) [0|1] "" XXX
-BO_ 683 ESCC: 8 XXX
- SG_ FCA_CmdAct : 0|1@1+ (1,0) [0|1] "" ESC
- SG_ CF_VSM_Warn_FCA11 : 1|2@1+ (1,0) [0|3] "" ACU,CLU,ESC
- SG_ AEB_CmdAct : 3|1@1+ (1,0) [0|1] "" ESC
- SG_ CF_VSM_Warn_SCC12 : 4|2@1+ (1,0) [0|3] "" CLU,ESC,IAP
- SG_ CF_VSM_DecCmdAct_SCC12 : 6|1@1+ (1,0) [0|1] "" ESC
- SG_ CF_VSM_DecCmdAct_FCA11 : 7|1@1+ (1,0) [0|1] "" ESC
- SG_ CR_VSM_DecCmd_SCC12 : 8|8@1+ (0.01,0) [0|2.55] "g" ESC
- SG_ ObjValid : 16|1@1+ (1,0) [0|1] "" CLU,ESC,TCU
- SG_ ACC_ObjStatus : 17|2@1+ (1,0) [0|3] "" ABS,ESC
- SG_ ACC_ObjLatPos : 24|9@1+ (0.1,-20) [-20|31.1] "m" ABS,ESC
- SG_ ACC_ObjRelSpd : 44|12@1+ (0.1,-170) [-170|239.5] "m/s" ABS,ESC
- SG_ ACC_ObjDist : 33|11@1+ (0.1,0) [0|204.7] "m" ABS,ESC
- SG_ CR_VSM_DecCmd_FCA11 : 56|8@1+ (0.01,0) [0|2.55] "g" ESC
-
+BO_ 1291 EV_Info: 8 XXX
+ SG_ OPKR_EV_Charge_Level : 17|7@1+ (1,0) [0|100] "%" XXX
CM_ "BO_ E_EMS11: All (plug-in) hybrids use this gas signal: CR_Vcu_AccPedDep_Pos, and all EVs use the Accel_Pedal_Pos signal. See hyundai/values.py for a specific car list";
CM_ 145 "Contains signal with accelerator pedal press. Used by fuel cell hydrogen-powered (FCEV) cars such as the 2021 Hyundai Nexo.";
CM_ 512 "Contains signal with gear shifter. Used by fuel cell hydrogen-powered (FCEV) cars such as the 2021 Hyundai Nexo.";
CM_ SG_ 871 CF_Lvr_IsgState "Idle Stop and Go";
CM_ SG_ 1056 SCCInfoDisplay "Goes to 1 for a second while transitioning from Cruise Control to No Message";
CM_ SG_ 1348 SpeedLim_Nav_Clu "Speed limit displayed on Nav, Cluster and HUD";
+CM_ SG_ 1348 SpeedLim_Nav_Cam "Speed limit if speed cam exist";
+VAL_ 882 Elect_Gear_Shifter_NEXO 1546 "D" 2314 "N" 2566 "R" 2569 "P";
VAL_ 274 CUR_GR 1 "D" 2 "D" 3 "D" 4 "D" 5 "D" 6 "D" 7 "D" 8 "D" 14 "R" 0 "P";
VAL_ 512 HYDROGEN_GEAR_SHIFTER 5 "D" 8 "S" 6 "N" 7 "R" 0 "P";
VAL_ 871 CF_Lvr_IsgState 0 "enabled" 1 "activated" 2 "unknown" 3 "disabled";
VAL_ 871 CF_Lvr_Gear 12 "T" 5 "D" 8 "S" 6 "N" 7 "R" 0 "P";
-VAL_ 882 Elect_Gear_Shifter 4 "S" 5 "D" 8 "S" 6 "N" 7 "R" 0 "P";
+VAL_ 882 Elect_Gear_Shifter 4 "S" 5 "D" 8 "S" 6 "N" 7 "R" 0 "P" 12 "T";
VAL_ 905 ACCMode 0 "off" 1 "enabled" 2 "driver_override" 3 "off_maybe_fault" 4 "cancelled";
VAL_ 905 ObjDistStat 0 "no_object" 1 "receding" 2 "approaching";
VAL_ 909 CF_VSM_Warn 2 "FCW" 3 "AEB";
diff --git a/iqdbc_repo/iqdbc/dbc/tesla_model3_party.dbc b/iqdbc_repo/iqdbc/dbc/tesla_model3_party.dbc
index 3e0af37..f08a72a 100644
--- a/iqdbc_repo/iqdbc/dbc/tesla_model3_party.dbc
+++ b/iqdbc_repo/iqdbc/dbc/tesla_model3_party.dbc
@@ -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" ;
diff --git a/iqdbc_repo/iqdbc/dbc/tesla_model3_vehicle.dbc b/iqdbc_repo/iqdbc/dbc/tesla_model3_vehicle.dbc
index 73c90aa..a8faeca 100644
--- a/iqdbc_repo/iqdbc/dbc/tesla_model3_vehicle.dbc
+++ b/iqdbc_repo/iqdbc/dbc/tesla_model3_vehicle.dbc
@@ -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
diff --git a/iqdbc_repo/iqdbc/dbc/vw_pq.dbc b/iqdbc_repo/iqdbc/dbc/vw_pq.dbc
index b4111e3..15626ec 100644
--- a/iqdbc_repo/iqdbc/dbc/vw_pq.dbc
+++ b/iqdbc_repo/iqdbc/dbc/vw_pq.dbc
@@ -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
diff --git a/iqdbc_repo/iqdbc/lvbs/car/car_catalog.py b/iqdbc_repo/iqdbc/lvbs/car/car_catalog.py
index b3eee24..3da55cb 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/car_catalog.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/car_catalog.py
@@ -1,14 +1,9 @@
import re
-import json
-import os
import unicodedata
-from iqdbc.car.common.basedir import BASEDIR
from iqdbc.car.docs import get_all_footnotes, get_params_for_docs
from iqdbc.car.values import PLATFORMS
-CAR_LIST_JSON_OUT = os.path.join(BASEDIR, "../", "iqpilot", "car", "car_list.json")
-
def build_car_catalog() -> dict[str, dict[str, list[str] | str]]:
collected_footnote = get_all_footnotes()
@@ -62,8 +57,6 @@ def collect_car_docs(platforms, footnotes) -> dict[str, dict[str, list[str] | st
if __name__ == "__main__":
- catalog = build_car_catalog()
-
- with open(CAR_LIST_JSON_OUT, "w") as json_file:
- json.dump(catalog, json_file, indent=2, ensure_ascii=False)
- print(f"Generated and written to {CAR_LIST_JSON_OUT}")
+ # build_car_catalog() is the raw platform source; the shipped catalog is generated
+ # (and encoded to its on-disk envelope) by the main-repo entry point:
+ print("run: python -m openpilot.iqpilot.selfdrive.car.vehicle_catalog")
diff --git a/iqdbc_repo/iqdbc/lvbs/car/car_list.json b/iqdbc_repo/iqdbc/lvbs/car/car_list.json
deleted file mode 100644
index ef32cf2..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/car_list.json
+++ /dev/null
@@ -1,4482 +0,0 @@
-{
- "Acura ILX 2016-18": {
- "platform": "ACURA_ILX",
- "make": "Acura",
- "brand": "honda",
- "model": "ILX",
- "year": [
- "2016",
- "2017",
- "2018"
- ],
- "package": "Technology Plus Package or AcuraWatch Plus"
- },
- "Acura ILX 2019": {
- "platform": "ACURA_ILX",
- "make": "Acura",
- "brand": "honda",
- "model": "ILX",
- "year": [
- "2019"
- ],
- "package": "All"
- },
- "Acura MDX 2025-26": {
- "platform": "ACURA_MDX_4G_MMR",
- "make": "Acura",
- "brand": "honda",
- "model": "MDX",
- "year": [
- "2025",
- "2026"
- ],
- "package": "All except Type S"
- },
- "Acura RDX 2016-18": {
- "platform": "ACURA_RDX",
- "make": "Acura",
- "brand": "honda",
- "model": "RDX",
- "year": [
- "2016",
- "2017",
- "2018"
- ],
- "package": "AcuraWatch Plus or Advance Package"
- },
- "Acura RDX 2019-21": {
- "platform": "ACURA_RDX_3G",
- "make": "Acura",
- "brand": "honda",
- "model": "RDX",
- "year": [
- "2019",
- "2020",
- "2021"
- ],
- "package": "All"
- },
- "Acura TLX 2021": {
- "platform": "ACURA_TLX_2G",
- "make": "Acura",
- "brand": "honda",
- "model": "TLX",
- "year": [
- "2021"
- ],
- "package": "All"
- },
- "Acura TLX 2025": {
- "platform": "ACURA_TLX_2G_MMR",
- "make": "Acura",
- "brand": "honda",
- "model": "TLX",
- "year": [
- "2025"
- ],
- "package": "All"
- },
- "Audi A3 2014-19": {
- "platform": "AUDI_A3_MK3",
- "make": "Audi",
- "brand": "volkswagen",
- "model": "A3",
- "year": [
- "2014",
- "2015",
- "2016",
- "2017",
- "2018",
- "2019"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Audi A3 Sportback e-tron 2017-18": {
- "platform": "AUDI_A3_MK3",
- "make": "Audi",
- "brand": "volkswagen",
- "model": "A3 Sportback e-tron",
- "year": [
- "2017",
- "2018"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Audi Q2 2018": {
- "platform": "AUDI_Q2_MK1",
- "make": "Audi",
- "brand": "volkswagen",
- "model": "Q2",
- "year": [
- "2018"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Audi Q3 2019-24": {
- "platform": "AUDI_Q3_MK2",
- "make": "Audi",
- "brand": "volkswagen",
- "model": "Q3",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Audi Q5 2013-17": {
- "platform": "AUDI_Q5_MK1",
- "make": "Audi",
- "brand": "volkswagen",
- "model": "Q5",
- "year": [
- "2013",
- "2014",
- "2015",
- "2016",
- "2017"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Porsche Macan 2015-": {
- "platform": "PORSCHE_MACAN_MK1",
- "make": "Audi",
- "brand": "volkswagen",
- "model": "Macan",
- "year": [
- "2015",
- "2016",
- "2017",
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023",
- "2024",
- "2025",
- "2026"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Audi RS3 2018": {
- "platform": "AUDI_A3_MK3",
- "make": "Audi",
- "brand": "volkswagen",
- "model": "RS3",
- "year": [
- "2018"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Audi S3 2015-17": {
- "platform": "AUDI_A3_MK3",
- "make": "Audi",
- "brand": "volkswagen",
- "model": "S3",
- "year": [
- "2015",
- "2016",
- "2017"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Buick LaCrosse 2017-19": {
- "platform": "BUICK_LACROSSE",
- "make": "Buick",
- "brand": "gm",
- "model": "LaCrosse",
- "year": [
- "2017",
- "2018",
- "2019"
- ],
- "package": "Driver Confidence Package 2"
- },
- "Cadillac Escalade 2017": {
- "platform": "CADILLAC_ESCALADE",
- "make": "Cadillac",
- "brand": "gm",
- "model": "Escalade",
- "year": [
- "2017"
- ],
- "package": "Driver Assist Package"
- },
- "Cadillac Escalade ESV 2016": {
- "platform": "CADILLAC_ESCALADE_ESV",
- "make": "Cadillac",
- "brand": "gm",
- "model": "Escalade ESV",
- "year": [
- "2016"
- ],
- "package": "Adaptive Cruise Control (ACC) & LKAS"
- },
- "Cadillac Escalade ESV 2019": {
- "platform": "CADILLAC_ESCALADE_ESV_2019",
- "make": "Cadillac",
- "brand": "gm",
- "model": "Escalade ESV",
- "year": [
- "2019"
- ],
- "package": "Adaptive Cruise Control (ACC) & LKAS"
- },
- "Cadillac XT4 2023": {
- "platform": "CADILLAC_XT4",
- "make": "Cadillac",
- "brand": "gm",
- "model": "XT4",
- "year": [
- "2023"
- ],
- "package": "Driver Assist Package"
- },
- "Chevrolet Bolt EUV 2022-23": {
- "platform": "CHEVROLET_BOLT_EUV",
- "make": "Chevrolet",
- "brand": "gm",
- "model": "Bolt EUV",
- "year": [
- "2022",
- "2023"
- ],
- "package": "Premier or Premier Redline Trim, without Super Cruise Package"
- },
- "Chevrolet Bolt EV 2022-23": {
- "platform": "CHEVROLET_BOLT_EUV",
- "make": "Chevrolet",
- "brand": "gm",
- "model": "Bolt EV",
- "year": [
- "2022",
- "2023"
- ],
- "package": "2LT Trim with Adaptive Cruise Control Package"
- },
- "Chevrolet Bolt EV Non-ACC 2017": {
- "platform": "CHEVROLET_BOLT_NON_ACC",
- "make": "Chevrolet",
- "brand": "gm",
- "model": "Bolt EV Non-ACC",
- "year": [
- "2017"
- ],
- "package": "No Adaptive Cruise Control (Non-ACC)"
- },
- "Chevrolet Bolt EV Non-ACC 2018-21": {
- "platform": "CHEVROLET_BOLT_NON_ACC_1ST_GEN",
- "make": "Chevrolet",
- "brand": "gm",
- "model": "Bolt EV Non-ACC",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021"
- ],
- "package": "No Adaptive Cruise Control (Non-ACC)"
- },
- "Chevrolet Equinox 2019-22": {
- "platform": "CHEVROLET_EQUINOX",
- "make": "Chevrolet",
- "brand": "gm",
- "model": "Equinox",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "Adaptive Cruise Control (ACC)"
- },
- "Chevrolet Malibu Non-ACC 2016-23": {
- "platform": "CHEVROLET_MALIBU_NON_ACC_9TH_GEN",
- "make": "Chevrolet",
- "brand": "gm",
- "model": "Malibu Non-ACC",
- "year": [
- "2016",
- "2017",
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "No Adaptive Cruise Control (Non-ACC)"
- },
- "Chevrolet Silverado 1500 2020-21": {
- "platform": "CHEVROLET_SILVERADO",
- "make": "Chevrolet",
- "brand": "gm",
- "model": "Silverado 1500",
- "year": [
- "2020",
- "2021"
- ],
- "package": "Safety Package II"
- },
- "Chevrolet Trailblazer 2021-22": {
- "platform": "CHEVROLET_TRAILBLAZER",
- "make": "Chevrolet",
- "brand": "gm",
- "model": "Trailblazer",
- "year": [
- "2021",
- "2022"
- ],
- "package": "Adaptive Cruise Control (ACC)"
- },
- "Chevrolet Traverse 2022-23": {
- "platform": "CHEVROLET_TRAVERSE",
- "make": "Chevrolet",
- "brand": "gm",
- "model": "Traverse",
- "year": [
- "2022",
- "2023"
- ],
- "package": "RS, Premier, or High Country Trim"
- },
- "Chevrolet Volt 2017-18": {
- "platform": "CHEVROLET_VOLT",
- "make": "Chevrolet",
- "brand": "gm",
- "model": "Volt",
- "year": [
- "2017",
- "2018"
- ],
- "package": "Adaptive Cruise Control (ACC)"
- },
- "Chevrolet Volt 2019": {
- "platform": "CHEVROLET_VOLT_2019",
- "make": "Chevrolet",
- "brand": "gm",
- "model": "Volt",
- "year": [
- "2019"
- ],
- "package": "Adaptive Cruise Control (ACC) & LKAS"
- },
- "Chrysler Pacifica 2017-18": {
- "platform": "CHRYSLER_PACIFICA_2018",
- "make": "Chrysler",
- "brand": "chrysler",
- "model": "Pacifica",
- "year": [
- "2017",
- "2018"
- ],
- "package": "Adaptive Cruise Control (ACC)"
- },
- "Chrysler Pacifica 2019-20": {
- "platform": "CHRYSLER_PACIFICA_2020",
- "make": "Chrysler",
- "brand": "chrysler",
- "model": "Pacifica",
- "year": [
- "2019",
- "2020"
- ],
- "package": "Adaptive Cruise Control (ACC)"
- },
- "Chrysler Pacifica 2021-23": {
- "platform": "CHRYSLER_PACIFICA_2020",
- "make": "Chrysler",
- "brand": "chrysler",
- "model": "Pacifica",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Chrysler Pacifica Hybrid 2017-18": {
- "platform": "CHRYSLER_PACIFICA_2018_HYBRID",
- "make": "Chrysler",
- "brand": "chrysler",
- "model": "Pacifica Hybrid",
- "year": [
- "2017",
- "2018"
- ],
- "package": "Adaptive Cruise Control (ACC)"
- },
- "Chrysler Pacifica Hybrid 2019-25": {
- "platform": "CHRYSLER_PACIFICA_2019_HYBRID",
- "make": "Chrysler",
- "brand": "chrysler",
- "model": "Pacifica Hybrid",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022",
- "2023",
- "2024",
- "2025"
- ],
- "package": "Adaptive Cruise Control (ACC)"
- },
- "comma body": {
- "platform": "COMMA_BODY",
- "make": "comma",
- "brand": "body",
- "model": "body",
- "year": [],
- "package": "All"
- },
- "CUPRA Ateca 2018-23": {
- "platform": "SEAT_ATECA_MK1",
- "make": "CUPRA",
- "brand": "volkswagen",
- "model": "Ateca",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Dodge Durango 2020-21": {
- "platform": "DODGE_DURANGO",
- "make": "Dodge",
- "brand": "chrysler",
- "model": "Durango",
- "year": [
- "2020",
- "2021"
- ],
- "package": "Adaptive Cruise Control (ACC)"
- },
- "Ford Bronco Sport 2021-24": {
- "platform": "FORD_BRONCO_SPORT_MK1",
- "make": "Ford",
- "brand": "ford",
- "model": "Bronco Sport",
- "year": [
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "Co-Pilot360 Assist+"
- },
- "Ford Escape 2020-22": {
- "platform": "FORD_ESCAPE_MK4",
- "make": "Ford",
- "brand": "ford",
- "model": "Escape",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "Co-Pilot360 Assist+"
- },
- "Ford Escape 2023-24": {
- "platform": "FORD_ESCAPE_MK4_5",
- "make": "Ford",
- "brand": "ford",
- "model": "Escape",
- "year": [
- "2023",
- "2024"
- ],
- "package": "Co-Pilot360 Assist+"
- },
- "Ford Escape Hybrid 2020-22": {
- "platform": "FORD_ESCAPE_MK4",
- "make": "Ford",
- "brand": "ford",
- "model": "Escape Hybrid",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "Co-Pilot360 Assist+"
- },
- "Ford Escape Hybrid 2023-24": {
- "platform": "FORD_ESCAPE_MK4_5",
- "make": "Ford",
- "brand": "ford",
- "model": "Escape Hybrid",
- "year": [
- "2023",
- "2024"
- ],
- "package": "Co-Pilot360 Assist+"
- },
- "Ford Escape Plug-in Hybrid 2020-22": {
- "platform": "FORD_ESCAPE_MK4",
- "make": "Ford",
- "brand": "ford",
- "model": "Escape Plug-in Hybrid",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "Co-Pilot360 Assist+"
- },
- "Ford Escape Plug-in Hybrid 2023-24": {
- "platform": "FORD_ESCAPE_MK4_5",
- "make": "Ford",
- "brand": "ford",
- "model": "Escape Plug-in Hybrid",
- "year": [
- "2023",
- "2024"
- ],
- "package": "Co-Pilot360 Assist+"
- },
- "Ford Expedition 2022-24": {
- "platform": "FORD_EXPEDITION_MK4",
- "make": "Ford",
- "brand": "ford",
- "model": "Expedition",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "Co-Pilot360 Assist 2.0"
- },
- "Ford Explorer 2020-24": {
- "platform": "FORD_EXPLORER_MK6",
- "make": "Ford",
- "brand": "ford",
- "model": "Explorer",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "Co-Pilot360 Assist+"
- },
- "Ford Explorer Hybrid 2020-24": {
- "platform": "FORD_EXPLORER_MK6",
- "make": "Ford",
- "brand": "ford",
- "model": "Explorer Hybrid",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "Co-Pilot360 Assist+"
- },
- "Ford F-150 2021-23": {
- "platform": "FORD_F_150_MK14",
- "make": "Ford",
- "brand": "ford",
- "model": "F-150",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "Co-Pilot360 Assist 2.0"
- },
- "Ford F-150 Hybrid 2021-23": {
- "platform": "FORD_F_150_MK14",
- "make": "Ford",
- "brand": "ford",
- "model": "F-150 Hybrid",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "Co-Pilot360 Assist 2.0"
- },
- "Ford F-150 Lightning 2022-23": {
- "platform": "FORD_F_150_LIGHTNING_MK1",
- "make": "Ford",
- "brand": "ford",
- "model": "F-150 Lightning",
- "year": [
- "2022",
- "2023"
- ],
- "package": "Co-Pilot360 Assist 2.0"
- },
- "Ford Focus 2018": {
- "platform": "FORD_FOCUS_MK4",
- "make": "Ford",
- "brand": "ford",
- "model": "Focus",
- "year": [
- "2018"
- ],
- "package": "Adaptive Cruise Control with Lane Centering"
- },
- "Ford Focus Hybrid 2018": {
- "platform": "FORD_FOCUS_MK4",
- "make": "Ford",
- "brand": "ford",
- "model": "Focus Hybrid",
- "year": [
- "2018"
- ],
- "package": "Adaptive Cruise Control with Lane Centering"
- },
- "Ford Kuga 2020-23": {
- "platform": "FORD_ESCAPE_MK4",
- "make": "Ford",
- "brand": "ford",
- "model": "Kuga",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control with Lane Centering"
- },
- "Ford Kuga Hybrid 2020-23": {
- "platform": "FORD_ESCAPE_MK4",
- "make": "Ford",
- "brand": "ford",
- "model": "Kuga Hybrid",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control with Lane Centering"
- },
- "Ford Kuga Hybrid 2024": {
- "platform": "FORD_ESCAPE_MK4_5",
- "make": "Ford",
- "brand": "ford",
- "model": "Kuga Hybrid",
- "year": [
- "2024"
- ],
- "package": "All"
- },
- "Ford Kuga Plug-in Hybrid 2020-23": {
- "platform": "FORD_ESCAPE_MK4",
- "make": "Ford",
- "brand": "ford",
- "model": "Kuga Plug-in Hybrid",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control with Lane Centering"
- },
- "Ford Kuga Plug-in Hybrid 2024": {
- "platform": "FORD_ESCAPE_MK4_5",
- "make": "Ford",
- "brand": "ford",
- "model": "Kuga Plug-in Hybrid",
- "year": [
- "2024"
- ],
- "package": "All"
- },
- "Ford Maverick 2022": {
- "platform": "FORD_MAVERICK_MK1",
- "make": "Ford",
- "brand": "ford",
- "model": "Maverick",
- "year": [
- "2022"
- ],
- "package": "LARIAT Luxury"
- },
- "Ford Maverick 2023-24": {
- "platform": "FORD_MAVERICK_MK1",
- "make": "Ford",
- "brand": "ford",
- "model": "Maverick",
- "year": [
- "2023",
- "2024"
- ],
- "package": "Co-Pilot360 Assist"
- },
- "Ford Maverick Hybrid 2022": {
- "platform": "FORD_MAVERICK_MK1",
- "make": "Ford",
- "brand": "ford",
- "model": "Maverick Hybrid",
- "year": [
- "2022"
- ],
- "package": "LARIAT Luxury"
- },
- "Ford Maverick Hybrid 2023-24": {
- "platform": "FORD_MAVERICK_MK1",
- "make": "Ford",
- "brand": "ford",
- "model": "Maverick Hybrid",
- "year": [
- "2023",
- "2024"
- ],
- "package": "Co-Pilot360 Assist"
- },
- "Ford Mustang Mach-E 2021-24": {
- "platform": "FORD_MUSTANG_MACH_E_MK1",
- "make": "Ford",
- "brand": "ford",
- "model": "Mustang Mach-E",
- "year": [
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "All"
- },
- "Ford Ranger 2024": {
- "platform": "FORD_RANGER_MK2",
- "make": "Ford",
- "brand": "ford",
- "model": "Ranger",
- "year": [
- "2024"
- ],
- "package": "Adaptive Cruise Control with Lane Centering"
- },
- "Genesis G70 2018": {
- "platform": "GENESIS_G70",
- "make": "Genesis",
- "brand": "hyundai",
- "model": "G70",
- "year": [
- "2018"
- ],
- "package": "All"
- },
- "Genesis G70 2019-21": {
- "platform": "GENESIS_G70_2020",
- "make": "Genesis",
- "brand": "hyundai",
- "model": "G70",
- "year": [
- "2019",
- "2020",
- "2021"
- ],
- "package": "All"
- },
- "Genesis G70 2022-23": {
- "platform": "GENESIS_G70_2020",
- "make": "Genesis",
- "brand": "hyundai",
- "model": "G70",
- "year": [
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Genesis G80 2017": {
- "platform": "HYUNDAI_GENESIS",
- "make": "Genesis",
- "brand": "hyundai",
- "model": "G80",
- "year": [
- "2017"
- ],
- "package": "All"
- },
- "Genesis G80 2018-19": {
- "platform": "GENESIS_G80",
- "make": "Genesis",
- "brand": "hyundai",
- "model": "G80",
- "year": [
- "2018",
- "2019"
- ],
- "package": "All"
- },
- "Genesis G80 (2.5T Advanced Trim, with HDA II) 2024": {
- "platform": "GENESIS_G80_2ND_GEN_FL",
- "make": "Genesis",
- "brand": "hyundai",
- "model": "G80 (2.5T Advanced Trim, with HDA II)",
- "year": [
- "2024"
- ],
- "package": "Highway Driving Assist II"
- },
- "Genesis G90 2017-20": {
- "platform": "GENESIS_G90",
- "make": "Genesis",
- "brand": "hyundai",
- "model": "G90",
- "year": [
- "2017",
- "2018",
- "2019",
- "2020"
- ],
- "package": "All"
- },
- "Genesis GV60 (Advanced Trim) 2023": {
- "platform": "GENESIS_GV60_EV_1ST_GEN",
- "make": "Genesis",
- "brand": "hyundai",
- "model": "GV60 (Advanced Trim)",
- "year": [
- "2023"
- ],
- "package": "All"
- },
- "Genesis GV60 (Performance Trim) 2022-23": {
- "platform": "GENESIS_GV60_EV_1ST_GEN",
- "make": "Genesis",
- "brand": "hyundai",
- "model": "GV60 (Performance Trim)",
- "year": [
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Genesis GV70 (2.5T Trim, without HDA II) 2022-24": {
- "platform": "GENESIS_GV70_1ST_GEN",
- "make": "Genesis",
- "brand": "hyundai",
- "model": "GV70 (2.5T Trim, without HDA II)",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "All"
- },
- "Genesis GV70 (3.5T Trim, without HDA II) 2022-23": {
- "platform": "GENESIS_GV70_1ST_GEN",
- "make": "Genesis",
- "brand": "hyundai",
- "model": "GV70 (3.5T Trim, without HDA II)",
- "year": [
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Genesis GV70 Electrified (Australia Only) 2022": {
- "platform": "GENESIS_GV70_ELECTRIFIED_1ST_GEN",
- "make": "Genesis",
- "brand": "hyundai",
- "model": "GV70 Electrified (Australia Only)",
- "year": [
- "2022"
- ],
- "package": "All"
- },
- "Genesis GV70 Electrified (with HDA II) 2023-24": {
- "platform": "GENESIS_GV70_ELECTRIFIED_1ST_GEN",
- "make": "Genesis",
- "brand": "hyundai",
- "model": "GV70 Electrified (with HDA II)",
- "year": [
- "2023",
- "2024"
- ],
- "package": "Highway Driving Assist II"
- },
- "Genesis GV80 2023": {
- "platform": "GENESIS_GV80",
- "make": "Genesis",
- "brand": "hyundai",
- "model": "GV80",
- "year": [
- "2023"
- ],
- "package": "All"
- },
- "GMC Acadia 2018": {
- "platform": "GMC_ACADIA",
- "make": "GMC",
- "brand": "gm",
- "model": "Acadia",
- "year": [
- "2018"
- ],
- "package": "Adaptive Cruise Control (ACC)"
- },
- "GMC Sierra 1500 2020-21": {
- "platform": "CHEVROLET_SILVERADO",
- "make": "GMC",
- "brand": "gm",
- "model": "Sierra 1500",
- "year": [
- "2020",
- "2021"
- ],
- "package": "Driver Alert Package II"
- },
- "Honda Accord 2018-22": {
- "platform": "HONDA_ACCORD",
- "make": "Honda",
- "brand": "honda",
- "model": "Accord",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Honda Accord 2023-25": {
- "platform": "HONDA_ACCORD_11G",
- "make": "Honda",
- "brand": "honda",
- "model": "Accord",
- "year": [
- "2023",
- "2024",
- "2025"
- ],
- "package": "All"
- },
- "Honda Accord Hybrid 2018-22": {
- "platform": "HONDA_ACCORD",
- "make": "Honda",
- "brand": "honda",
- "model": "Accord Hybrid",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Honda Accord Hybrid 2023-25": {
- "platform": "HONDA_ACCORD_11G",
- "make": "Honda",
- "brand": "honda",
- "model": "Accord Hybrid",
- "year": [
- "2023",
- "2024",
- "2025"
- ],
- "package": "All"
- },
- "Honda City (Brazil only) 2023": {
- "platform": "HONDA_CITY_7G",
- "make": "Honda",
- "brand": "honda",
- "model": "City (Brazil only)",
- "year": [
- "2023"
- ],
- "package": "All"
- },
- "Honda Civic 2016-18": {
- "platform": "HONDA_CIVIC",
- "make": "Honda",
- "brand": "honda",
- "model": "Civic",
- "year": [
- "2016",
- "2017",
- "2018"
- ],
- "package": "Honda Sensing"
- },
- "Honda Civic 2019-21": {
- "platform": "HONDA_CIVIC_BOSCH",
- "make": "Honda",
- "brand": "honda",
- "model": "Civic",
- "year": [
- "2019",
- "2020",
- "2021"
- ],
- "package": "All"
- },
- "Honda Civic 2022-24": {
- "platform": "HONDA_CIVIC_2022",
- "make": "Honda",
- "brand": "honda",
- "model": "Civic",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "All"
- },
- "Honda Civic Hatchback 2017-18": {
- "platform": "HONDA_CIVIC_BOSCH",
- "make": "Honda",
- "brand": "honda",
- "model": "Civic Hatchback",
- "year": [
- "2017",
- "2018"
- ],
- "package": "Honda Sensing"
- },
- "Honda Civic Hatchback 2019-21": {
- "platform": "HONDA_CIVIC_BOSCH",
- "make": "Honda",
- "brand": "honda",
- "model": "Civic Hatchback",
- "year": [
- "2019",
- "2020",
- "2021"
- ],
- "package": "All"
- },
- "Honda Civic Hatchback 2022-24": {
- "platform": "HONDA_CIVIC_2022",
- "make": "Honda",
- "brand": "honda",
- "model": "Civic Hatchback",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "All"
- },
- "Honda Civic Hatchback Hybrid 2025-26": {
- "platform": "HONDA_CIVIC_2022",
- "make": "Honda",
- "brand": "honda",
- "model": "Civic Hatchback Hybrid",
- "year": [
- "2025",
- "2026"
- ],
- "package": "All"
- },
- "Honda Civic Hatchback Hybrid (Europe only) 2023": {
- "platform": "HONDA_CIVIC_2022",
- "make": "Honda",
- "brand": "honda",
- "model": "Civic Hatchback Hybrid (Europe only)",
- "year": [
- "2023"
- ],
- "package": "All"
- },
- "Honda Civic Hybrid 2025-26": {
- "platform": "HONDA_CIVIC_2022",
- "make": "Honda",
- "brand": "honda",
- "model": "Civic Hybrid",
- "year": [
- "2025",
- "2026"
- ],
- "package": "All"
- },
- "Honda Clarity 2018-21": {
- "platform": "HONDA_CLARITY",
- "make": "Honda",
- "brand": "honda",
- "model": "Clarity",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021"
- ],
- "package": "Honda Sensing"
- },
- "Honda CR-V 2015-16": {
- "platform": "HONDA_CRV",
- "make": "Honda",
- "brand": "honda",
- "model": "CR-V",
- "year": [
- "2015",
- "2016"
- ],
- "package": "Touring Trim"
- },
- "Honda CR-V 2017-22": {
- "platform": "HONDA_CRV_5G",
- "make": "Honda",
- "brand": "honda",
- "model": "CR-V",
- "year": [
- "2017",
- "2018",
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "Honda Sensing"
- },
- "Honda CR-V 2023-26": {
- "platform": "HONDA_CRV_6G",
- "make": "Honda",
- "brand": "honda",
- "model": "CR-V",
- "year": [
- "2023",
- "2024",
- "2025",
- "2026"
- ],
- "package": "All"
- },
- "Honda CR-V Hybrid 2017-22": {
- "platform": "HONDA_CRV_HYBRID",
- "make": "Honda",
- "brand": "honda",
- "model": "CR-V Hybrid",
- "year": [
- "2017",
- "2018",
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "Honda Sensing"
- },
- "Honda CR-V Hybrid 2023-26": {
- "platform": "HONDA_CRV_6G",
- "make": "Honda",
- "brand": "honda",
- "model": "CR-V Hybrid",
- "year": [
- "2023",
- "2024",
- "2025",
- "2026"
- ],
- "package": "All"
- },
- "Honda e 2020": {
- "platform": "HONDA_E",
- "make": "Honda",
- "brand": "honda",
- "model": "e",
- "year": [
- "2020"
- ],
- "package": "All"
- },
- "Honda Fit 2018-20": {
- "platform": "HONDA_FIT",
- "make": "Honda",
- "brand": "honda",
- "model": "Fit",
- "year": [
- "2018",
- "2019",
- "2020"
- ],
- "package": "Honda Sensing"
- },
- "Honda Freed 2020": {
- "platform": "HONDA_FREED",
- "make": "Honda",
- "brand": "honda",
- "model": "Freed",
- "year": [
- "2020"
- ],
- "package": "Honda Sensing"
- },
- "Honda HR-V 2019-22": {
- "platform": "HONDA_HRV",
- "make": "Honda",
- "brand": "honda",
- "model": "HR-V",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "Honda Sensing"
- },
- "Honda HR-V 2023-25": {
- "platform": "HONDA_HRV_3G",
- "make": "Honda",
- "brand": "honda",
- "model": "HR-V",
- "year": [
- "2023",
- "2024",
- "2025"
- ],
- "package": "All"
- },
- "Honda Insight 2019-22": {
- "platform": "HONDA_INSIGHT",
- "make": "Honda",
- "brand": "honda",
- "model": "Insight",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Honda Inspire 2018": {
- "platform": "HONDA_ACCORD",
- "make": "Honda",
- "brand": "honda",
- "model": "Inspire",
- "year": [
- "2018"
- ],
- "package": "All"
- },
- "Honda N-Box 2018": {
- "platform": "HONDA_NBOX_2G",
- "make": "Honda",
- "brand": "honda",
- "model": "N-Box",
- "year": [
- "2018"
- ],
- "package": "All"
- },
- "Honda Odyssey 2018-20": {
- "platform": "HONDA_ODYSSEY",
- "make": "Honda",
- "brand": "honda",
- "model": "Odyssey",
- "year": [
- "2018",
- "2019",
- "2020"
- ],
- "package": "Honda Sensing"
- },
- "Honda Odyssey 2021-26": {
- "platform": "HONDA_ODYSSEY_5G_MMR",
- "make": "Honda",
- "brand": "honda",
- "model": "Odyssey",
- "year": [
- "2021",
- "2022",
- "2023",
- "2024",
- "2025",
- "2026"
- ],
- "package": "All"
- },
- "Honda Odyssey (Taiwan) 2018-19": {
- "platform": "HONDA_ODYSSEY_TWN",
- "make": "Honda",
- "brand": "honda",
- "model": "Odyssey (Taiwan)",
- "year": [
- "2018",
- "2019"
- ],
- "package": "Honda Sensing"
- },
- "Honda Passport 2019-25": {
- "platform": "HONDA_PILOT",
- "make": "Honda",
- "brand": "honda",
- "model": "Passport",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022",
- "2023",
- "2024",
- "2025"
- ],
- "package": "All"
- },
- "Honda Passport 2026": {
- "platform": "HONDA_PASSPORT_4G",
- "make": "Honda",
- "brand": "honda",
- "model": "Passport",
- "year": [
- "2026"
- ],
- "package": "All"
- },
- "Honda Pilot 2016-22": {
- "platform": "HONDA_PILOT",
- "make": "Honda",
- "brand": "honda",
- "model": "Pilot",
- "year": [
- "2016",
- "2017",
- "2018",
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "Honda Sensing"
- },
- "Honda Pilot 2023-25": {
- "platform": "HONDA_PILOT_4G",
- "make": "Honda",
- "brand": "honda",
- "model": "Pilot",
- "year": [
- "2023",
- "2024",
- "2025"
- ],
- "package": "All"
- },
- "Honda Ridgeline 2017-25": {
- "platform": "HONDA_RIDGELINE",
- "make": "Honda",
- "brand": "honda",
- "model": "Ridgeline",
- "year": [
- "2017",
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023",
- "2024",
- "2025"
- ],
- "package": "Honda Sensing"
- },
- "Hyundai Azera 2022": {
- "platform": "HYUNDAI_AZERA_6TH_GEN",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Azera",
- "year": [
- "2022"
- ],
- "package": "All"
- },
- "Hyundai Azera Hybrid 2019": {
- "platform": "HYUNDAI_AZERA_HEV_6TH_GEN",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Azera Hybrid",
- "year": [
- "2019"
- ],
- "package": "All"
- },
- "Hyundai Azera Hybrid 2020": {
- "platform": "HYUNDAI_AZERA_HEV_6TH_GEN",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Azera Hybrid",
- "year": [
- "2020"
- ],
- "package": "All"
- },
- "Hyundai Custin 2023": {
- "platform": "HYUNDAI_CUSTIN_1ST_GEN",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Custin",
- "year": [
- "2023"
- ],
- "package": "All"
- },
- "Hyundai Elantra 2017-18": {
- "platform": "HYUNDAI_ELANTRA",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Elantra",
- "year": [
- "2017",
- "2018"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Elantra 2019": {
- "platform": "HYUNDAI_ELANTRA",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Elantra",
- "year": [
- "2019"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Elantra 2021-23": {
- "platform": "HYUNDAI_ELANTRA_2021",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Elantra",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Elantra GT 2017-20": {
- "platform": "HYUNDAI_ELANTRA_GT_I30",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Elantra GT",
- "year": [
- "2017",
- "2018",
- "2019",
- "2020"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Elantra Hybrid 2021-23": {
- "platform": "HYUNDAI_ELANTRA_HEV_2021",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Elantra Hybrid",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Elantra Non-SCC 2022": {
- "platform": "HYUNDAI_ELANTRA_2022_NON_SCC",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Elantra Non-SCC",
- "year": [
- "2022"
- ],
- "package": "No Smart Cruise Control (Non-SCC)"
- },
- "Hyundai Genesis 2015-16": {
- "platform": "HYUNDAI_GENESIS",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Genesis",
- "year": [
- "2015",
- "2016"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai i30 2017-19": {
- "platform": "HYUNDAI_ELANTRA_GT_I30",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "i30",
- "year": [
- "2017",
- "2018",
- "2019"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Ioniq 5 (Southeast Asia and Europe only) 2022-24": {
- "platform": "HYUNDAI_IONIQ_5",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Ioniq 5 (Southeast Asia and Europe only)",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "All"
- },
- "Hyundai Ioniq 5 (with HDA II) 2022-24": {
- "platform": "HYUNDAI_IONIQ_5",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Ioniq 5 (with HDA II)",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "Highway Driving Assist II"
- },
- "Hyundai Ioniq 5 (without HDA II) 2022-24": {
- "platform": "HYUNDAI_IONIQ_5",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Ioniq 5 (without HDA II)",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "Highway Driving Assist"
- },
- "Hyundai Ioniq 6 (with HDA II) 2023-24": {
- "platform": "HYUNDAI_IONIQ_6",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Ioniq 6 (with HDA II)",
- "year": [
- "2023",
- "2024"
- ],
- "package": "Highway Driving Assist II"
- },
- "Hyundai Ioniq Electric 2019": {
- "platform": "HYUNDAI_IONIQ_EV_LTD",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Ioniq Electric",
- "year": [
- "2019"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Ioniq Electric 2020": {
- "platform": "HYUNDAI_IONIQ_EV_2020",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Ioniq Electric",
- "year": [
- "2020"
- ],
- "package": "All"
- },
- "Hyundai Ioniq Hybrid 2017-19": {
- "platform": "HYUNDAI_IONIQ",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Ioniq Hybrid",
- "year": [
- "2017",
- "2018",
- "2019"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Ioniq Hybrid 2020-22": {
- "platform": "HYUNDAI_IONIQ_HEV_2022",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Ioniq Hybrid",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Ioniq Plug-in Hybrid 2019": {
- "platform": "HYUNDAI_IONIQ_PHEV_2019",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Ioniq Plug-in Hybrid",
- "year": [
- "2019"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Ioniq Plug-in Hybrid 2020-22": {
- "platform": "HYUNDAI_IONIQ_PHEV",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Ioniq Plug-in Hybrid",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Hyundai Kona 2020": {
- "platform": "HYUNDAI_KONA",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Kona",
- "year": [
- "2020"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Kona 2022-23": {
- "platform": "HYUNDAI_KONA_2022",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Kona",
- "year": [
- "2022",
- "2023"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Kona Electric 2018-21": {
- "platform": "HYUNDAI_KONA_EV",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Kona Electric",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Kona Electric 2022-23": {
- "platform": "HYUNDAI_KONA_EV_2022",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Kona Electric",
- "year": [
- "2022",
- "2023"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Kona Electric (with HDA II, Korea only) 2023": {
- "platform": "HYUNDAI_KONA_EV_2ND_GEN",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Kona Electric (with HDA II, Korea only)",
- "year": [
- "2023"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Kona Electric Non-SCC 2019": {
- "platform": "HYUNDAI_KONA_EV_NON_SCC",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Kona Electric Non-SCC",
- "year": [
- "2019"
- ],
- "package": "No Smart Cruise Control (Non-SCC)"
- },
- "Hyundai Kona Hybrid 2020": {
- "platform": "HYUNDAI_KONA_HEV",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Kona Hybrid",
- "year": [
- "2020"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Kona Non-SCC 2019": {
- "platform": "HYUNDAI_KONA_NON_SCC",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Kona Non-SCC",
- "year": [
- "2019"
- ],
- "package": "No Smart Cruise Control (Non-SCC)"
- },
- "Hyundai Nexo 2021": {
- "platform": "HYUNDAI_NEXO_1ST_GEN",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Nexo",
- "year": [
- "2021"
- ],
- "package": "All"
- },
- "Hyundai Palisade 2020-22": {
- "platform": "HYUNDAI_PALISADE",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Palisade",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Hyundai Santa Cruz 2022-24": {
- "platform": "HYUNDAI_SANTA_CRUZ_1ST_GEN",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Santa Cruz",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Santa Fe 2019-20": {
- "platform": "HYUNDAI_SANTA_FE",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Santa Fe",
- "year": [
- "2019",
- "2020"
- ],
- "package": "All"
- },
- "Hyundai Santa Fe 2021-23": {
- "platform": "HYUNDAI_SANTA_FE_2022",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Santa Fe",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Hyundai Santa Fe Hybrid 2022-23": {
- "platform": "HYUNDAI_SANTA_FE_HEV_2022",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Santa Fe Hybrid",
- "year": [
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Hyundai Santa Fe Plug-in Hybrid 2022-23": {
- "platform": "HYUNDAI_SANTA_FE_PHEV_2022",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Santa Fe Plug-in Hybrid",
- "year": [
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Hyundai Sonata 2018-19": {
- "platform": "HYUNDAI_SONATA_LF",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Sonata",
- "year": [
- "2018",
- "2019"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Sonata 2020-23": {
- "platform": "HYUNDAI_SONATA",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Sonata",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Hyundai Sonata Hybrid 2020-23": {
- "platform": "HYUNDAI_SONATA_HYBRID",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Sonata Hybrid",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Hyundai Staria 2023": {
- "platform": "HYUNDAI_STARIA_4TH_GEN",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Staria",
- "year": [
- "2023"
- ],
- "package": "All"
- },
- "Hyundai Tucson 2021": {
- "platform": "HYUNDAI_TUCSON",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Tucson",
- "year": [
- "2021"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Tucson 2022": {
- "platform": "HYUNDAI_TUCSON_4TH_GEN",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Tucson",
- "year": [
- "2022"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Tucson 2023-24": {
- "platform": "HYUNDAI_TUCSON_4TH_GEN",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Tucson",
- "year": [
- "2023",
- "2024"
- ],
- "package": "All"
- },
- "Hyundai Tucson Diesel 2019": {
- "platform": "HYUNDAI_TUCSON",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Tucson Diesel",
- "year": [
- "2019"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Hyundai Tucson Hybrid 2022-24": {
- "platform": "HYUNDAI_TUCSON_4TH_GEN",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Tucson Hybrid",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "All"
- },
- "Hyundai Tucson Plug-in Hybrid 2024": {
- "platform": "HYUNDAI_TUCSON_4TH_GEN",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Tucson Plug-in Hybrid",
- "year": [
- "2024"
- ],
- "package": "All"
- },
- "Hyundai Veloster 2019-20": {
- "platform": "HYUNDAI_VELOSTER",
- "make": "Hyundai",
- "brand": "hyundai",
- "model": "Veloster",
- "year": [
- "2019",
- "2020"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Jeep Grand Cherokee 2016-18": {
- "platform": "JEEP_GRAND_CHEROKEE",
- "make": "Jeep",
- "brand": "chrysler",
- "model": "Grand Cherokee",
- "year": [
- "2016",
- "2017",
- "2018"
- ],
- "package": "Adaptive Cruise Control (ACC)"
- },
- "Jeep Grand Cherokee 2019-21": {
- "platform": "JEEP_GRAND_CHEROKEE_2019",
- "make": "Jeep",
- "brand": "chrysler",
- "model": "Grand Cherokee",
- "year": [
- "2019",
- "2020",
- "2021"
- ],
- "package": "Adaptive Cruise Control (ACC)"
- },
- "Kia Carnival 2022-24": {
- "platform": "KIA_CARNIVAL_4TH_GEN",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Carnival",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Carnival (China only) 2023": {
- "platform": "KIA_CARNIVAL_4TH_GEN",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Carnival (China only)",
- "year": [
- "2023"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Ceed 2019-21": {
- "platform": "KIA_CEED",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Ceed",
- "year": [
- "2019",
- "2020",
- "2021"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Ceed Plug-in Hybrid Non-SCC 2022": {
- "platform": "KIA_CEED_PHEV_2022_NON_SCC",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Ceed Plug-in Hybrid Non-SCC",
- "year": [
- "2022"
- ],
- "package": "No Smart Cruise Control (Non-SCC)"
- },
- "Kia EV6 (Southeast Asia only) 2022-24": {
- "platform": "KIA_EV6",
- "make": "Kia",
- "brand": "hyundai",
- "model": "EV6 (Southeast Asia only)",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "All"
- },
- "Kia EV6 (with HDA II) 2022-24": {
- "platform": "KIA_EV6",
- "make": "Kia",
- "brand": "hyundai",
- "model": "EV6 (with HDA II)",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "Highway Driving Assist II"
- },
- "Kia EV6 (without HDA II) 2022-24": {
- "platform": "KIA_EV6",
- "make": "Kia",
- "brand": "hyundai",
- "model": "EV6 (without HDA II)",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "Highway Driving Assist"
- },
- "Kia Forte 2019-21": {
- "platform": "KIA_FORTE",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Forte",
- "year": [
- "2019",
- "2020",
- "2021"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Forte 2022-23": {
- "platform": "KIA_FORTE",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Forte",
- "year": [
- "2022",
- "2023"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Forte Non-SCC 2019": {
- "platform": "KIA_FORTE_2019_NON_SCC",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Forte Non-SCC",
- "year": [
- "2019"
- ],
- "package": "No Smart Cruise Control (Non-SCC)"
- },
- "Kia K5 2021-24": {
- "platform": "KIA_K5_2021",
- "make": "Kia",
- "brand": "hyundai",
- "model": "K5",
- "year": [
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia K5 Hybrid 2020-22": {
- "platform": "KIA_K5_HEV_2020",
- "make": "Kia",
- "brand": "hyundai",
- "model": "K5 Hybrid",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia K8 Hybrid (with HDA II) 2023": {
- "platform": "KIA_K8_HEV_1ST_GEN",
- "make": "Kia",
- "brand": "hyundai",
- "model": "K8 Hybrid (with HDA II)",
- "year": [
- "2023"
- ],
- "package": "Highway Driving Assist II"
- },
- "Kia Niro EV 2019": {
- "platform": "KIA_NIRO_EV",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Niro EV",
- "year": [
- "2019"
- ],
- "package": "All"
- },
- "Kia Niro EV 2020": {
- "platform": "KIA_NIRO_EV",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Niro EV",
- "year": [
- "2020"
- ],
- "package": "All"
- },
- "Kia Niro EV 2021": {
- "platform": "KIA_NIRO_EV",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Niro EV",
- "year": [
- "2021"
- ],
- "package": "All"
- },
- "Kia Niro EV 2022": {
- "platform": "KIA_NIRO_EV",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Niro EV",
- "year": [
- "2022"
- ],
- "package": "All"
- },
- "Kia Niro EV (with HDA II) 2025": {
- "platform": "KIA_NIRO_EV_2ND_GEN",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Niro EV (with HDA II)",
- "year": [
- "2025"
- ],
- "package": "Highway Driving Assist II"
- },
- "Kia Niro EV (without HDA II) 2023-25": {
- "platform": "KIA_NIRO_EV_2ND_GEN",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Niro EV (without HDA II)",
- "year": [
- "2023",
- "2024",
- "2025"
- ],
- "package": "All"
- },
- "Kia Niro Hybrid 2018": {
- "platform": "KIA_NIRO_PHEV",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Niro Hybrid",
- "year": [
- "2018"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Niro Hybrid 2021": {
- "platform": "KIA_NIRO_HEV_2021",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Niro Hybrid",
- "year": [
- "2021"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Niro Hybrid 2022": {
- "platform": "KIA_NIRO_HEV_2021",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Niro Hybrid",
- "year": [
- "2022"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Niro Hybrid 2023": {
- "platform": "KIA_NIRO_HEV_2ND_GEN",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Niro Hybrid",
- "year": [
- "2023"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Niro Plug-in Hybrid 2018-19": {
- "platform": "KIA_NIRO_PHEV",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Niro Plug-in Hybrid",
- "year": [
- "2018",
- "2019"
- ],
- "package": "All"
- },
- "Kia Niro Plug-in Hybrid 2020": {
- "platform": "KIA_NIRO_PHEV",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Niro Plug-in Hybrid",
- "year": [
- "2020"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Niro Plug-in Hybrid 2021": {
- "platform": "KIA_NIRO_PHEV_2022",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Niro Plug-in Hybrid",
- "year": [
- "2021"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Niro Plug-in Hybrid 2022": {
- "platform": "KIA_NIRO_PHEV_2022",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Niro Plug-in Hybrid",
- "year": [
- "2022"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Optima 2017": {
- "platform": "KIA_OPTIMA_G4",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Optima",
- "year": [
- "2017"
- ],
- "package": "Advanced Smart Cruise Control"
- },
- "Kia Optima 2019-20": {
- "platform": "KIA_OPTIMA_G4_FL",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Optima",
- "year": [
- "2019",
- "2020"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Optima Hybrid 2019": {
- "platform": "KIA_OPTIMA_H_G4_FL",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Optima Hybrid",
- "year": [
- "2019"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Seltos 2021": {
- "platform": "KIA_SELTOS",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Seltos",
- "year": [
- "2021"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Sorento 2018": {
- "platform": "KIA_SORENTO",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Sorento",
- "year": [
- "2018"
- ],
- "package": "Advanced Smart Cruise Control & LKAS"
- },
- "Kia Sorento 2019": {
- "platform": "KIA_SORENTO",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Sorento",
- "year": [
- "2019"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Sorento 2021-23": {
- "platform": "KIA_SORENTO_4TH_GEN",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Sorento",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Sorento Hybrid 2021-23": {
- "platform": "KIA_SORENTO_HEV_4TH_GEN",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Sorento Hybrid",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Kia Sorento Plug-in Hybrid 2022-23": {
- "platform": "KIA_SORENTO_HEV_4TH_GEN",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Sorento Plug-in Hybrid",
- "year": [
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Kia Sportage 2023-24": {
- "platform": "KIA_SPORTAGE_5TH_GEN",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Sportage",
- "year": [
- "2023",
- "2024"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Sportage Hybrid 2023": {
- "platform": "KIA_SPORTAGE_5TH_GEN",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Sportage Hybrid",
- "year": [
- "2023"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Stinger 2018-20": {
- "platform": "KIA_STINGER",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Stinger",
- "year": [
- "2018",
- "2019",
- "2020"
- ],
- "package": "Smart Cruise Control (SCC)"
- },
- "Kia Stinger 2022-23": {
- "platform": "KIA_STINGER_2022",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Stinger",
- "year": [
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Kia Telluride 2020-22": {
- "platform": "HYUNDAI_PALISADE",
- "make": "Kia",
- "brand": "hyundai",
- "model": "Telluride",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Lexus CT Hybrid 2017-18": {
- "platform": "LEXUS_CTH",
- "make": "Lexus",
- "brand": "toyota",
- "model": "CT Hybrid",
- "year": [
- "2017",
- "2018"
- ],
- "package": "Lexus Safety System+"
- },
- "Lexus ES 2017-18": {
- "platform": "LEXUS_ES",
- "make": "Lexus",
- "brand": "toyota",
- "model": "ES",
- "year": [
- "2017",
- "2018"
- ],
- "package": "All"
- },
- "Lexus ES 2019-25": {
- "platform": "LEXUS_ES_TSS2",
- "make": "Lexus",
- "brand": "toyota",
- "model": "ES",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022",
- "2023",
- "2024",
- "2025"
- ],
- "package": "All"
- },
- "Lexus ES Hybrid 2017-18": {
- "platform": "LEXUS_ES",
- "make": "Lexus",
- "brand": "toyota",
- "model": "ES Hybrid",
- "year": [
- "2017",
- "2018"
- ],
- "package": "All"
- },
- "Lexus ES Hybrid 2019-25": {
- "platform": "LEXUS_ES_TSS2",
- "make": "Lexus",
- "brand": "toyota",
- "model": "ES Hybrid",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022",
- "2023",
- "2024",
- "2025"
- ],
- "package": "All"
- },
- "Lexus GS F 2016": {
- "platform": "LEXUS_GS_F",
- "make": "Lexus",
- "brand": "toyota",
- "model": "GS F",
- "year": [
- "2016"
- ],
- "package": "All"
- },
- "Lexus IS 2017-19": {
- "platform": "LEXUS_IS",
- "make": "Lexus",
- "brand": "toyota",
- "model": "IS",
- "year": [
- "2017",
- "2018",
- "2019"
- ],
- "package": "All"
- },
- "Lexus IS 2022-24": {
- "platform": "LEXUS_IS_TSS2",
- "make": "Lexus",
- "brand": "toyota",
- "model": "IS",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "All"
- },
- "Lexus LC 2024-25": {
- "platform": "LEXUS_LC_TSS2",
- "make": "Lexus",
- "brand": "toyota",
- "model": "LC",
- "year": [
- "2024",
- "2025"
- ],
- "package": "All"
- },
- "Lexus LS 2018": {
- "platform": "LEXUS_LS",
- "make": "Lexus",
- "brand": "toyota",
- "model": "LS",
- "year": [
- "2018"
- ],
- "package": "All except Lexus Safety System+ A"
- },
- "Lexus NX 2018-19": {
- "platform": "LEXUS_NX",
- "make": "Lexus",
- "brand": "toyota",
- "model": "NX",
- "year": [
- "2018",
- "2019"
- ],
- "package": "All"
- },
- "Lexus NX 2020-21": {
- "platform": "LEXUS_NX_TSS2",
- "make": "Lexus",
- "brand": "toyota",
- "model": "NX",
- "year": [
- "2020",
- "2021"
- ],
- "package": "All"
- },
- "Lexus NX Hybrid 2018-19": {
- "platform": "LEXUS_NX",
- "make": "Lexus",
- "brand": "toyota",
- "model": "NX Hybrid",
- "year": [
- "2018",
- "2019"
- ],
- "package": "All"
- },
- "Lexus NX Hybrid 2020-21": {
- "platform": "LEXUS_NX_TSS2",
- "make": "Lexus",
- "brand": "toyota",
- "model": "NX Hybrid",
- "year": [
- "2020",
- "2021"
- ],
- "package": "All"
- },
- "Lexus RC 2018-20": {
- "platform": "LEXUS_RC",
- "make": "Lexus",
- "brand": "toyota",
- "model": "RC",
- "year": [
- "2018",
- "2019",
- "2020"
- ],
- "package": "All"
- },
- "Lexus RC 2023": {
- "platform": "LEXUS_RC_TSS2",
- "make": "Lexus",
- "brand": "toyota",
- "model": "RC",
- "year": [
- "2023"
- ],
- "package": "All"
- },
- "Lexus RX 2016": {
- "platform": "LEXUS_RX",
- "make": "Lexus",
- "brand": "toyota",
- "model": "RX",
- "year": [
- "2016"
- ],
- "package": "Lexus Safety System+"
- },
- "Lexus RX 2017-19": {
- "platform": "LEXUS_RX",
- "make": "Lexus",
- "brand": "toyota",
- "model": "RX",
- "year": [
- "2017",
- "2018",
- "2019"
- ],
- "package": "All"
- },
- "Lexus RX 2020-22": {
- "platform": "LEXUS_RX_TSS2",
- "make": "Lexus",
- "brand": "toyota",
- "model": "RX",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Lexus RX Hybrid 2016": {
- "platform": "LEXUS_RX",
- "make": "Lexus",
- "brand": "toyota",
- "model": "RX Hybrid",
- "year": [
- "2016"
- ],
- "package": "Lexus Safety System+"
- },
- "Lexus RX Hybrid 2017-19": {
- "platform": "LEXUS_RX",
- "make": "Lexus",
- "brand": "toyota",
- "model": "RX Hybrid",
- "year": [
- "2017",
- "2018",
- "2019"
- ],
- "package": "All"
- },
- "Lexus RX Hybrid 2020-22": {
- "platform": "LEXUS_RX_TSS2",
- "make": "Lexus",
- "brand": "toyota",
- "model": "RX Hybrid",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Lexus UX Hybrid 2019-24": {
- "platform": "TOYOTA_COROLLA_TSS2",
- "make": "Lexus",
- "brand": "toyota",
- "model": "UX Hybrid",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "All"
- },
- "Lincoln Aviator 2020-24": {
- "platform": "FORD_EXPLORER_MK6",
- "make": "Lincoln",
- "brand": "ford",
- "model": "Aviator",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "Co-Pilot360 Plus"
- },
- "Lincoln Aviator Plug-in Hybrid 2020-24": {
- "platform": "FORD_EXPLORER_MK6",
- "make": "Lincoln",
- "brand": "ford",
- "model": "Aviator Plug-in Hybrid",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "Co-Pilot360 Plus"
- },
- "MAN eTGE 2020-24": {
- "platform": "VOLKSWAGEN_CRAFTER_MK2",
- "make": "MAN",
- "brand": "volkswagen",
- "model": "eTGE",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "MAN TGE 2017-24": {
- "platform": "VOLKSWAGEN_CRAFTER_MK2",
- "make": "MAN",
- "brand": "volkswagen",
- "model": "TGE",
- "year": [
- "2017",
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Mazda CX-5 2022-25": {
- "platform": "MAZDA_CX5_2022",
- "make": "Mazda",
- "brand": "mazda",
- "model": "CX-5",
- "year": [
- "2022",
- "2023",
- "2024",
- "2025"
- ],
- "package": "All"
- },
- "Mazda CX-9 2021-23": {
- "platform": "MAZDA_CX9_2021",
- "make": "Mazda",
- "brand": "mazda",
- "model": "CX-9",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Nissan Altima 2019-20, 2024": {
- "platform": "NISSAN_ALTIMA",
- "make": "Nissan",
- "brand": "nissan",
- "model": "Altima",
- "year": [
- "2019",
- "2020",
- "2024"
- ],
- "package": "ProPILOT Assist"
- },
- "Nissan Leaf 2018-23": {
- "platform": "NISSAN_LEAF",
- "make": "Nissan",
- "brand": "nissan",
- "model": "Leaf",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "ProPILOT Assist"
- },
- "Nissan Rogue 2018-20": {
- "platform": "NISSAN_ROGUE",
- "make": "Nissan",
- "brand": "nissan",
- "model": "Rogue",
- "year": [
- "2018",
- "2019",
- "2020"
- ],
- "package": "ProPILOT Assist"
- },
- "Nissan X-Trail 2017": {
- "platform": "NISSAN_XTRAIL",
- "make": "Nissan",
- "brand": "nissan",
- "model": "X-Trail",
- "year": [
- "2017"
- ],
- "package": "ProPILOT Assist"
- },
- "Ram 1500 2019-24": {
- "platform": "RAM_1500_5TH_GEN",
- "make": "Ram",
- "brand": "chrysler",
- "model": "1500",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "Adaptive Cruise Control (ACC)"
- },
- "Ram 2500 2020-24": {
- "platform": "RAM_HD_5TH_GEN",
- "make": "Ram",
- "brand": "chrysler",
- "model": "2500",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "Adaptive Cruise Control (ACC)"
- },
- "Ram 3500 2019-22": {
- "platform": "RAM_HD_5TH_GEN",
- "make": "Ram",
- "brand": "chrysler",
- "model": "3500",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "Adaptive Cruise Control (ACC)"
- },
- "Rivian R1S 2022-24": {
- "platform": "RIVIAN_R1_GEN1",
- "make": "Rivian",
- "brand": "rivian",
- "model": "R1S",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "All"
- },
- "Rivian R1T 2022-24": {
- "platform": "RIVIAN_R1_GEN1",
- "make": "Rivian",
- "brand": "rivian",
- "model": "R1T",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "All"
- },
- "SEAT Ateca 2016-23": {
- "platform": "SEAT_ATECA_MK1",
- "make": "SEAT",
- "brand": "volkswagen",
- "model": "Ateca",
- "year": [
- "2016",
- "2017",
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "SEAT Leon 2014-20": {
- "platform": "SEAT_ATECA_MK1",
- "make": "SEAT",
- "brand": "volkswagen",
- "model": "Leon",
- "year": [
- "2014",
- "2015",
- "2016",
- "2017",
- "2018",
- "2019",
- "2020"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Subaru Ascent 2019-21": {
- "platform": "SUBARU_ASCENT",
- "make": "Subaru",
- "brand": "subaru",
- "model": "Ascent",
- "year": [
- "2019",
- "2020",
- "2021"
- ],
- "package": "All"
- },
- "Subaru Crosstrek 2018-19": {
- "platform": "SUBARU_IMPREZA",
- "make": "Subaru",
- "brand": "subaru",
- "model": "Crosstrek",
- "year": [
- "2018",
- "2019"
- ],
- "package": "EyeSight Driver Assistance"
- },
- "Subaru Crosstrek 2020-23": {
- "platform": "SUBARU_IMPREZA_2020",
- "make": "Subaru",
- "brand": "subaru",
- "model": "Crosstrek",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "EyeSight Driver Assistance"
- },
- "Subaru Forester 2017-18": {
- "platform": "SUBARU_FORESTER_PREGLOBAL",
- "make": "Subaru",
- "brand": "subaru",
- "model": "Forester",
- "year": [
- "2017",
- "2018"
- ],
- "package": "EyeSight Driver Assistance"
- },
- "Subaru Forester 2019-21": {
- "platform": "SUBARU_FORESTER",
- "make": "Subaru",
- "brand": "subaru",
- "model": "Forester",
- "year": [
- "2019",
- "2020",
- "2021"
- ],
- "package": "All"
- },
- "Subaru Impreza 2017-19": {
- "platform": "SUBARU_IMPREZA",
- "make": "Subaru",
- "brand": "subaru",
- "model": "Impreza",
- "year": [
- "2017",
- "2018",
- "2019"
- ],
- "package": "EyeSight Driver Assistance"
- },
- "Subaru Impreza 2020-22": {
- "platform": "SUBARU_IMPREZA_2020",
- "make": "Subaru",
- "brand": "subaru",
- "model": "Impreza",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "EyeSight Driver Assistance"
- },
- "Subaru Legacy 2015-18": {
- "platform": "SUBARU_LEGACY_PREGLOBAL",
- "make": "Subaru",
- "brand": "subaru",
- "model": "Legacy",
- "year": [
- "2015",
- "2016",
- "2017",
- "2018"
- ],
- "package": "EyeSight Driver Assistance"
- },
- "Subaru Legacy 2020-22": {
- "platform": "SUBARU_LEGACY",
- "make": "Subaru",
- "brand": "subaru",
- "model": "Legacy",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Subaru Outback 2015-17": {
- "platform": "SUBARU_OUTBACK_PREGLOBAL",
- "make": "Subaru",
- "brand": "subaru",
- "model": "Outback",
- "year": [
- "2015",
- "2016",
- "2017"
- ],
- "package": "EyeSight Driver Assistance"
- },
- "Subaru Outback 2018-19": {
- "platform": "SUBARU_OUTBACK_PREGLOBAL_2018",
- "make": "Subaru",
- "brand": "subaru",
- "model": "Outback",
- "year": [
- "2018",
- "2019"
- ],
- "package": "EyeSight Driver Assistance"
- },
- "Subaru Outback 2020-22": {
- "platform": "SUBARU_OUTBACK",
- "make": "Subaru",
- "brand": "subaru",
- "model": "Outback",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Subaru XV 2018-19": {
- "platform": "SUBARU_IMPREZA",
- "make": "Subaru",
- "brand": "subaru",
- "model": "XV",
- "year": [
- "2018",
- "2019"
- ],
- "package": "EyeSight Driver Assistance"
- },
- "Subaru XV 2020-21": {
- "platform": "SUBARU_IMPREZA_2020",
- "make": "Subaru",
- "brand": "subaru",
- "model": "XV",
- "year": [
- "2020",
- "2021"
- ],
- "package": "EyeSight Driver Assistance"
- },
- "Škoda Fabia 2022-23": {
- "platform": "SKODA_FABIA_MK4",
- "make": "Škoda",
- "brand": "volkswagen",
- "model": "Fabia",
- "year": [
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Škoda Kamiq 2021-23": {
- "platform": "SKODA_KAMIQ_MK1",
- "make": "Škoda",
- "brand": "volkswagen",
- "model": "Kamiq",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Škoda Karoq 2019-23": {
- "platform": "SKODA_KAROQ_MK1",
- "make": "Škoda",
- "brand": "volkswagen",
- "model": "Karoq",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Škoda Kodiaq 2017-23": {
- "platform": "SKODA_KODIAQ_MK1",
- "make": "Škoda",
- "brand": "volkswagen",
- "model": "Kodiaq",
- "year": [
- "2017",
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Škoda Octavia 2015-19": {
- "platform": "SKODA_OCTAVIA_MK3",
- "make": "Škoda",
- "brand": "volkswagen",
- "model": "Octavia",
- "year": [
- "2015",
- "2016",
- "2017",
- "2018",
- "2019"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Škoda Octavia RS 2016": {
- "platform": "SKODA_OCTAVIA_MK3",
- "make": "Škoda",
- "brand": "volkswagen",
- "model": "Octavia RS",
- "year": [
- "2016"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Škoda Octavia Scout 2017-19": {
- "platform": "SKODA_OCTAVIA_MK3",
- "make": "Škoda",
- "brand": "volkswagen",
- "model": "Octavia Scout",
- "year": [
- "2017",
- "2018",
- "2019"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Škoda Scala 2020-23": {
- "platform": "SKODA_KAMIQ_MK1",
- "make": "Škoda",
- "brand": "volkswagen",
- "model": "Scala",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Škoda Superb 2015-22": {
- "platform": "SKODA_SUPERB_MK3",
- "make": "Škoda",
- "brand": "volkswagen",
- "model": "Superb",
- "year": [
- "2015",
- "2016",
- "2017",
- "2018",
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Tesla Model 3 (with HW3) 2019-23": {
- "platform": "TESLA_MODEL_3",
- "make": "Tesla",
- "brand": "tesla",
- "model": "Model 3 (with HW3)",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Tesla Model 3 (with HW4) 2024-25": {
- "platform": "TESLA_MODEL_3",
- "make": "Tesla",
- "brand": "tesla",
- "model": "Model 3 (with HW4)",
- "year": [
- "2024",
- "2025"
- ],
- "package": "All"
- },
- "Tesla Model X (with HW4) 2024": {
- "platform": "TESLA_MODEL_X",
- "make": "Tesla",
- "brand": "tesla",
- "model": "Model X (with HW4)",
- "year": [
- "2024"
- ],
- "package": "All"
- },
- "Tesla Model Y (with HW3) 2020-23": {
- "platform": "TESLA_MODEL_Y",
- "make": "Tesla",
- "brand": "tesla",
- "model": "Model Y (with HW3)",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Tesla Model Y (with HW4) 2024-25": {
- "platform": "TESLA_MODEL_Y",
- "make": "Tesla",
- "brand": "tesla",
- "model": "Model Y (with HW4)",
- "year": [
- "2024",
- "2025"
- ],
- "package": "All"
- },
- "Toyota Alphard 2019-20": {
- "platform": "TOYOTA_ALPHARD_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Alphard",
- "year": [
- "2019",
- "2020"
- ],
- "package": "All"
- },
- "Toyota Alphard Hybrid 2021": {
- "platform": "TOYOTA_ALPHARD_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Alphard Hybrid",
- "year": [
- "2021"
- ],
- "package": "All"
- },
- "Toyota Avalon 2016": {
- "platform": "TOYOTA_AVALON",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Avalon",
- "year": [
- "2016"
- ],
- "package": "Toyota Safety Sense P"
- },
- "Toyota Avalon 2017-18": {
- "platform": "TOYOTA_AVALON",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Avalon",
- "year": [
- "2017",
- "2018"
- ],
- "package": "All"
- },
- "Toyota Avalon 2019-21": {
- "platform": "TOYOTA_AVALON_2019",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Avalon",
- "year": [
- "2019",
- "2020",
- "2021"
- ],
- "package": "All"
- },
- "Toyota Avalon 2022": {
- "platform": "TOYOTA_AVALON_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Avalon",
- "year": [
- "2022"
- ],
- "package": "All"
- },
- "Toyota Avalon Hybrid 2019-21": {
- "platform": "TOYOTA_AVALON_2019",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Avalon Hybrid",
- "year": [
- "2019",
- "2020",
- "2021"
- ],
- "package": "All"
- },
- "Toyota Avalon Hybrid 2022": {
- "platform": "TOYOTA_AVALON_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Avalon Hybrid",
- "year": [
- "2022"
- ],
- "package": "All"
- },
- "Toyota C-HR 2017-20": {
- "platform": "TOYOTA_CHR",
- "make": "Toyota",
- "brand": "toyota",
- "model": "C-HR",
- "year": [
- "2017",
- "2018",
- "2019",
- "2020"
- ],
- "package": "All"
- },
- "Toyota C-HR 2021": {
- "platform": "TOYOTA_CHR_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "C-HR",
- "year": [
- "2021"
- ],
- "package": "All"
- },
- "Toyota C-HR Hybrid 2017-20": {
- "platform": "TOYOTA_CHR",
- "make": "Toyota",
- "brand": "toyota",
- "model": "C-HR Hybrid",
- "year": [
- "2017",
- "2018",
- "2019",
- "2020"
- ],
- "package": "All"
- },
- "Toyota C-HR Hybrid 2021-22": {
- "platform": "TOYOTA_CHR_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "C-HR Hybrid",
- "year": [
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Toyota Camry 2018-20": {
- "platform": "TOYOTA_CAMRY",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Camry",
- "year": [
- "2018",
- "2019",
- "2020"
- ],
- "package": "All"
- },
- "Toyota Camry 2021-24": {
- "platform": "TOYOTA_CAMRY_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Camry",
- "year": [
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "All"
- },
- "Toyota Camry Hybrid 2018-20": {
- "platform": "TOYOTA_CAMRY",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Camry Hybrid",
- "year": [
- "2018",
- "2019",
- "2020"
- ],
- "package": "All"
- },
- "Toyota Camry Hybrid 2021-24": {
- "platform": "TOYOTA_CAMRY_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Camry Hybrid",
- "year": [
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "All"
- },
- "Toyota Corolla 2017-19": {
- "platform": "TOYOTA_COROLLA",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Corolla",
- "year": [
- "2017",
- "2018",
- "2019"
- ],
- "package": "All"
- },
- "Toyota Corolla 2020-22": {
- "platform": "TOYOTA_COROLLA_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Corolla",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Toyota Corolla Cross (Non-US only) 2020-23": {
- "platform": "TOYOTA_COROLLA_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Corolla Cross (Non-US only)",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Toyota Corolla Cross Hybrid (Non-US only) 2020-22": {
- "platform": "TOYOTA_COROLLA_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Corolla Cross Hybrid (Non-US only)",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Toyota Corolla Hatchback 2019-22": {
- "platform": "TOYOTA_COROLLA_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Corolla Hatchback",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Toyota Corolla Hybrid 2020-22": {
- "platform": "TOYOTA_COROLLA_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Corolla Hybrid",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Toyota Corolla Hybrid (South America only) 2020-23": {
- "platform": "TOYOTA_COROLLA_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Corolla Hybrid (South America only)",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Toyota Highlander 2017-19": {
- "platform": "TOYOTA_HIGHLANDER",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Highlander",
- "year": [
- "2017",
- "2018",
- "2019"
- ],
- "package": "All"
- },
- "Toyota Highlander 2020-23": {
- "platform": "TOYOTA_HIGHLANDER_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Highlander",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Toyota Highlander Hybrid 2017-19": {
- "platform": "TOYOTA_HIGHLANDER",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Highlander Hybrid",
- "year": [
- "2017",
- "2018",
- "2019"
- ],
- "package": "All"
- },
- "Toyota Highlander Hybrid 2020-23": {
- "platform": "TOYOTA_HIGHLANDER_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Highlander Hybrid",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Toyota Mirai 2021": {
- "platform": "TOYOTA_MIRAI",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Mirai",
- "year": [
- "2021"
- ],
- "package": "All"
- },
- "Toyota Prius 2016": {
- "platform": "TOYOTA_PRIUS",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Prius",
- "year": [
- "2016"
- ],
- "package": "Toyota Safety Sense P"
- },
- "Toyota Prius 2017-20": {
- "platform": "TOYOTA_PRIUS",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Prius",
- "year": [
- "2017",
- "2018",
- "2019",
- "2020"
- ],
- "package": "All"
- },
- "Toyota Prius 2021-22": {
- "platform": "TOYOTA_PRIUS_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Prius",
- "year": [
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Toyota Prius Prime 2017-20": {
- "platform": "TOYOTA_PRIUS",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Prius Prime",
- "year": [
- "2017",
- "2018",
- "2019",
- "2020"
- ],
- "package": "All"
- },
- "Toyota Prius Prime 2021-22": {
- "platform": "TOYOTA_PRIUS_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Prius Prime",
- "year": [
- "2021",
- "2022"
- ],
- "package": "All"
- },
- "Toyota Prius v 2017": {
- "platform": "TOYOTA_PRIUS_V",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Prius v",
- "year": [
- "2017"
- ],
- "package": "Toyota Safety Sense P"
- },
- "Toyota RAV4 2016": {
- "platform": "TOYOTA_RAV4",
- "make": "Toyota",
- "brand": "toyota",
- "model": "RAV4",
- "year": [
- "2016"
- ],
- "package": "Toyota Safety Sense P"
- },
- "Toyota RAV4 2017-18": {
- "platform": "TOYOTA_RAV4",
- "make": "Toyota",
- "brand": "toyota",
- "model": "RAV4",
- "year": [
- "2017",
- "2018"
- ],
- "package": "All"
- },
- "Toyota RAV4 2019-21": {
- "platform": "TOYOTA_RAV4_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "RAV4",
- "year": [
- "2019",
- "2020",
- "2021"
- ],
- "package": "All"
- },
- "Toyota RAV4 2022": {
- "platform": "TOYOTA_RAV4_TSS2_2022",
- "make": "Toyota",
- "brand": "toyota",
- "model": "RAV4",
- "year": [
- "2022"
- ],
- "package": "All"
- },
- "Toyota RAV4 2023-25": {
- "platform": "TOYOTA_RAV4_TSS2_2023",
- "make": "Toyota",
- "brand": "toyota",
- "model": "RAV4",
- "year": [
- "2023",
- "2024",
- "2025"
- ],
- "package": "All"
- },
- "Toyota RAV4 Hybrid 2016": {
- "platform": "TOYOTA_RAV4H",
- "make": "Toyota",
- "brand": "toyota",
- "model": "RAV4 Hybrid",
- "year": [
- "2016"
- ],
- "package": "Toyota Safety Sense P"
- },
- "Toyota RAV4 Hybrid 2017-18": {
- "platform": "TOYOTA_RAV4H",
- "make": "Toyota",
- "brand": "toyota",
- "model": "RAV4 Hybrid",
- "year": [
- "2017",
- "2018"
- ],
- "package": "All"
- },
- "Toyota RAV4 Hybrid 2019-21": {
- "platform": "TOYOTA_RAV4_TSS2",
- "make": "Toyota",
- "brand": "toyota",
- "model": "RAV4 Hybrid",
- "year": [
- "2019",
- "2020",
- "2021"
- ],
- "package": "All"
- },
- "Toyota RAV4 Hybrid 2022": {
- "platform": "TOYOTA_RAV4_TSS2_2022",
- "make": "Toyota",
- "brand": "toyota",
- "model": "RAV4 Hybrid",
- "year": [
- "2022"
- ],
- "package": "All"
- },
- "Toyota RAV4 Hybrid 2023-25": {
- "platform": "TOYOTA_RAV4_TSS2_2023",
- "make": "Toyota",
- "brand": "toyota",
- "model": "RAV4 Hybrid",
- "year": [
- "2023",
- "2024",
- "2025"
- ],
- "package": "All"
- },
- "Toyota Sienna 2018-20": {
- "platform": "TOYOTA_SIENNA",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Sienna",
- "year": [
- "2018",
- "2019",
- "2020"
- ],
- "package": "All"
- },
- "Toyota Sienna 4th Gen 2021-23": {
- "platform": "TOYOTA_SIENNA_4TH_GEN",
- "make": "Toyota",
- "brand": "toyota",
- "model": "Sienna",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "All"
- },
- "Volkswagen Arteon 2018-23": {
- "platform": "VOLKSWAGEN_ARTEON_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Arteon",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Arteon eHybrid 2020-23": {
- "platform": "VOLKSWAGEN_ARTEON_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Arteon eHybrid",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Arteon R 2020-23": {
- "platform": "VOLKSWAGEN_ARTEON_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Arteon R",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Arteon Shooting Brake 2020-23": {
- "platform": "VOLKSWAGEN_ARTEON_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Arteon Shooting Brake",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Atlas 2018-23": {
- "platform": "VOLKSWAGEN_ATLAS_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Atlas",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Atlas Cross Sport 2020-22": {
- "platform": "VOLKSWAGEN_ATLAS_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Atlas Cross Sport",
- "year": [
- "2020",
- "2021",
- "2022"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen California 2021-23": {
- "platform": "VOLKSWAGEN_TRANSPORTER_T61",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "California",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Caravelle 2020": {
- "platform": "VOLKSWAGEN_TRANSPORTER_T61",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Caravelle",
- "year": [
- "2020"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen CC 2018-22": {
- "platform": "VOLKSWAGEN_ARTEON_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "CC",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Crafter 2017-24": {
- "platform": "VOLKSWAGEN_CRAFTER_MK2",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Crafter",
- "year": [
- "2017",
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen e-Crafter 2018-24": {
- "platform": "VOLKSWAGEN_CRAFTER_MK2",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "e-Crafter",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen e-Golf 2014-20": {
- "platform": "VOLKSWAGEN_GOLF_MK7",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "e-Golf",
- "year": [
- "2014",
- "2015",
- "2016",
- "2017",
- "2018",
- "2019",
- "2020"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Golf 2015-20": {
- "platform": "VOLKSWAGEN_GOLF_MK7",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Golf",
- "year": [
- "2015",
- "2016",
- "2017",
- "2018",
- "2019",
- "2020"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Golf 2020-25": {
- "platform": "VOLKSWAGEN_GOLF_MK8",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Golf",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023",
- "2024",
- "2025"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Golf Alltrack 2015-19": {
- "platform": "VOLKSWAGEN_GOLF_MK7",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Golf Alltrack",
- "year": [
- "2015",
- "2016",
- "2017",
- "2018",
- "2019"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Golf GTD 2015-20": {
- "platform": "VOLKSWAGEN_GOLF_MK7",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Golf GTD",
- "year": [
- "2015",
- "2016",
- "2017",
- "2018",
- "2019",
- "2020"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Golf GTE 2015-20": {
- "platform": "VOLKSWAGEN_GOLF_MK7",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Golf GTE",
- "year": [
- "2015",
- "2016",
- "2017",
- "2018",
- "2019",
- "2020"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Golf GTI 2015-21": {
- "platform": "VOLKSWAGEN_GOLF_MK7",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Golf GTI",
- "year": [
- "2015",
- "2016",
- "2017",
- "2018",
- "2019",
- "2020",
- "2021"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Golf R 2015-19": {
- "platform": "VOLKSWAGEN_GOLF_MK7",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Golf R",
- "year": [
- "2015",
- "2016",
- "2017",
- "2018",
- "2019"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Golf SportsVan 2015-20": {
- "platform": "VOLKSWAGEN_GOLF_MK7",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Golf SportsVan",
- "year": [
- "2015",
- "2016",
- "2017",
- "2018",
- "2019",
- "2020"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Grand California 2019-24": {
- "platform": "VOLKSWAGEN_CRAFTER_MK2",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Grand California",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen ID.3 2020-23": {
- "platform": "VOLKSWAGEN_ID3_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "ID.3",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen ID.3 2024-25": {
- "platform": "VOLKSWAGEN_ID3_MK2",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "ID.3",
- "year": [
- "2024",
- "2025"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen ID.4 2021-23": {
- "platform": "VOLKSWAGEN_ID4_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "ID.4",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen ID.4 2024-25": {
- "platform": "VOLKSWAGEN_ID4_MK2",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "ID.4",
- "year": [
- "2024",
- "2025"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen ID.5 2022-23": {
- "platform": "VOLKSWAGEN_ID4_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "ID.5",
- "year": [
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Jetta 2019-23": {
- "platform": "VOLKSWAGEN_JETTA_MK7",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Jetta",
- "year": [
- "2019",
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Jetta MK6 2015-2018": {
- "platform": "VOLKSWAGEN_JETTA_MK6",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Jetta",
- "year": [
- "2015",
- "2016",
- "2017",
- "2018"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Jetta GLI 2021-23": {
- "platform": "VOLKSWAGEN_JETTA_MK7",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Jetta GLI",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Passat 2015-22 (B8)": {
- "platform": "VOLKSWAGEN_PASSAT_MK8",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Passat",
- "year": [
- "2015",
- "2016",
- "2017",
- "2018",
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Passat 2012-2014 (B7)": {
- "platform": "VOLKSWAGEN_PASSAT_MK7",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Passat",
- "year": [
- "2012",
- "2013",
- "2014"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Passat NMS+ 2018-22": {
- "platform": "VOLKSWAGEN_PASSAT_NMS_PLUS",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Passat",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Passat NMS 2015-17": {
- "platform": "VOLKSWAGEN_PASSAT_NMS",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Passat",
- "year": [
- "2015",
- "2016",
- "2017"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Caddy MK3 2015-22": {
- "platform": "VOLKSWAGEN_CADDY_MK3",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Caddy",
- "year": [
- "2019"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "SEAT Alhambra 2018-2020": {
- "platform": "VOLKSWAGEN_SHARAN_MK2",
- "make": "SEAT",
- "brand": "volkswagen",
- "model": "Alhambra",
- "year": [
- "2018",
- "2019",
- "2020"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Sharan 2018-2022": {
- "platform": "VOLKSWAGEN_SHARAN_MK2",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Sharan",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Passat Alltrack 2015-22": {
- "platform": "VOLKSWAGEN_PASSAT_MK8",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Passat Alltrack",
- "year": [
- "2015",
- "2016",
- "2017",
- "2018",
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Škoda Enyaq 2021-23": {
- "platform": "SKODA_ENYAQ_MK1",
- "make": "Škoda",
- "brand": "volkswagen",
- "model": "Enyaq",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Škoda Enyaq 2024-25": {
- "platform": "SKODA_ENYAQ_MK2",
- "make": "Škoda",
- "brand": "volkswagen",
- "model": "Enyaq",
- "year": [
- "2024",
- "2025"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen MEB Gen 1 2020-23": {
- "platform": "VOLKSWAGEN_ID3_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "MEB Gen 1",
- "year": [
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen MEB Gen 2 2024-25": {
- "platform": "VOLKSWAGEN_ID3_MK2",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "MEB Gen 2",
- "year": [
- "2024",
- "2025"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "CUPRA Born 2022-23": {
- "platform": "CUPRA_BORN_MK1",
- "make": "CUPRA",
- "brand": "volkswagen",
- "model": "Born",
- "year": [
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Passat GTE 2015-22": {
- "platform": "VOLKSWAGEN_PASSAT_MK8",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Passat GTE",
- "year": [
- "2015",
- "2016",
- "2017",
- "2018",
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Polo 2018-23": {
- "platform": "VOLKSWAGEN_POLO_MK6",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Polo",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Polo GTI 2018-23": {
- "platform": "VOLKSWAGEN_POLO_MK6",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Polo GTI",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen T-Cross 2021": {
- "platform": "VOLKSWAGEN_TCROSS_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "T-Cross",
- "year": [
- "2021"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen T-Roc 2018-23": {
- "platform": "VOLKSWAGEN_TROC_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "T-Roc",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Taos 2022-24": {
- "platform": "VOLKSWAGEN_TAOS_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Taos",
- "year": [
- "2022",
- "2023",
- "2024"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Teramont 2018-22": {
- "platform": "VOLKSWAGEN_ATLAS_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Teramont",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021",
- "2022"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Teramont Cross Sport 2021-22": {
- "platform": "VOLKSWAGEN_ATLAS_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Teramont Cross Sport",
- "year": [
- "2021",
- "2022"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Teramont X 2021-22": {
- "platform": "VOLKSWAGEN_ATLAS_MK1",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Teramont X",
- "year": [
- "2021",
- "2022"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Tiguan 2018-24": {
- "platform": "VOLKSWAGEN_TIGUAN_MK2",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Tiguan",
- "year": [
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023",
- "2024"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Tiguan eHybrid 2021-23": {
- "platform": "VOLKSWAGEN_TIGUAN_MK2",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Tiguan eHybrid",
- "year": [
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- },
- "Volkswagen Touran 2016-23": {
- "platform": "VOLKSWAGEN_TOURAN_MK2",
- "make": "Volkswagen",
- "brand": "volkswagen",
- "model": "Touran",
- "year": [
- "2016",
- "2017",
- "2018",
- "2019",
- "2020",
- "2021",
- "2022",
- "2023"
- ],
- "package": "Adaptive Cruise Control (ACC) & Lane Assist"
- }
-}
diff --git a/iqdbc_repo/iqdbc/lvbs/car/chrysler/__init__.py b/iqdbc_repo/iqdbc/lvbs/car/chrysler/__init__.py
index 297dca9..e69de29 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/chrysler/__init__.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/chrysler/__init__.py
@@ -1,3 +0,0 @@
-"""
-Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
diff --git a/iqdbc_repo/iqdbc/lvbs/car/chrysler/aol.py b/iqdbc_repo/iqdbc/lvbs/car/chrysler/aol.py
index fd0497b..3486417 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/chrysler/aol.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/chrysler/aol.py
@@ -1,21 +1,23 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
+Always-on-Lateral adapter for Chrysler. CarState reads the LKAS toggle button
+(and the forwarded LKAS heartbeat); CarController tracks the AOL state and, when
+AOL is available, drives the LKAS_DISABLED bit the dash reads from the heartbeat.
+"""
from enum import StrEnum
from collections import namedtuple
from iqdbc.car import Bus, structs
from iqdbc.car.chrysler.values import RAM_CARS
-
from iqdbc.lvbs.aol_base import AolCarStateBase
from iqdbc.can.parser import CANParser
-AolDataIQ = namedtuple("AolDataIQ",
- ["enable_aol", "paused", "lkas_disabled"])
-
+AolDataIQ = namedtuple("AolDataIQ", ["enable_aol", "paused", "lkas_disabled"])
ButtonType = structs.CarState.ButtonEvent.Type
+_HEARTBIT_FIELDS = ("LKAS_DISABLED", "AUTO_HIGH_BEAM", "FORWARD_1", "FORWARD_2", "FORWARD_3")
+
class AolCarController:
def __init__(self):
@@ -23,28 +25,18 @@ class AolCarController:
@staticmethod
def create_lkas_heartbit(packer, lkas_heartbit, aol):
- # LKAS_HEARTBIT (0x2D9) LKAS heartbeat
- values = {s: lkas_heartbit[s] for s in [
- "LKAS_DISABLED",
- "AUTO_HIGH_BEAM",
- "FORWARD_1",
- "FORWARD_2",
- "FORWARD_3",
- ]}
-
+ values = {name: lkas_heartbit[name] for name in _HEARTBIT_FIELDS}
if aol.enable_aol:
values["LKAS_DISABLED"] = 1 if aol.lkas_disabled else 0
-
return packer.make_can_msg("LKAS_HEARTBIT", 0, values)
@staticmethod
def aol_status_update(CC: structs.CarControl, CC_IQ: structs.IQCarControl, CS) -> AolDataIQ:
enable_aol = CC_IQ.aol.available
paused = CC_IQ.aol.enabled and not CC.latActive
-
+ # A tap of the LKAS button flips the driver's "LKAS disabled" preference.
if any(be.type == ButtonType.lkas and be.pressed for be in CS.out.buttonEvents):
CS.lkas_disabled = not CS.lkas_disabled
-
return AolDataIQ(enable_aol, paused, CS.lkas_disabled)
def update(self, CC: structs.CarControl, CC_IQ: structs.IQCarControl, CS) -> None:
@@ -55,35 +47,27 @@ class AolCarState(AolCarStateBase):
def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
super().__init__(CP, CP_IQ)
self.lkas_heartbit = 0
-
self.init_lkas_disabled = False
self.lkas_disabled = False
@staticmethod
def get_parser(CP, pt_messages, cam_messages) -> None:
if CP.carFingerprint in RAM_CARS:
- pt_messages += [
- ("Center_Stack_2", 1),
- ]
+ pt_messages.append(("Center_Stack_2", 1))
else:
pt_messages.append(("TRACTION_BUTTON", 1))
cam_messages.append(("LKAS_HEARTBIT", 1))
- def get_lkas_button(self, cp, cp_cam):
+ def _read_lkas_button(self, cp, cp_cam) -> int:
if self.CP.carFingerprint in RAM_CARS:
- lkas_button = cp.vl["Center_Stack_2"]["LKAS_Button"]
- else:
- lkas_button = cp.vl["TRACTION_BUTTON"]["TOGGLE_LKAS"]
- self.lkas_heartbit = cp_cam.vl["LKAS_HEARTBIT"]
- if not self.init_lkas_disabled:
- self.lkas_disabled = cp_cam.vl["LKAS_HEARTBIT"]["LKAS_DISABLED"]
- self.init_lkas_disabled = True
+ return cp.vl["Center_Stack_2"]["LKAS_Button"]
- return lkas_button
+ self.lkas_heartbit = cp_cam.vl["LKAS_HEARTBIT"]
+ if not self.init_lkas_disabled:
+ self.lkas_disabled = cp_cam.vl["LKAS_HEARTBIT"]["LKAS_DISABLED"]
+ self.init_lkas_disabled = True
+ return cp.vl["TRACTION_BUTTON"]["TOGGLE_LKAS"]
def update_aol(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
- cp = can_parsers[Bus.pt]
- cp_cam = can_parsers[Bus.cam]
-
self.prev_lkas_button = self.lkas_button
- self.lkas_button = self.get_lkas_button(cp, cp_cam)
+ self.lkas_button = self._read_lkas_button(can_parsers[Bus.pt], can_parsers[Bus.cam])
diff --git a/iqdbc_repo/iqdbc/lvbs/car/chrysler/carstate_ext.py b/iqdbc_repo/iqdbc/lvbs/car/chrysler/carstate_ext.py
deleted file mode 100644
index 7769e61..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/chrysler/carstate_ext.py
+++ /dev/null
@@ -1,37 +0,0 @@
-
-"""
-Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
-
-from enum import StrEnum
-
-from iqdbc.car import Bus, structs
-from iqdbc.can.parser import CANParser
-from iqdbc.car.chrysler.values import RAM_HD
-from iqdbc.lvbs.car.chrysler.values_ext import BUTTONS
-
-
-class CarStateExt:
- def __init__(self, CP, CP_IQ):
- self.CP = CP
- self.CP_IQ = CP_IQ
-
- self.button_events = []
- self.button_states = {button.event_type: False for button in BUTTONS}
-
- def update(self, ret: structs.CarState, ret_iq: structs.IQCarState, can_parsers: dict[StrEnum, CANParser]):
- cp = can_parsers[Bus.pt]
-
- button_events = []
- for button in BUTTONS:
- state = (cp.vl[button.can_addr][button.can_msg] in button.values)
- if self.button_states[button.event_type] != state:
- event = structs.CarState.ButtonEvent.new_message()
- event.type = button.event_type
- event.pressed = state
- button_events.append(event)
- self.button_states[button.event_type] = state
- self.button_events = button_events
-
- if self.CP.carFingerprint in RAM_HD:
- ret.steeringAngleDeg = cp.vl["STEERING"]["STEERING_ANGLE"]
diff --git a/iqdbc_repo/iqdbc/lvbs/car/chrysler/carcontroller_ext.py b/iqdbc_repo/iqdbc/lvbs/car/chrysler/iq_carcontroller.py
similarity index 72%
rename from iqdbc_repo/iqdbc/lvbs/car/chrysler/carcontroller_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/chrysler/iq_carcontroller.py
index a19d635..140fff1 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/chrysler/carcontroller_ext.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/chrysler/iq_carcontroller.py
@@ -1,23 +1,27 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
+
+Chrysler low-speed steering gate: overrides the stock LKAS control bit when the
+no-min-steering-speed option is set, and holds the RAM DT engagement window.
"""
from iqdbc.car import structs
from iqdbc.car.interfaces import CarStateBase
from iqdbc.car.chrysler.values import RAM_DT
-from iqdbc.lvbs.car.chrysler.values_ext import ChryslerFlagsIQ
+from iqdbc.lvbs.car.chrysler.iq_values import ChryslerFlagsIQ
GearShifter = structs.CarState.GearShifter
-class CarControllerExt:
+class IQCarController:
def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
self.CP = CP
self.CP_IQ = CP_IQ
def get_lkas_control_bit(self, CS: CarStateBase, CC: structs.CarControl, lkas_control_bit: bool) -> bool:
if self.CP_IQ.flags & ChryslerFlagsIQ.NO_MIN_STEERING_SPEED:
- lkas_control_bit = CC.latActive
- elif self.CP.carFingerprint in RAM_DT:
+ return CC.latActive
+
+ if self.CP.carFingerprint in RAM_DT:
if self.CP.minEnableSpeed <= CS.out.vEgo <= self.CP.minEnableSpeed + 0.5:
lkas_control_bit = True
if self.CP.minEnableSpeed >= 14.5 and CS.out.gearShifter != GearShifter.drive:
diff --git a/iqdbc_repo/iqdbc/lvbs/car/chrysler/iq_carstate.py b/iqdbc_repo/iqdbc/lvbs/car/chrysler/iq_carstate.py
new file mode 100644
index 0000000..e92944a
--- /dev/null
+++ b/iqdbc_repo/iqdbc/lvbs/car/chrysler/iq_carstate.py
@@ -0,0 +1,32 @@
+"""
+Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
+
+Chrysler cruise-button reader: emits edge ButtonEvents for the ACC steering-wheel
+buttons so IQ.Pilot can react to accel/decel/cancel/resume.
+"""
+from enum import StrEnum
+
+from iqdbc.car import Bus, structs
+from iqdbc.can.parser import CANParser
+from iqdbc.lvbs.car.chrysler.iq_values import BUTTONS
+
+
+class IQCarState:
+ def __init__(self, CP, CP_IQ):
+ self.CP = CP
+ self.CP_IQ = CP_IQ
+ self.button_events: list = []
+ self.button_states = {button.event_type: False for button in BUTTONS}
+
+ def update(self, ret: structs.CarState, ret_iq: structs.IQCarState, can_parsers: dict[StrEnum, CANParser]) -> None:
+ cp = can_parsers[Bus.pt]
+ events = []
+ for button in BUTTONS:
+ pressed = cp.vl[button.can_addr][button.can_msg] in button.values
+ if pressed != self.button_states[button.event_type]:
+ event = structs.CarState.ButtonEvent.new_message()
+ event.type = button.event_type
+ event.pressed = pressed
+ events.append(event)
+ self.button_states[button.event_type] = pressed
+ self.button_events = events
diff --git a/iqdbc_repo/iqdbc/lvbs/car/chrysler/fingerprints_ext.py b/iqdbc_repo/iqdbc/lvbs/car/chrysler/iq_fingerprints.py
similarity index 100%
rename from iqdbc_repo/iqdbc/lvbs/car/chrysler/fingerprints_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/chrysler/iq_fingerprints.py
diff --git a/iqdbc_repo/iqdbc/lvbs/car/chrysler/values_ext.py b/iqdbc_repo/iqdbc/lvbs/car/chrysler/iq_values.py
similarity index 87%
rename from iqdbc_repo/iqdbc/lvbs/car/chrysler/values_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/chrysler/iq_values.py
index 7b966ee..caee733 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/chrysler/values_ext.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/chrysler/iq_values.py
@@ -1,7 +1,9 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
+IQ.Pilot Chrysler extension flags + the cruise-button table read by the AOL
+cruise-button reader.
+"""
from collections import namedtuple
from enum import IntFlag
@@ -20,5 +22,3 @@ BUTTONS = [
class ChryslerFlagsIQ(IntFlag):
NO_MIN_STEERING_SPEED = 1
-
-
diff --git a/iqdbc_repo/iqdbc/lvbs/car/ford/__init__.py b/iqdbc_repo/iqdbc/lvbs/car/ford/__init__.py
deleted file mode 100644
index 297dca9..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/ford/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
diff --git a/iqdbc_repo/iqdbc/lvbs/car/ford/aol.py b/iqdbc_repo/iqdbc/lvbs/car/ford/aol.py
deleted file mode 100644
index 5e427b9..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/ford/aol.py
+++ /dev/null
@@ -1,21 +0,0 @@
-"""
-Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
-
-from enum import StrEnum
-
-from iqdbc.car import Bus,structs
-
-from iqdbc.lvbs.aol_base import AolCarStateBase
-from iqdbc.can.parser import CANParser
-
-
-class AolCarState(AolCarStateBase):
- def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
- super().__init__(CP, CP_IQ)
-
- def update_aol(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
- cp = can_parsers[Bus.pt]
-
- self.prev_lkas_button = self.lkas_button
- self.lkas_button = cp.vl["Steering_Data_FD1"]["TjaButtnOnOffPress"]
diff --git a/iqdbc_repo/iqdbc/lvbs/car/gm/__init__.py b/iqdbc_repo/iqdbc/lvbs/car/gm/__init__.py
index 297dca9..e69de29 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/gm/__init__.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/gm/__init__.py
@@ -1,3 +0,0 @@
-"""
-Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
diff --git a/iqdbc_repo/iqdbc/lvbs/car/gm/interface_ext.py b/iqdbc_repo/iqdbc/lvbs/car/gm/interface_ext.py
deleted file mode 100644
index 6dcdb1a..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/gm/interface_ext.py
+++ /dev/null
@@ -1,58 +0,0 @@
-"""
-Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
-import os
-from math import exp
-
-from iqdbc.car import structs
-from iqdbc.car.common.basedir import BASEDIR
-from iqdbc.car.gm.interface import CAR
-from iqdbc.lvbs.car.interfaces import LatControlInputs, NanoFFModel, TorqueFromLateralAccelCallbackTypeTorqueSpace
-
-NON_LINEAR_TORQUE_PARAMS = {
- CAR.CHEVROLET_BOLT_EUV: [2.6531724862969748, 1.0, 0.1919764879840985, 0.009054123646805178],
- CAR.GMC_ACADIA: [4.78003305, 1.0, 0.3122, 0.05591772],
- CAR.CHEVROLET_SILVERADO: [3.29974374, 1.0, 0.25571356, 0.0465122]
-}
-
-
-class CarInterfaceExt:
- def __init__(self, CP: structs.CarParams, CI_Base):
- self.CP = CP
- self.CI_Base = CI_Base
- self.neural_ff_model = None
-
- def torque_from_lateral_accel_siglin(self, latcontrol_inputs: LatControlInputs, torque_params: structs.CarParams.LateralTorqueTuning,
- gravity_adjusted: bool) -> float:
- def sig(val):
- # https://timvieira.github.io/blog/post/2014/02/11/exp-normalize-trick
- if val >= 0:
- return 1 / (1 + exp(-val)) - 0.5
- else:
- z = exp(val)
- return z / (1 + z) - 0.5
-
- # The "lat_accel vs torque" relationship is assumed to be the sum of "sigmoid + linear" curves
- # An important thing to consider is that the slope at 0 should be > 0 (ideally >1)
- # This has big effect on the stability about 0 (noise when going straight)
- # ToDo: To generalize to other GMs, explore tanh function as the nonlinear
- non_linear_torque_params = NON_LINEAR_TORQUE_PARAMS.get(self.CP.carFingerprint)
- assert non_linear_torque_params, "The params are not defined"
- a, b, c, _ = non_linear_torque_params
- steer_torque = (sig(latcontrol_inputs.lateral_acceleration * a) * b) + (latcontrol_inputs.lateral_acceleration * c)
- return float(steer_torque)
-
- def torque_from_lateral_accel_neural(self, latcontrol_inputs: LatControlInputs, orque_params: structs.CarParams.LateralTorqueTuning,
- gravity_adjusted: bool) -> float:
- inputs = list(latcontrol_inputs)
- if gravity_adjusted:
- inputs[0] += inputs[1]
- return float(self.neural_ff_model.predict(inputs))
-
- def torque_from_lateral_accel_in_torque_space(self) -> TorqueFromLateralAccelCallbackTypeTorqueSpace:
- if self.CP.carFingerprint == CAR.CHEVROLET_BOLT_EUV:
- return self.torque_from_lateral_accel_neural
- elif self.CP.carFingerprint in NON_LINEAR_TORQUE_PARAMS:
- return self.torque_from_lateral_accel_siglin
- else:
- return self.CI_Base.torque_from_lateral_accel_linear_in_torque_space
diff --git a/iqdbc_repo/iqdbc/lvbs/car/gm/carstate_ext.py b/iqdbc_repo/iqdbc/lvbs/car/gm/iq_carstate.py
similarity index 50%
rename from iqdbc_repo/iqdbc/lvbs/car/gm/carstate_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/gm/iq_carstate.py
index 6c3ffe1..96d1344 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/gm/carstate_ext.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/gm/iq_carstate.py
@@ -1,23 +1,26 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
+
+Non-ACC GM carState: these cars have no adaptive cruise, so cruise engage/set
+speed come from the stock (non-adaptive) ECM cruise message.
"""
from enum import StrEnum
from iqdbc.car import Bus, structs
from iqdbc.car.common.conversions import Conversions as CV
from iqdbc.can.parser import CANParser
-from iqdbc.lvbs.car.gm.values_ext import GMFlagsIQ
+from iqdbc.lvbs.car.gm.iq_values import GMFlagsIQ
-class CarStateExt:
+class IQCarState:
def __init__(self, CP, CP_IQ):
self.CP = CP
self.CP_IQ = CP_IQ
def update(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
+ if not self.CP_IQ.flags & GMFlagsIQ.NON_ACC:
+ return
pt_cp = can_parsers[Bus.pt]
-
- if self.CP_IQ.flags & GMFlagsIQ.NON_ACC:
- ret.cruiseState.enabled = pt_cp.vl["ECMCruiseControl"]["CruiseActive"] != 0
- ret.cruiseState.speed = pt_cp.vl["ECMCruiseControl"]["CruiseSetSpeed"] * CV.KPH_TO_MS
- ret.accFaulted = False
+ ret.cruiseState.enabled = pt_cp.vl["ECMCruiseControl"]["CruiseActive"] != 0
+ ret.cruiseState.speed = pt_cp.vl["ECMCruiseControl"]["CruiseSetSpeed"] * CV.KPH_TO_MS
+ ret.accFaulted = False
diff --git a/iqdbc_repo/iqdbc/lvbs/car/gm/fingerprints_ext.py b/iqdbc_repo/iqdbc/lvbs/car/gm/iq_fingerprints.py
similarity index 100%
rename from iqdbc_repo/iqdbc/lvbs/car/gm/fingerprints_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/gm/iq_fingerprints.py
diff --git a/iqdbc_repo/iqdbc/lvbs/car/gm/iq_interface.py b/iqdbc_repo/iqdbc/lvbs/car/gm/iq_interface.py
new file mode 100644
index 0000000..1c7b64c
--- /dev/null
+++ b/iqdbc_repo/iqdbc/lvbs/car/gm/iq_interface.py
@@ -0,0 +1,43 @@
+"""
+Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
+
+GM torque-space feed-forward for the IQ.Pilot lateral extension: a sigmoid+linear
+lat-accel -> torque curve for the tuned platforms, else the linear default.
+"""
+from math import exp
+
+from iqdbc.car import structs
+from iqdbc.car.gm.interface import CAR
+from iqdbc.lvbs.car.interfaces import LatControlInputs, TorqueFromLateralAccelCallbackTypeTorqueSpace
+
+_NON_LINEAR_TORQUE_PARAMS = {
+ CAR.CHEVROLET_BOLT_EUV: [2.6531724862969748, 1.0, 0.1919764879840985, 0.009054123646805178],
+ CAR.GMC_ACADIA: [4.78003305, 1.0, 0.3122, 0.05591772],
+ CAR.CHEVROLET_SILVERADO: [3.29974374, 1.0, 0.25571356, 0.0465122],
+}
+
+
+class IQCarInterface:
+ def __init__(self, CP: structs.CarParams, CI_Base):
+ self.CP = CP
+ self.CI_Base = CI_Base
+
+ @staticmethod
+ def _centered_sigmoid(val: float) -> float:
+ # sigmoid shifted to pass through the origin; branch keeps exp() from overflowing
+ if val >= 0:
+ return 1.0 / (1.0 + exp(-val)) - 0.5
+ z = exp(val)
+ return z / (1.0 + z) - 0.5
+
+ def torque_from_lateral_accel_siglin(self, latcontrol_inputs: LatControlInputs,
+ torque_params: structs.CarParams.LateralTorqueTuning,
+ gravity_adjusted: bool) -> float:
+ a, b, c, _ = _NON_LINEAR_TORQUE_PARAMS[self.CP.carFingerprint]
+ lat_accel = latcontrol_inputs.lateral_acceleration
+ return float(self._centered_sigmoid(lat_accel * a) * b + lat_accel * c)
+
+ def torque_from_lateral_accel_in_torque_space(self) -> TorqueFromLateralAccelCallbackTypeTorqueSpace:
+ if self.CP.carFingerprint in _NON_LINEAR_TORQUE_PARAMS:
+ return self.torque_from_lateral_accel_siglin
+ return self.CI_Base.torque_from_lateral_accel_linear_in_torque_space
diff --git a/iqdbc_repo/iqdbc/lvbs/car/gm/values_ext.py b/iqdbc_repo/iqdbc/lvbs/car/gm/iq_values.py
similarity index 72%
rename from iqdbc_repo/iqdbc/lvbs/car/gm/values_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/gm/iq_values.py
index ddbce1a..b52d293 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/gm/values_ext.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/gm/iq_values.py
@@ -1,7 +1,8 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
+IQ.Pilot GM extension flags for the non-adaptive-cruise (Non-ACC) camera-harness port.
+"""
from enum import IntFlag
@@ -11,5 +12,3 @@ class GMFlagsIQ(IntFlag):
class GMSafetyFlagsIQ:
NON_ACC = 1
-
-
diff --git a/iqdbc_repo/iqdbc/lvbs/car/honda/carstate_ext.py b/iqdbc_repo/iqdbc/lvbs/car/honda/iq_carstate.py
similarity index 93%
rename from iqdbc_repo/iqdbc/lvbs/car/honda/carstate_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/honda/iq_carstate.py
index 006b288..830b77b 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/honda/carstate_ext.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/honda/iq_carstate.py
@@ -5,10 +5,10 @@ from enum import StrEnum
from iqdbc.car import Bus, structs
from iqdbc.can.parser import CANParser
-from iqdbc.lvbs.car.honda.values_ext import HondaFlagsIQ
+from iqdbc.lvbs.car.honda.iq_values import HondaFlagsIQ
-class CarStateExt:
+class IQCarState:
def __init__(self, CP, CP_IQ):
self.CP = CP
self.CP_IQ = CP_IQ
diff --git a/iqdbc_repo/iqdbc/lvbs/car/honda/fingerprints_ext.py b/iqdbc_repo/iqdbc/lvbs/car/honda/iq_fingerprints.py
similarity index 100%
rename from iqdbc_repo/iqdbc/lvbs/car/honda/fingerprints_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/honda/iq_fingerprints.py
diff --git a/iqdbc_repo/iqdbc/lvbs/car/honda/values_ext.py b/iqdbc_repo/iqdbc/lvbs/car/honda/iq_values.py
similarity index 100%
rename from iqdbc_repo/iqdbc/lvbs/car/honda/values_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/honda/iq_values.py
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/__init__.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/__init__.py
deleted file mode 100644
index 297dca9..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/aol.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/aol.py
deleted file mode 100644
index e07927f..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/aol.py
+++ /dev/null
@@ -1,105 +0,0 @@
-"""
-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
-
-from iqdbc.car import Bus, DT_CTRL, structs
-from iqdbc.car.hyundai.values import CAR
-
-from iqdbc.car.hyundai.values import HyundaiFlags
-from iqdbc.lvbs.car.hyundai.values import HyundaiFlagsIQ
-from iqdbc.lvbs.aol_base import AolCarStateBase
-from iqdbc.can.parser import CANParser
-
-ButtonType = structs.CarState.ButtonEvent.Type
-
-AolDataIQ = namedtuple("AolDataIQ",
- ["enable_aol", "lat_active", "disengaging", "paused"])
-
-
-class AolCarController:
- def __init__(self):
- self.aol = AolDataIQ(False, False, False, False)
-
- self.lat_disengage_blink = 0
- self.lat_disengage_init = False
- self.prev_lat_active = False
-
- 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
-
- if CC.latActive:
- self.lat_disengage_init = False
- elif self.prev_lat_active:
- self.lat_disengage_init = True
-
- if not self.lat_disengage_init:
- self.lat_disengage_blink = frame
-
- paused = CC_IQ.aol.enabled and not CC.latActive
- disengaging = (frame - self.lat_disengage_blink) * DT_CTRL < 1.0 if self.lat_disengage_init else False
-
- self.prev_lat_active = CC.latActive
-
- return AolDataIQ(enable_aol, CC.latActive, disengaging, paused)
-
- def create_lkas_icon(self, CP: structs.CarParams, enabled: bool) -> int:
- if self.aol.enable_aol:
- lkas_icon = 2 if self.aol.lat_active else 3 if self.aol.disengaging else 1
- 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
-
- return lkas_icon
-
- def create_lfa_icon(self, enabled: bool) -> int:
- if self.aol.enable_aol:
- lfa_icon = 2 if self.aol.lat_active else 3 if self.aol.disengaging else 1 if self.aol.paused else 0
- else:
- lfa_icon = 2 if enabled else 0
-
- return lfa_icon
-
- def update(self, CP: structs.CarParams, CC: structs.CarControl, CC_IQ: structs.IQCarControl, frame: int) -> None:
- self.aol = self.aol_status_update(CC, CC_IQ, frame)
- self.lkas_icon = self.create_lkas_icon(CP, CC.enabled)
- self.lfa_icon = self.create_lfa_icon(CC.enabled)
-
-
-class AolCarState(AolCarStateBase):
- def __init__(self, CP: structs.CarParams, CP_IQ: structs.CarParams):
- super().__init__(CP, CP_IQ)
- self.main_cruise_enabled: bool = False
-
- @staticmethod
- def get_parser(CP, CP_IQ, pt_messages) -> None:
- pass
-
- def get_main_cruise(self, ret: structs.CarState) -> bool:
- if self.CP_IQ.flags & HyundaiFlagsIQ.LONGITUDINAL_MAIN_CRUISE_TOGGLEABLE:
- if any(be.type == ButtonType.mainCruise and be.pressed for be in ret.buttonEvents):
- self.main_cruise_enabled = not self.main_cruise_enabled
- else:
- self.main_cruise_enabled = True
-
- return self.main_cruise_enabled if ret.cruiseState.available else False
-
- def update_aol(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
- pass
-
- def update_aol_canfd(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
- cp = can_parsers[Bus.pt]
- cp_cam = can_parsers[Bus.cam]
-
- if not self.CP.openpilotLongitudinalControl:
- cp_cruise_info = cp_cam if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else cp
- ret.cruiseState.available = cp_cruise_info.vl["SCC_CONTROL"]["MainMode_ACC"] == 1
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/carstate_ext.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/carstate_ext.py
deleted file mode 100644
index 94d7f82..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/carstate_ext.py
+++ /dev/null
@@ -1,83 +0,0 @@
-"""
-Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
-
-from enum import StrEnum
-
-from iqdbc.car import Bus, structs
-from iqdbc.can.parser import CANParser
-from iqdbc.car.hyundai.values import HyundaiFlags
-from iqdbc.lvbs.car.hyundai.values import HyundaiFlagsIQ
-
-
-class CarStateExt:
- def __init__(self, CP, CP_IQ):
- self.CP = CP
- self.CP_IQ = CP_IQ
-
- self.aBasis = 0.0
-
- def update_speed_limit(self, cp, cp_cam) -> float:
- speed_limit = 0
-
- if self.CP.flags & HyundaiFlags.CANFD:
- if self.CP_IQ.flags & HyundaiFlagsIQ.SPEED_LIMIT_AVAILABLE:
- bus = cp if self.CP.flags & HyundaiFlags.CANFD_LKA_STEERING else cp_cam
- speed_limit = bus.vl["FR_CMR_02_100ms"]["ISLW_SpdCluMainDis"]
- else:
- nav, cam = 0, 0
- if self.CP_IQ.flags & HyundaiFlagsIQ.SPEED_LIMIT_AVAILABLE:
- nav = cp.vl["Navi_HU"]["SpeedLim_Nav_Clu"]
- if self.CP_IQ.flags & HyundaiFlagsIQ.HAS_LKAS12:
- cam = cp_cam.vl["LKAS12"]["CF_Lkas_TsrSpeed_Display_Clu"]
-
- speed_limit = cam if cam not in (0, 255) else nav
-
- if speed_limit in (0, 255):
- speed_limit = 0
-
- return speed_limit
-
- def update(self, ret: structs.CarState, ret_iq: structs.IQCarState, can_parsers: dict[StrEnum, CANParser], speed_conv: float) -> None:
- cp = can_parsers[Bus.pt]
- cp_cam = can_parsers[Bus.cam]
-
- self.aBasis = cp.vl["TCS13"]["aBasis"]
-
- if self.CP_IQ.flags & HyundaiFlagsIQ.NON_SCC:
- cruise_msg = "LABEL11" if self.CP.flags & HyundaiFlags.EV else \
- "E_CRUISE_CONTROL" if self.CP.flags & HyundaiFlags.HYBRID else \
- "EMS16"
- cruise_available_sig = "CC_React" if self.CP.flags & HyundaiFlags.EV else "CRUISE_LAMP_M"
- cruise_enabled_sig = "CC_ACT" if self.CP.flags & HyundaiFlags.EV else "CRUISE_LAMP_S"
- cruise_speed_msg = "E_EMS11" if self.CP.flags & HyundaiFlags.EV else \
- "ELECT_GEAR" if self.CP.flags & HyundaiFlags.HYBRID else \
- "LVR12"
- cruise_speed_sig = "Cruise_Limit_Target" if self.CP.flags & HyundaiFlags.EV else \
- "SLC_SET_SPEED" if self.CP.flags & HyundaiFlags.HYBRID else \
- "CF_Lvr_CruiseSet"
- ret.cruiseState.available = cp.vl[cruise_msg][cruise_available_sig] != 0
- ret.cruiseState.enabled = cp.vl[cruise_msg][cruise_enabled_sig] != 0
- ret.cruiseState.speed = cp.vl[cruise_speed_msg][cruise_speed_sig] * speed_conv
- ret.cruiseState.standstill = False
- ret.cruiseState.nonAdaptive = False
-
- if not self.CP_IQ.flags & HyundaiFlagsIQ.NON_SCC_NO_FCA:
- cp_cruise = cp if self.CP_IQ.flags & HyundaiFlagsIQ.NON_SCC_RADAR_FCA else cp_cam
-
- aeb_src = "FCA11"
- aeb_warning = cp_cruise.vl[aeb_src]["CF_VSM_Warn"] != 0
- aeb_braking = cp_cruise.vl[aeb_src]["CF_VSM_DecCmdAct"] != 0 or cp_cruise.vl[aeb_src]["FCA_CmdAct"] != 0
- ret.stockFcw = aeb_warning and not aeb_braking
- ret.stockAeb = aeb_warning and aeb_braking
-
- ret_iq.speedLimit = self.update_speed_limit(cp, cp_cam) * speed_conv
-
- def update_canfd_ext(self, ret: structs.CarState, ret_iq: structs.IQCarState, can_parsers: dict[StrEnum, CANParser],
- speed_factor: float) -> None:
- cp = can_parsers[Bus.pt]
- cp_cam = can_parsers[Bus.cam]
-
- self.aBasis = cp.vl["TCS"]["aBasis"]
-
- ret_iq.speedLimit = self.update_speed_limit(cp, cp_cam) * speed_factor
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/enable_radar_tracks.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/enable_radar_tracks.py
deleted file mode 100644
index ce44b19..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/enable_radar_tracks.py
+++ /dev/null
@@ -1,71 +0,0 @@
-"""
-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
-
-DEVELOPER_DIAGNOSTIC = 0x07
-CUSTOM_DIAGNOSTIC_REQUEST = bytes([uds.SERVICE_TYPE.DIAGNOSTIC_SESSION_CONTROL, DEVELOPER_DIAGNOSTIC])
-CUSTOM_DIAGNOSTIC_RESPONSE = bytes([uds.SERVICE_TYPE.DIAGNOSTIC_SESSION_CONTROL + 0x40, DEVELOPER_DIAGNOSTIC])
-
-READ_DATA_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER])
-READ_DATA_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40])
-
-WRITE_DATA_REQUEST = bytes([uds.SERVICE_TYPE.WRITE_DATA_BY_IDENTIFIER])
-WRITE_DATA_RESPONSE = bytes([uds.SERVICE_TYPE.WRITE_DATA_BY_IDENTIFIER + 0x40])
-
-CONFIG_DATA_ID = bytes([0x01, 0x42])
-DEFAULT_CONFIG = bytes([0x00, 0x00, 0x00, 0x01, 0x00, 0x00])
-TRACKS_ENABLED_CONFIG = bytes([0x00, 0x00, 0x00, 0x01, 0x00, 0x01])
-TRACKS_ENABLED_CONFIG_BYTES = b"\x00\x00\x01\x00\x01"
-
-
-def enable_radar_tracks(logcan, sendcan, bus=0, addr=0x7d0, timeout=0.1, retry=2):
- carlog.error("radar_tracks: enabling ...")
-
- for i in range(retry):
- try:
- query = IsoTpParallelQuery(sendcan, logcan, bus, [addr], [CUSTOM_DIAGNOSTIC_REQUEST], [CUSTOM_DIAGNOSTIC_RESPONSE])
-
- for _, _ in query.get_data(timeout).items():
- carlog.error("radar_tracks: check current config ...")
-
- request = READ_DATA_REQUEST + CONFIG_DATA_ID
- query = IsoTpParallelQuery(sendcan, logcan, bus, [addr], [request], [READ_DATA_RESPONSE])
-
- for _, data in query.get_data(timeout).items():
- current_config = data[3:]
-
- carlog.error(f"radar_tracks: current config: {current_config.hex()}")
-
- if current_config == TRACKS_ENABLED_CONFIG_BYTES:
- carlog.error("radar_tracks: already enabled, skipping ...")
- else:
- carlog.error("radar_tracks: reconfigure radar to output radar points ...")
- request = WRITE_DATA_REQUEST + CONFIG_DATA_ID + TRACKS_ENABLED_CONFIG
- query = IsoTpParallelQuery(sendcan, logcan, bus, [addr], [request], [WRITE_DATA_RESPONSE])
- query.get_data(0)
-
- carlog.error("radar_tracks: successfully enabled")
-
- return True
-
- except Exception as e:
- carlog.exception(f"radar_tracks exception: {e}")
-
- carlog.error(f"radar_tracks retry ({i + 1}) ...")
- carlog.error("radar_tracks: failed")
- return False
-
-
-if __name__ == "__main__":
- import time
- import cereal.messaging as messaging
- sendcan = messaging.pub_sock('sendcan')
- logcan = messaging.sub_sock('can')
- time.sleep(1)
-
- enabled = enable_radar_tracks(logcan, sendcan, bus=0, addr=0x7d0, timeout=0.1)
- print(f"enabled: {enabled}")
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/escc.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/escc.py
deleted file mode 100644
index e9fd072..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/escc.py
+++ /dev/null
@@ -1,68 +0,0 @@
-from iqdbc.car import structs
-
-from iqdbc.lvbs.car.hyundai.values import HyundaiFlagsIQ
-
-ESCC_MSG = 0x2AB
-
-
-class EnhancedSmartCruiseControl:
- def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
- self.CP = CP
- self.CP_IQ = CP_IQ
-
- @property
- def enabled(self):
- return self.CP_IQ.flags & HyundaiFlagsIQ.ENHANCED_SCC
-
- @property
- def trigger_msg(self):
- 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
-
-
-class EsccCarStateBase:
- def __init__(self):
- self.escc_aeb_warning = 0
- self.escc_aeb_dec_cmd_act = 0
- self.escc_cmd_act = 0
- self.escc_aeb_dec_cmd = 0
-
-
-class EsccCarController:
- def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
- self.ESCC = EnhancedSmartCruiseControl(CP, CP_IQ)
-
- def update(self, car_state):
- self.ESCC.update_car_state(car_state)
-
-
-class EsccRadarInterfaceBase:
- def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
- self.ESCC = EnhancedSmartCruiseControl(CP, CP_IQ)
- self.use_escc = False
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/fingerprints_ext.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/fingerprints_ext.py
deleted file mode 100644
index 0323a15..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/fingerprints_ext.py
+++ /dev/null
@@ -1,126 +0,0 @@
-from iqdbc.car.structs import CarParams
-from iqdbc.car.hyundai.values import CAR
-
-Ecu = CarParams.Ecu
-
-
-FW_VERSIONS_EXT = {
- CAR.KIA_CEED_PHEV_2022_NON_SCC: {
- (Ecu.eps, 0x7D4, None): [
- b'\xf1\x00CD MDPS C 1.00 1.01 56310-XX000 4CPHC101',
- ],
- (Ecu.fwdCamera, 0x7C4, None): [
- 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',
- ],
- (Ecu.fwdRadar, 0x7d0, None): [
- b'\xf1\x00IK__ SCC --CUP 1.00 1.02 96400-G9100 ',
- ],
- (Ecu.fwdCamera, 0x7c4, None): [
- b'\xf1\x00IK MFC MT USA LHD 1.00 1.01 95740-G9000 170920',
- ],
- },
- 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',
- ],
- (Ecu.fwdCamera, 0x7c4, None): [
- b'\xf1\x00OS9 LKAS AT USA LHD 1.00 1.00 95740-J9200 g30',
- ],
- (Ecu.transmission, 0x7e1, None): [
- b'\xf1\x006T6J0_C2\x00\x006T6K1051\x00\x00TOS4N20NS2\x00\x00\x00\x00',
- ],
- },
- CAR.KIA_FORTE_2019_NON_SCC: {
- (Ecu.eps, 0x7D4, None): [
- b'\xf1\x00BD MDPS C 1.00 1.04 56310/M6000 4BDDC104',
- b'\xf1\x00BD MDPS C 1.00 1.05 56310/M6000 4BDDC105',
- ],
- (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): [
- b'\xf1\x00BD MDPS C 1.00 1.08 56310M6000\x00 4BDDC108',
- ],
- (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): [
- b'\xf1\x00SP ESC \t 101"\t\x01 58910-Q5510',
- b'\xf1\x00SP ESC \r 100"\x04\x01 58910-Q5510',
- ],
- (Ecu.eps, 0x7d4, None): [
- b'\xf1\x00SP2 MDPS C 1.00 1.04 56310Q5240 4SPSC104',
- b'\xf1\x00SP2 MDPS C 1.00 1.01 56300Q5920 ',
- ],
- (Ecu.fwdCamera, 0x7c4, None): [
- b'\xf1\x00SP2 MFC AT USA LHD 1.00 1.03 99210-Q5500 230208',
- b'\xf1\x00SP2 MFC AT AUS RHD 1.00 1.02 99210-Q5500 220624',
- ],
- (Ecu.transmission, 0x7e1, None): [
- b'\xf1\x006V2B0_C2\x00\x006V2D5051\x00\x00CSP2N20NL0\x00\x00\x00\x00',
- b'\xf1\x006V2B0_C2\x00\x006V2D4051\x00\x00CSP2N20KL1\x00\x00\x00\x00',
- ],
- },
- 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): [
- b'\xf1\x00CN7 MFC AT USA LHD 1.00 1.01 99210-AB000 210205',
- 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',
- ],
- },
- CAR.HYUNDAI_BAYON_1ST_GEN_NON_SCC: {
- # TODO: Check working route for more FW
- (Ecu.fwdCamera, 0x7c4, None): [
- b'\xf1\x00BC3 LKA AT EUR LHD 1.00 1.01 99211-Q0100 261'
- ],
- },
-}
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/lead_data_ext.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/lead_data_ext.py
deleted file mode 100644
index fa805b6..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/lead_data_ext.py
+++ /dev/null
@@ -1,114 +0,0 @@
-"""
-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
-
-
-class LeadData(ABC):
- def __init__(self, object_gap: int, lead_distance: float, lead_rel_speed: float, lead_visible: bool):
- self.object_gap = object_gap
- self.lead_distance = lead_distance
- self.lead_rel_speed = lead_rel_speed
- self.lead_visible = lead_visible
-
- @property
- @abstractmethod
- def object_rel_gap(self) -> int:
- raise NotImplementedError("Subclasses must implement this method")
-
-
-class CanLeadData(LeadData):
- @property
- def object_rel_gap(self) -> int:
- return 0 if self.lead_distance == 0 else 2 if self.lead_rel_speed < -0.2 else 1
-
-
-class CanFdLeadData(LeadData):
- @property
- def object_rel_gap(self) -> int:
- return 0 if not self.lead_visible else 2 if self.lead_rel_speed < 0 else 1
-
-
-def _hysteresis_update(current, new_value, counter, threshold):
- """
- Updates a value based on a hysteresis threshold mechanism. This function
- compares a new value against the current value and uses a counter to detect
- when a transition should occur, avoiding rapid oscillations between states.
- A new value will only be adopted if it differs from the current value and
- the counter reaches the specified threshold.
-
- :param current: The current value being tracked.
- :param new_value: The potential new value to compare against the current.
- :param counter: The count of consecutive different values encountered.
- :param threshold: The minimum count required before switching to the new value.
- :return: A tuple containing:
- - The updated current value, which is either the original current
- value or the new value if the hysteresis condition was met.
- - The updated counter, reset to 0 if the new value was adopted,
- or incremented by 1 otherwise.
- """
- if new_value == current:
- return current, 0
- counter += 1
- return (new_value, 0) if counter >= threshold else (current, counter)
-
-
-class LeadDataCarController:
- # Hysteresis parameters
- LEAD_HYSTERESIS_FRAMES: int = 50
-
- def __init__(self, CP: structs.CarParams):
- self.CP = CP
-
- self.lead_one = {}
- self.lead_two = {}
-
- self._lead_on_counter = 0
- self._lead_off_counter = 0
- self.lead_visible = False
- self.gap_counter = 0
- self.object_gap = 0
- self.lead_distance = 0
- self.lead_rel_speed = 0
-
- def _update_object_gap(self, lead_distance: float | None):
- new_gap = 5 # Default gap value if no lead distance is provided
- if lead_distance is None or lead_distance == 0:
- new_gap = 0
- elif lead_distance < 20:
- new_gap = 2
- elif lead_distance < 25:
- new_gap = 3
- elif lead_distance < 30:
- new_gap = 4
-
- self.object_gap, self.gap_counter = _hysteresis_update(self.object_gap, new_gap, self.gap_counter, self.LEAD_HYSTERESIS_FRAMES)
-
- def _update_lead_visible_hysteresis(self, raw_lead_visible: bool):
- counter = self._lead_on_counter if raw_lead_visible else self._lead_off_counter
- self.lead_visible, counter = _hysteresis_update(self.lead_visible, raw_lead_visible, counter, self.LEAD_HYSTERESIS_FRAMES)
-
- if raw_lead_visible:
- self._lead_on_counter = counter
- self._lead_off_counter = 0 # reset opposite counter
- else:
- self._lead_off_counter = counter
- self._lead_on_counter = 0 # reset opposite counter
-
- def update(self, CC_IQ: structs.IQCarControl) -> None:
- self.lead_one = CC_IQ.leadOne
- self.lead_two = CC_IQ.leadTwo
-
- self.lead_distance = self.lead_one.dRel
- self.lead_rel_speed = self.lead_one.vRel
- self._update_lead_visible_hysteresis(self.lead_one.status)
- self._update_object_gap(self.lead_distance)
-
- @property
- def lead_data(self) -> CanLeadData | CanFdLeadData:
- if self.CP.flags & HyundaiFlags.CANFD:
- return CanFdLeadData(self.object_gap, self.lead_distance, self.lead_rel_speed, self.lead_visible)
-
- return CanLeadData(self.object_gap, self.lead_distance, self.lead_rel_speed, self.lead_visible)
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/longitudinal/__init__.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/longitudinal/__init__.py
deleted file mode 100644
index 297dca9..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/longitudinal/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/longitudinal/config.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/longitudinal/config.py
deleted file mode 100644
index 499d485..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/longitudinal/config.py
+++ /dev/null
@@ -1,65 +0,0 @@
-"""
-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
-
-
-@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])
- longitudinal_actuator_delay: float = 0.45
- jerk_limits: float = 4.0
-
-
-# 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,
- ),
- "DEFAULT": CarTuningConfig(
- 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.3],
- )
-}
-
-# 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,
- ),
- CAR.HYUNDAI_IONIQ: CarTuningConfig(
- jerk_limits=4.5,
- )
-}
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/longitudinal/controller.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/longitudinal/controller.py
deleted file mode 100644
index 7998452..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/longitudinal/controller.py
+++ /dev/null
@@ -1,292 +0,0 @@
-"""
-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
-
-from iqdbc.car import structs, DT_CTRL
-from iqdbc.car.interfaces import CarStateBase
-from iqdbc.car.hyundai.values import CarControllerParams
-from iqdbc.lvbs.car.hyundai.longitudinal.helpers import get_car_config, jerk_limited_integrator, ramp_update
-from iqdbc.lvbs.car.hyundai.values import HyundaiFlagsIQ
-
-LongCtrlState = structs.CarControl.Actuators.LongControlState
-
-MIN_JERK = 0.5
-COMFORT_BAND_VAL = 0.01
-
-DYNAMIC_LOWER_JERK_BP = [-2.0, -1.5, -1.0, -0.25, -0.1, -0.025, -0.01, -0.005]
-DYNAMIC_LOWER_JERK_V = [3.3, 2.5, 2.0, 1.9, 1.8, 1.65, 1.15, 0.5]
-
-
-@dataclass
-class LongitudinalState:
- desired_accel: float = 0.0
- actual_accel: float = 0.0
- accel_last: float = 0.0
- jerk_upper: float = 0.0
- jerk_lower: float = 0.0
- comfort_band_upper: float = 0.0
- comfort_band_lower: float = 0.0
- stopping: bool = False
-
-
-class LongitudinalController:
- """Longitudinal controller which gets injected into CarControllerParams."""
-
- def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams) -> None:
- self.CP = CP
- self.CP_IQ = CP_IQ
-
- self.tuning = LongitudinalState()
- self.car_config = get_car_config(CP)
- self.long_control_state_last = LongCtrlState.off
- self.stopping_count = 0
-
- self.accel_cmd = 0.0
- self.desired_accel = 0.0
- self.actual_accel = 0.0
- self.accel_last = 0.0
- self.jerk_upper = 0.0
- self.jerk_lower = 0.0
- self.comfort_band_upper = 0.0
- self.comfort_band_lower = 0.0
- self.stopping = False
-
- @property
- def enabled(self) -> bool:
- return bool(self.CP_IQ.flags & (HyundaiFlagsIQ.LONG_TUNING_DYNAMIC | HyundaiFlagsIQ.LONG_TUNING_PREDICTIVE))
-
- def get_stopping_state(self, actuators: structs.CarControl.Actuators) -> None:
- stopping = actuators.longControlState == LongCtrlState.stopping
-
- # If custom tuning is not enabled, use upstream stopping logic
- if not self.enabled:
- self.stopping = stopping
- self.stopping_count = 0
- return
-
- # Reset stopping state when not in stopping mode
- if not stopping:
- self.stopping = False
- self.stopping_count = 0
- return
-
- # When transitioning from off state to stopping
- if self.long_control_state_last == LongCtrlState.off:
- self.stopping = True
- return
-
- # Keep track of time in stopping state (in control cycles)
- if self.stopping_count > 1 / (DT_CTRL * 2):
- self.stopping = True
-
- self.stopping_count += 1
-
- @staticmethod
- def _calculate_speed_based_jerk_limits(velocity: float, long_control_state: LongCtrlState) -> tuple[float, float]:
- """Calculate jerk limits based on vehicle speed according to ISO 15622:2018.
-
- Args:
- velocity: Current vehicle speed (m/s)
- long_control_state: Current longitudinal control state
-
- Returns:
- Tuple of (upper_limit, lower_limit) in m/s³
- """
-
- # Upper jerk limit varies based on speed and control state
- if long_control_state == LongCtrlState.pid:
- upper_limit = float(np.interp(velocity, [0.0, 5.0, 20.0], [2.0, 3.0, 1.6]))
- else:
- upper_limit = 0.5 # Default for non-PID states
-
- # Lower jerk limit varies based on speed
- lower_limit = float(np.interp(velocity, [0.0, 5.0, 20.0], [5.0, 4.0, 2.5]))
-
- return upper_limit, lower_limit
-
- def _calculate_lookahead_jerk(self, accel_error: float, velocity: float) -> tuple[float, float]:
- """Calculate lookahead jerk needed to reach target acceleration.
-
- Args:
- accel_error: Difference between target and current acceleration (m/s²)
- velocity: Current vehicle speed (m/s)
-
- Returns:
- Tuple of (upper_jerk, lower_jerk) in m/s³
- """
-
- # Time window to reach target acceleration, varies with speed
- future_t_upper = float(np.interp(velocity, self.car_config.lookahead_jerk_bp, self.car_config.lookahead_jerk_upper_v))
- future_t_lower = float(np.interp(velocity, self.car_config.lookahead_jerk_bp, self.car_config.lookahead_jerk_lower_v))
-
- # Required jerk to reach target acceleration in lookahead window
- j_ego_upper = accel_error / future_t_upper
- j_ego_lower = accel_error / future_t_lower
-
- return j_ego_upper, j_ego_lower
-
- def _calculate_dynamic_lower_jerk(self, accel_error: float, velocity: float) -> float:
- """Calculate dynamic jerk for braking based on acceleration error.
-
- Used for the dynamic tuning approach (non-predictive).
-
- Args:
- accel_error: Difference between actual and previous acceleration (m/s²)
- velocity: Current vehicle speed (m/s)
-
- Returns:
- Dynamic lower jerk limit (m/s³)
- """
-
- if self.CP.radarUnavailable:
- return 5.0
-
- if accel_error < 0:
- # Scale the brake jerk values based on car config
- lower_max = self.car_config.jerk_limits
- original_values = np.array(DYNAMIC_LOWER_JERK_V)
- scaled_values = original_values * (lower_max / original_values[0])
-
- # Interpolate based on acceleration error
- dynamic_lower_jerk = float(np.interp(accel_error, DYNAMIC_LOWER_JERK_BP, scaled_values))
- else:
- dynamic_lower_jerk = 0.5
-
- return dynamic_lower_jerk
-
- def calculate_jerk(self, CC: structs.CarControl, CS: CarStateBase, long_control_state: LongCtrlState) -> None:
- """Calculate appropriate jerk limits for smooth acceleration/deceleration.
-
- Args:
- CC: Car control signals
- CS: Car state
- long_control_state: Current longitudinal control state
- """
-
- # If custom tuning is disabled, use upstream fixed values
- if not self.enabled:
- jerk_limit = 3.0 if long_control_state == LongCtrlState.pid else 1.0
- self.jerk_upper = jerk_limit
- self.jerk_lower = 5.0
- return
-
- velocity = CS.out.vEgo
- accel_error = self.accel_cmd - self.accel_last
-
- # Calculate jerk limits based on speed
- upper_speed_factor, lower_speed_factor = self._calculate_speed_based_jerk_limits(velocity, long_control_state)
-
- # Calculate lookahead jerk
- j_ego_upper, j_ego_lower = self._calculate_lookahead_jerk(accel_error, velocity)
-
- # Calculate lower jerk limit
- lower_jerk = max(-j_ego_lower, MIN_JERK)
- if self.CP.radarUnavailable:
- lower_jerk = 5.0
-
- # Final jerk limits with thresholds
- desired_jerk_upper = min(max(j_ego_upper, MIN_JERK), upper_speed_factor)
- desired_jerk_lower = min(lower_jerk, lower_speed_factor)
-
- # Calculate dynamic lower jerk for non-predictive tuning
- a_ego_blended = float(np.interp(velocity, [1.0, 2.0], [CS.aBasis, CS.out.aEgo]))
- dynamic_accel_error = a_ego_blended - self.accel_last
- dynamic_lower_jerk = self._calculate_dynamic_lower_jerk(dynamic_accel_error, velocity)
- dynamic_desired_lower_jerk = min(dynamic_lower_jerk, lower_speed_factor)
-
- # Apply jerk limits based on tuning approach
- self.jerk_upper = ramp_update(self.jerk_upper, desired_jerk_upper)
-
- # Predictive tuning uses calculated desired jerk directly
- # Dynamic tuning applies a ramped approach for smoother transitions
- if self.CP_IQ.flags & HyundaiFlagsIQ.LONG_TUNING_PREDICTIVE:
- self.jerk_lower = desired_jerk_lower
- else:
- self.jerk_lower = ramp_update(self.jerk_lower, dynamic_desired_lower_jerk)
-
- # Disable jerk when longitudinal control is inactive
- if not CC.longActive:
- self.jerk_upper = 0.0
- self.jerk_lower = 0.0
-
- def calculate_accel(self, CC: structs.CarControl) -> None:
- """Calculate commanded acceleration using jerk-limited approach.
-
- Args:
- CC: Car control signals
- """
-
- # Skip custom processing if tuning is disabled or radar unavailable
- if not self.enabled or self.CP.radarUnavailable:
- self.desired_accel = self.accel_cmd
- self.actual_accel = self.accel_cmd
- return
-
- # Reset acceleration when control is inactive
- if not CC.longActive:
- self.desired_accel = 0.0
- self.actual_accel = 0.0
- self.accel_last = 0.0
- return
-
- # Force zero acceleration during stopping
- if self.stopping:
- self.desired_accel = 0.0
- else:
- self.desired_accel = float(np.clip(self.accel_cmd, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX))
-
- # Apply jerk-limited integration to get smooth acceleration
- self.actual_accel = jerk_limited_integrator(self.desired_accel, self.accel_last, self.jerk_upper, self.jerk_lower)
-
- self.accel_last = self.actual_accel
-
- def calculate_comfort_band(self, CC: structs.CarControl) -> None:
- if not self.enabled or self.CP.radarUnavailable or not CC.longActive:
- self.comfort_band_upper = 0.0
- self.comfort_band_lower = 0.0
- return
-
- self.comfort_band_upper = COMFORT_BAND_VAL
- self.comfort_band_lower = COMFORT_BAND_VAL
-
- def get_tuning_state(self) -> None:
- """Update the tuning state object with current control values.
-
- External components depend on this state for longitudinal control.
- """
-
- self.tuning = LongitudinalState(
- desired_accel=self.desired_accel,
- actual_accel=self.actual_accel,
- accel_last=self.accel_last,
- jerk_upper=self.jerk_upper,
- jerk_lower=self.jerk_lower,
- comfort_band_upper=self.comfort_band_upper,
- comfort_band_lower=self.comfort_band_lower,
- stopping=self.stopping,
- )
-
- def update(self, CC: structs.CarControl, CS: CarStateBase) -> None:
- """Update longitudinal control calculations.
-
- This is the main entry point called externally.
-
- Args:
- CC: Car control signals including actuators
- CS: Car state information
- """
-
- actuators = CC.actuators
- long_control_state = actuators.longControlState
- self.accel_cmd = CC.actuators.accel
-
- self.get_stopping_state(actuators)
- self.calculate_jerk(CC, CS, long_control_state)
- self.calculate_accel(CC)
- self.calculate_comfort_band(CC)
- self.get_tuning_state()
-
- self.long_control_state_last = long_control_state
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/longitudinal/helpers.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/longitudinal/helpers.py
deleted file mode 100644
index 5703bd1..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/longitudinal/helpers.py
+++ /dev/null
@@ -1,60 +0,0 @@
-"""
-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
-from iqdbc.car.hyundai.values import HyundaiFlags
-from iqdbc.lvbs.car.hyundai.longitudinal.config import CarTuningConfig, TUNING_CONFIGS, CAR_SPECIFIC_CONFIGS
-
-JERK_THRESHOLD = 0.1
-JERK_STEP = 0.1
-
-
-class LongitudinalTuningType:
- OFF = 0
- DYNAMIC = 1
- PREDICTIVE = 2
-
-
-def get_car_config(CP: structs.CarParams) -> CarTuningConfig:
- # Get car type flags from specific configs or determine from car flags
- car_config = CAR_SPECIFIC_CONFIGS.get(CP.carFingerprint)
- # If car is not in specific configs, determine from flags
- if car_config is None:
- if CP.flags & HyundaiFlags.CANFD:
- car_config = TUNING_CONFIGS["CANFD"]
- elif CP.flags & HyundaiFlags.EV:
- car_config = TUNING_CONFIGS["EV"]
- elif CP.flags & HyundaiFlags.HYBRID:
- car_config = TUNING_CONFIGS["HYBRID"]
- else:
- car_config = TUNING_CONFIGS["DEFAULT"]
-
- return car_config
-
-
-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
-
-
-def jerk_limited_integrator(desired_accel, last_accel, jerk_upper, jerk_lower) -> float:
- if desired_accel >= last_accel:
- val = jerk_upper * DT_CTRL * 2
- else:
- val = jerk_lower * DT_CTRL * 2
-
- return rate_limit(desired_accel, last_accel, -val, val)
-
-
-def ramp_update(current, target):
- error = target - current
- if abs(error) > JERK_THRESHOLD:
- return current + float(np.clip(error, -JERK_STEP, JERK_STEP))
- return target
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/radar_interface_ext.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/radar_interface_ext.py
deleted file mode 100644
index 8528a98..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/radar_interface_ext.py
+++ /dev/null
@@ -1,85 +0,0 @@
-from iqdbc.can.parser import CANParser
-from iqdbc.car import structs, Bus
-from iqdbc.car.hyundai.hyundaicanfd import CanBus
-from iqdbc.car.hyundai.values import DBC, HyundaiFlags
-
-from iqdbc.lvbs.car.hyundai.escc import EsccRadarInterfaceBase
-
-
-class RadarInterfaceExt(EsccRadarInterfaceBase):
- msg_src: str
- trigger_msg: int
- rcp: CANParser
- pts: dict[int, structs.RadarData.RadarPoint]
-
- def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
- EsccRadarInterfaceBase.__init__(self, CP, CP_IQ)
- self.CP = CP
- self.CP_IQ = CP_IQ
-
- self.track_id = 0
-
- @property
- def use_radar_interface_ext(self) -> bool:
- return self.use_escc or self.CP.flags & (HyundaiFlags.CAMERA_SCC | HyundaiFlags.CANFD_CAMERA_SCC)
-
- def get_msg_src(self) -> str | None:
- if self.use_escc:
- return "ESCC"
- if self.CP.flags & (HyundaiFlags.CAMERA_SCC | HyundaiFlags.CANFD_CAMERA_SCC):
- return "SCC_CONTROL" if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else "SCC11"
-
- def get_radar_ext_can_parser(self) -> CANParser:
- if self.ESCC.enabled:
- lead_src, bus = "ESCC", 0
- elif self.CP.flags & (HyundaiFlags.CAMERA_SCC | HyundaiFlags.CANFD_CAMERA_SCC):
- lead_src = "SCC_CONTROL" if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else "SCC11"
- bus = CanBus(self.CP).CAM if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else 2
- else:
- return None
-
- messages = [(lead_src, 50)]
- return CANParser(DBC[self.CP.carFingerprint][Bus.pt], messages, bus)
-
- def get_trigger_msg(self, default_trigger_msg) -> int:
- if self.ESCC.enabled:
- return self.ESCC.trigger_msg
- if self.CP.flags & (HyundaiFlags.CAMERA_SCC | HyundaiFlags.CANFD_CAMERA_SCC):
- return 0x1A0 if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else 0x420
- return default_trigger_msg
-
- def initialize_radar_ext(self, default_trigger_msg) -> None:
- if self.ESCC.enabled:
- self.use_escc = True
-
- self.rcp = self.get_radar_ext_can_parser()
- self.trigger_msg = self.get_trigger_msg(default_trigger_msg)
-
- def update_ext(self, ret: structs.RadarData) -> structs.RadarData:
- if not self.rcp.can_valid:
- ret.errors.canError = True
- return ret
-
- for ii in range(1):
- msg_src = self.get_msg_src()
- msg = self.rcp.vl[msg_src]
-
- if ii not in self.pts:
- self.pts[ii] = structs.RadarData.RadarPoint()
- self.pts[ii].trackId = self.track_id
- self.track_id += 1
-
- valid = msg['ACC_ObjDist'] < 204.6 if self.CP.flags & HyundaiFlags.CANFD_CAMERA_SCC else msg['ACC_ObjStatus']
- 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].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].yvRel = float('nan')
-
- else:
- del self.pts[ii]
-
- ret.points = list(self.pts.values())
- return ret
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/tests/__init__.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/tests/__init__.py
deleted file mode 100644
index 297dca9..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/tests/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/tests/test_escc_base.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/tests/test_escc_base.py
deleted file mode 100644
index 178563b..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/tests/test_escc_base.py
+++ /dev/null
@@ -1,61 +0,0 @@
-import pytest
-from hypothesis import given, strategies as st, settings, HealthCheck
-from iqdbc.lvbs.car.hyundai.escc import EnhancedSmartCruiseControl, ESCC_MSG
-from iqdbc.car.hyundai.carstate import CarState
-from iqdbc.car import structs
-from iqdbc.lvbs.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
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/tests/test_lead_data_car_controller.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/tests/test_lead_data_car_controller.py
deleted file mode 100644
index 73a1f74..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/tests/test_lead_data_car_controller.py
+++ /dev/null
@@ -1,77 +0,0 @@
-from enum import IntFlag
-
-from iqdbc.lvbs.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
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/tests/test_radar_interface_ext.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/tests/test_radar_interface_ext.py
deleted file mode 100644
index 98ff9ee..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/tests/test_radar_interface_ext.py
+++ /dev/null
@@ -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.lvbs.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
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/tests/test_tuning_controller.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/tests/test_tuning_controller.py
deleted file mode 100644
index ad5a60f..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/tests/test_tuning_controller.py
+++ /dev/null
@@ -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.lvbs.car.hyundai.longitudinal.controller import LongitudinalController, LongitudinalState
-from iqdbc.lvbs.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()
diff --git a/iqdbc_repo/iqdbc/lvbs/car/hyundai/values.py b/iqdbc_repo/iqdbc/lvbs/car/hyundai/values.py
deleted file mode 100644
index 26f78e5..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/hyundai/values.py
+++ /dev/null
@@ -1,32 +0,0 @@
-"""
-Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
-
-from enum import IntFlag
-
-
-class HyundaiSafetyFlagsIQ:
- DEFAULT = 0
- ESCC = 1
- LONG_MAIN_CRUISE_TOGGLEABLE = 2
- HAS_LDA_BUTTON = 4
- NON_SCC = 8
-
-
-class HyundaiFlagsIQ(IntFlag):
- """
- Flags for Hyundai specific quirks within iqpilot.
- """
- ENHANCED_SCC = 1
- HAS_LFA_BUTTON = 2 # Deprecated in favor of HyundaiFlags.HAS_LDA_BUTTON
- LONGITUDINAL_MAIN_CRUISE_TOGGLEABLE = 2 ** 2
- ENABLE_RADAR_TRACKS_DEPRECATED = 2 ** 3
- LONG_TUNING_DYNAMIC = 2 ** 4
- LONG_TUNING_PREDICTIVE = 2 ** 5
- NON_SCC = 2 ** 6
- NON_SCC_RADAR_FCA = 2 ** 7 # most with FCA come from the camera
- NON_SCC_NO_FCA = 2 ** 8 # not all have FCA
- SPEED_LIMIT_AVAILABLE = 2 ** 9 # platforms with speed limit data available
- HAS_LKAS12 = 2 ** 10
-
-
diff --git a/iqdbc_repo/iqdbc/lvbs/car/interfaces.py b/iqdbc_repo/iqdbc/lvbs/car/interfaces.py
index 893d72e..59905ed 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/interfaces.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/interfaces.py
@@ -8,12 +8,8 @@ from collections.abc import Callable
from iqdbc.car import structs
from iqdbc.car.can_definitions import CanRecvCallable, CanSendCallable
-from iqdbc.car.hyundai.values import HyundaiFlags
from iqdbc.car.subaru.values import SubaruFlags
-from iqdbc.lvbs.car.hyundai.enable_radar_tracks import enable_radar_tracks as hyundai_enable_radar_tracks
-from iqdbc.lvbs.car.hyundai.longitudinal.helpers import LongitudinalTuningType
-from iqdbc.lvbs.car.hyundai.values import HyundaiFlagsIQ
-from iqdbc.lvbs.car.subaru.values_ext import SubaruFlagsIQ, SubaruSafetyFlagsIQ
+from iqdbc.lvbs.car.subaru.iq_values import SubaruFlagsIQ, SubaruSafetyFlagsIQ
from iqdbc.lvbs.car.tesla.values import TeslaFlagsIQ
from iqdbc.lvbs.car.toyota.values import ToyotaFlagsIQ
@@ -81,7 +77,6 @@ def apply_iq_car_config(CI, CP: structs.CarParams, CP_IQ: structs.IQCarParams,
_apply_long_tuning(CI, CP, CP_IQ, params_dict)
_apply_torque_blend(CP, CP_IQ, params_dict)
- _initialize_radar_tracks(CP, CP_IQ, can_recv, can_send)
_apply_creep_assist(CP, CP_IQ, params_dict)
_apply_toyota_options(CP, CP_IQ, params_dict)
@@ -89,14 +84,6 @@ def apply_iq_car_config(CI, CP: structs.CarParams, CP_IQ: structs.IQCarParams,
def _apply_long_tuning(CI, CP: structs.CarParams, CP_IQ: structs.IQCarParams,
params_dict: dict[str, str]) -> None:
- # Hyundai Custom Longitudinal Tuning
- if CP.brand == 'hyundai':
- hyundai_longitudinal_tuning = int(params_dict.get("HyundaiLongitudinalTuning", 0))
- if hyundai_longitudinal_tuning == LongitudinalTuningType.DYNAMIC:
- CP_IQ.flags |= HyundaiFlagsIQ.LONG_TUNING_DYNAMIC.value
- if hyundai_longitudinal_tuning == LongitudinalTuningType.PREDICTIVE:
- CP_IQ.flags |= HyundaiFlagsIQ.LONG_TUNING_PREDICTIVE.value
-
_ = CI.get_longitudinal_tuning_iq(CP, CP_IQ)
@@ -108,25 +95,18 @@ def _apply_torque_blend(CP: structs.CarParams, CP_IQ: structs.IQCarParams,
CP_IQ.flags |= TeslaFlagsIQ.COOP_STEERING.value
-def _initialize_radar_tracks(CP: structs.CarParams, CP_IQ: structs.IQCarParams,
- can_recv: CanRecvCallable | None = None, can_send: CanSendCallable | None = None) -> None:
- if CP.brand == 'hyundai':
- if CP.flags & HyundaiFlags.MANDO_RADAR and (CP.radarUnavailable or CP_IQ.flags & HyundaiFlagsIQ.ENHANCED_SCC):
- tracks_enabled = hyundai_enable_radar_tracks(can_recv, can_send, bus=0, addr=0x7d0)
- CP.radarUnavailable = not tracks_enabled
-
-
def _apply_creep_assist(CP: structs.CarParams, CP_IQ: structs.IQCarParams, params_dict: dict[str, str]) -> None:
- if CP.brand == 'subaru' and not CP.flags & (SubaruFlags.GLOBAL_GEN2 | SubaruFlags.HYBRID):
- stop_and_go = int(params_dict.get("IQSubaruCreepAssist", 0)) == 1
- stop_and_go_manual_parking_brake = int(params_dict.get("IQSubaruCreepAssistManualBrake", 0)) == 1
+ # Subaru stop-and-go; unsupported on gen2-global and hybrid platforms.
+ if CP.brand != 'subaru' or CP.flags & (SubaruFlags.GLOBAL_GEN2 | SubaruFlags.HYBRID):
+ return
- if stop_and_go:
- CP_IQ.flags |= SubaruFlagsIQ.STOP_AND_GO.value
- if stop_and_go_manual_parking_brake:
- CP_IQ.flags |= SubaruFlagsIQ.STOP_AND_GO_MANUAL_PARKING_BRAKE.value
- if stop_and_go or stop_and_go_manual_parking_brake:
- CP_IQ.safetyParam |= SubaruSafetyFlagsIQ.STOP_AND_GO
+ if int(params_dict.get("IQSubaruCreepAssist", 0)) == 1:
+ CP_IQ.flags |= SubaruFlagsIQ.STOP_AND_GO.value
+ if int(params_dict.get("IQSubaruCreepAssistManualBrake", 0)) == 1:
+ CP_IQ.flags |= SubaruFlagsIQ.STOP_AND_GO_MANUAL_PARKING_BRAKE.value
+
+ if CP_IQ.flags & (SubaruFlagsIQ.STOP_AND_GO | SubaruFlagsIQ.STOP_AND_GO_MANUAL_PARKING_BRAKE):
+ CP_IQ.iqSafetyFlags |= SubaruSafetyFlagsIQ.STOP_AND_GO
def _apply_toyota_options(CP: structs.CarParams, CP_IQ: structs.IQCarParams, params_dict: dict[str, str]) -> None:
diff --git a/iqdbc_repo/iqdbc/lvbs/car/fingerprints_ext.py b/iqdbc_repo/iqdbc/lvbs/car/iq_fingerprints.py
similarity index 100%
rename from iqdbc_repo/iqdbc/lvbs/car/fingerprints_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/iq_fingerprints.py
diff --git a/iqdbc_repo/iqdbc/lvbs/car/mazda/__init__.py b/iqdbc_repo/iqdbc/lvbs/car/mazda/__init__.py
deleted file mode 100644
index 297dca9..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/mazda/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-"""
-Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
diff --git a/iqdbc_repo/iqdbc/lvbs/car/nissan/__init__.py b/iqdbc_repo/iqdbc/lvbs/car/nissan/__init__.py
index 297dca9..e69de29 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/nissan/__init__.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/nissan/__init__.py
@@ -1,3 +0,0 @@
-"""
-Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
diff --git a/iqdbc_repo/iqdbc/lvbs/car/nissan/carstate_ext.py b/iqdbc_repo/iqdbc/lvbs/car/nissan/iq_carstate.py
similarity index 57%
rename from iqdbc_repo/iqdbc/lvbs/car/nissan/carstate_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/nissan/iq_carstate.py
index e896d30..76e8891 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/nissan/carstate_ext.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/nissan/iq_carstate.py
@@ -1,7 +1,8 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
+Nissan cruise-button reader: emits edge ButtonEvents for the RES/SET buttons.
+"""
from enum import StrEnum
from iqdbc.car import Bus, structs
@@ -9,24 +10,22 @@ from iqdbc.can.parser import CANParser
from iqdbc.lvbs.car.nissan.values import BUTTONS
-class CarStateExt:
+class IQCarState:
def __init__(self, CP, CP_IQ):
self.CP = CP
self.CP_IQ = CP_IQ
-
- self.button_events = []
+ self.button_events: list = []
self.button_states = {button.event_type: False for button in BUTTONS}
- def update(self, ret: structs.CarState, ret_iq: structs.IQCarState, can_parsers: dict[StrEnum, CANParser]):
+ def update(self, ret: structs.CarState, ret_iq: structs.IQCarState, can_parsers: dict[StrEnum, CANParser]) -> None:
cp = can_parsers[Bus.pt]
-
- button_events = []
+ events = []
for button in BUTTONS:
- state = (cp.vl[button.can_addr][button.can_msg] in button.values)
- if self.button_states[button.event_type] != state:
+ pressed = cp.vl[button.can_addr][button.can_msg] in button.values
+ if pressed != self.button_states[button.event_type]:
event = structs.CarState.ButtonEvent.new_message()
event.type = button.event_type
- event.pressed = state
- button_events.append(event)
- self.button_states[button.event_type] = state
- self.button_events = button_events
+ event.pressed = pressed
+ events.append(event)
+ self.button_states[button.event_type] = pressed
+ self.button_events = events
diff --git a/iqdbc_repo/iqdbc/lvbs/car/nissan/values.py b/iqdbc_repo/iqdbc/lvbs/car/nissan/values.py
index 2c2e333..d1cbe20 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/nissan/values.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/nissan/values.py
@@ -1,8 +1,10 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
+IQ.Pilot Nissan extension: safety flag + cruise-button table.
+"""
from collections import namedtuple
+
from iqdbc.car import structs
@@ -11,12 +13,9 @@ class NissanSafetyFlagsIQ:
LEAF = 1
-
-
ButtonType = structs.CarState.ButtonEvent.Type
Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values'])
-
BUTTONS = [
Button(ButtonType.accelCruise, "CRUISE_THROTTLE", "RES_BUTTON", [1]),
Button(ButtonType.decelCruise, "CRUISE_THROTTLE", "SET_BUTTON", [1]),
diff --git a/iqdbc_repo/iqdbc/lvbs/car/rivian/__init__.py b/iqdbc_repo/iqdbc/lvbs/car/rivian/__init__.py
index 297dca9..e69de29 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/rivian/__init__.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/rivian/__init__.py
@@ -1,3 +0,0 @@
-"""
-Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
diff --git a/iqdbc_repo/iqdbc/lvbs/car/rivian/aol.py b/iqdbc_repo/iqdbc/lvbs/car/rivian/aol.py
index f28c0c2..3c92c9a 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/rivian/aol.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/rivian/aol.py
@@ -1,33 +1,30 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
+
+Always-on-Lateral output adapter for Rivian: derives the per-frame lateral-active
+and lane-keep icon state the LKAS command needs from the shared AOL state.
"""
from collections import namedtuple
from iqdbc.car import structs
from iqdbc.car.interfaces import CarStateBase
-MAX_STEERING_ANGLE = 90.0
+# Rivian EPAS rejects large-angle torque, so lateral is dropped past this bound.
+_MAX_STEERING_ANGLE = 90.0
-AolDataIQ = namedtuple("AolDataIQ",
- ["lka_icon_states", "lat_active"])
+AolDataIQ = namedtuple("AolDataIQ", ["lka_icon_states", "lat_active"])
class AolCarController:
def __init__(self):
self.aol = AolDataIQ(False, False)
- self.lka_icon_states = False
- self.lat_active = False
-
- def aol_status_update(self, CC: structs.CarControl, CC_IQ: structs.IQCarControl, CS: CarStateBase) -> AolDataIQ:
- if CC_IQ.aol.available:
- self.lka_icon_states = self.lat_active
- self.lat_active = CC.latActive and abs(CS.out.steeringAngleDeg) < MAX_STEERING_ANGLE
- else:
- self.lka_icon_states = CC.enabled
- self.lat_active = CC.latActive
-
- return AolDataIQ(self.lka_icon_states, self.lat_active)
-
def update(self, CC: structs.CarControl, CC_IQ: structs.IQCarControl, CS: CarStateBase) -> None:
- self.aol = self.aol_status_update(CC, CC_IQ, CS)
+ prev_active = self.aol.lat_active
+ if CC_IQ.aol.available:
+ lat_active = CC.latActive and abs(CS.out.steeringAngleDeg) < _MAX_STEERING_ANGLE
+ lka_icon = prev_active
+ else:
+ lat_active = CC.latActive
+ lka_icon = CC.enabled
+ self.aol = AolDataIQ(lka_icon, lat_active)
diff --git a/iqdbc_repo/iqdbc/lvbs/car/rivian/carstate_ext.py b/iqdbc_repo/iqdbc/lvbs/car/rivian/iq_carstate.py
similarity index 53%
rename from iqdbc_repo/iqdbc/lvbs/car/rivian/carstate_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/rivian/iq_carstate.py
index 13ce8ca..d7098e2 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/rivian/carstate_ext.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/rivian/iq_carstate.py
@@ -1,5 +1,9 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
+
+Rivian longitudinal-harness-upgrade carState reader: with the upgrade harness the
+right steering-wheel controls and the drive stalk drive the openpilot set speed,
+and the harness exposes blind-spot indicators. Only active behind the upgrade flag.
"""
import math
from enum import StrEnum
@@ -12,11 +16,13 @@ from iqdbc.lvbs.car.rivian.values import RivianFlagsIQ
ButtonType = structs.CarState.ButtonEvent.Type
-MAX_SET_SPEED = 85 * CV.MPH_TO_MS
-MIN_SET_SPEED = 20 * CV.MPH_TO_MS
+_SET_SPEED_MAX = 85 * CV.MPH_TO_MS
+_SET_SPEED_MIN = 20 * CV.MPH_TO_MS
+_LONG_PRESS_FRAMES = 66
+_STALK_HOLD_FRAMES = 50
-class CarStateExt:
+class IQCarState:
def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
self.CP = CP
self.CP_IQ = CP_IQ
@@ -29,57 +35,57 @@ class CarStateExt:
self.decrease_counter = 0
self.stalk_down_counter = 0
+ def _apply_set_speed_buttons(self, ret: structs.CarState, cp_park, cp_adas) -> None:
+ was_increasing = self.increase_button
+ was_decreasing = self.decrease_button
+
+ self.increase_button = cp_park.vl["WheelButtons"]["RightButton_RightClick"] == 2
+ self.decrease_button = cp_park.vl["WheelButtons"]["RightButton_LeftClick"] == 2
+ self.increase_counter = self.increase_counter + 1 if self.increase_button else 0
+ self.decrease_counter = self.decrease_counter + 1 if self.decrease_button else 0
+
+ metric = cp_adas.vl["Cluster"]["Cluster_Unit"] == 0
+ conversion = CV.KPH_TO_MS if metric else CV.MPH_TO_MS
+ step = 10.0 if metric else 5.0
+ shown = self.set_speed * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH)
+
+ # A held button steps to the next round multiple; a tap nudges by one unit.
+ if self.increase_button:
+ if self.increase_counter % _LONG_PRESS_FRAMES == 0:
+ self.set_speed = math.ceil((shown + 1) / step) * step * conversion
+ elif not was_increasing:
+ self.set_speed += conversion
+ if self.decrease_button:
+ if self.decrease_counter % _LONG_PRESS_FRAMES == 0:
+ self.set_speed = math.floor((shown - 1) / step) * step * conversion
+ elif not was_decreasing:
+ self.set_speed -= conversion
+
def update_longitudinal_upgrade(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
cp_park = can_parsers[Bus.alt]
cp_adas = can_parsers[Bus.adas]
cp = can_parsers[Bus.pt]
- prev_increase_button = self.increase_button
- prev_decrease_button = self.decrease_button
-
if self.CP.openpilotLongitudinalControl:
- # distance scroll wheel
right_scroll = cp_park.vl["WheelButtons"]["RightButton_Scroll"]
if right_scroll != 255:
if self.distance_button != right_scroll:
ret.buttonEvents = [structs.CarState.ButtonEvent(pressed=False, type=ButtonType.gapAdjustCruise)]
self.distance_button = right_scroll
- # button logic for set-speed
- self.increase_button = cp_park.vl["WheelButtons"]["RightButton_RightClick"] == 2
- self.decrease_button = cp_park.vl["WheelButtons"]["RightButton_LeftClick"] == 2
-
- self.increase_counter = self.increase_counter + 1 if self.increase_button else 0
- self.decrease_counter = self.decrease_counter + 1 if self.decrease_button else 0
-
- metric = cp_adas.vl["Cluster"]["Cluster_Unit"] == 0
- conversion = CV.KPH_TO_MS if metric else CV.MPH_TO_MS
- long_press_step = 10.0 if metric else 5.0
- set_speed_converted = self.set_speed * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH)
-
- if self.increase_button:
- if self.increase_counter % 66 == 0:
- self.set_speed = (int(math.ceil((set_speed_converted + 1) / long_press_step)) * long_press_step) * conversion
- elif not prev_increase_button:
- self.set_speed += conversion
-
- if self.decrease_button:
- if self.decrease_counter % 66 == 0:
- self.set_speed = (int(math.floor((set_speed_converted - 1) / long_press_step)) * long_press_step) * conversion
- elif not prev_decrease_button:
- self.set_speed -= conversion
+ self._apply_set_speed_buttons(ret, cp_park, cp_adas)
if not ret.cruiseState.enabled:
self.set_speed = ret.vEgoCluster
- # VDM_UserAdasRequest: 0=IDLE, 1=UP_1, 2=UP_2, 3=DOWN_1, 4=DOWN_2
+ # Drive stalk held down (VDM_UserAdasRequest 3/4) for ~0.5s snaps set speed
+ # up to the current speed, matching stock Rivian ACC (it never lowers it).
stalk_down = int(cp.vl["VDM_AdasSts"]["VDM_UserAdasRequest"]) in (3, 4)
self.stalk_down_counter = self.stalk_down_counter + 1 if stalk_down else 0
- if self.stalk_down_counter == 50:
- # Mimic Rivian ACC: holding stalk 0.5s sets speed to current speed (never decreases)
+ if self.stalk_down_counter == _STALK_HOLD_FRAMES:
self.set_speed = max(self.set_speed, ret.vEgoCluster)
- self.set_speed = max(MIN_SET_SPEED, min(self.set_speed, MAX_SET_SPEED))
+ self.set_speed = max(_SET_SPEED_MIN, min(self.set_speed, _SET_SPEED_MAX))
ret.cruiseState.speed = self.set_speed
if self.CP.enableBsm:
@@ -92,9 +98,7 @@ class CarStateExt:
@staticmethod
def get_parser(CP, CP_IQ) -> dict[StrEnum, CANParser]:
- messages = {}
-
+ messages: dict[StrEnum, CANParser] = {}
if CP_IQ.flags & RivianFlagsIQ.LONGITUDINAL_HARNESS_UPGRADE:
messages[Bus.alt] = CANParser(DBC[CP.carFingerprint][Bus.alt], [], 5)
-
return messages
diff --git a/iqdbc_repo/iqdbc/lvbs/car/rivian/values.py b/iqdbc_repo/iqdbc/lvbs/car/rivian/values.py
index c165a17..0cbd701 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/rivian/values.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/rivian/values.py
@@ -1,10 +1,10 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
+
+IQ.Pilot Rivian extension flags.
"""
from enum import IntFlag
class RivianFlagsIQ(IntFlag):
LONGITUDINAL_HARNESS_UPGRADE = 1
-
-
diff --git a/iqdbc_repo/iqdbc/lvbs/car/subaru/__init__.py b/iqdbc_repo/iqdbc/lvbs/car/subaru/__init__.py
index 297dca9..e69de29 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/subaru/__init__.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/subaru/__init__.py
@@ -1,3 +0,0 @@
-"""
-Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
diff --git a/iqdbc_repo/iqdbc/lvbs/car/subaru/aol.py b/iqdbc_repo/iqdbc/lvbs/car/subaru/aol.py
index 86c51e2..6846faf 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/subaru/aol.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/subaru/aol.py
@@ -1,45 +1,36 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
+
+Always-on-Lateral input adapter for Subaru: turns the dashboard LKAS button into
+a carState lkas ButtonEvent so the shared AOL state machine can toggle lateral.
"""
-
from enum import StrEnum
-from iqdbc.car import Bus, structs
+from iqdbc.car import Bus, structs
from iqdbc.car.subaru.values import SubaruFlags
from iqdbc.lvbs.aol_base import AolCarStateBase
from iqdbc.can.parser import CANParser
-ButtonType = structs.CarState.ButtonEvent.Type
+_LKAS = structs.CarState.ButtonEvent.Type.lkas
+
+# ES_LKAS_State/LKAS_Dash_State: 0 = neutral, 1 = LKAS shown on, 2 = LKAS shown off
+_DASH_ON = 1
+_DASH_OFF = 2
class AolCarState(AolCarStateBase):
- def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
- super().__init__(CP, CP_IQ)
-
- @staticmethod
- def create_lkas_button_events(cur_btn: int, prev_btn: int,
- buttons_dict: dict[int, structs.CarState.ButtonEvent.Type]) -> list[structs.CarState.ButtonEvent]:
- events: list[structs.CarState.ButtonEvent] = []
-
- if cur_btn == prev_btn:
- return events
-
- state_changes = [
- {"pressed": prev_btn != cur_btn and cur_btn != 2 and not (prev_btn == 2 and cur_btn == 1)},
- {"pressed": prev_btn != cur_btn and cur_btn == 2 and cur_btn != 1},
- ]
-
- for change in state_changes:
- if change["pressed"]:
- events.append(structs.CarState.ButtonEvent(pressed=change["pressed"],
- type=buttons_dict.get(cur_btn, ButtonType.unknown)))
- return events
-
def update_aol(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
- cp_cam = can_parsers[Bus.cam]
+ if self.CP.flags & SubaruFlags.PREGLOBAL:
+ return
self.prev_lkas_button = self.lkas_button
- if not self.CP.flags & SubaruFlags.PREGLOBAL:
- self.lkas_button = cp_cam.vl["ES_LKAS_State"]["LKAS_Dash_State"]
+ self.lkas_button = can_parsers[Bus.cam].vl["ES_LKAS_State"]["LKAS_Dash_State"]
- ret.buttonEvents = self.create_lkas_button_events(self.lkas_button, self.prev_lkas_button, {1: ButtonType.lkas})
+ if self._is_toggle_edge():
+ ret.buttonEvents = [*ret.buttonEvents, structs.CarState.ButtonEvent(type=_LKAS, pressed=True)]
+
+ def _is_toggle_edge(self) -> bool:
+ # every dash-state change is a deliberate press except the off->on rebound (2 -> 1)
+ if self.lkas_button == self.prev_lkas_button:
+ return False
+ return not (self.prev_lkas_button == _DASH_OFF and self.lkas_button == _DASH_ON)
diff --git a/iqdbc_repo/iqdbc/lvbs/car/subaru/creep_assist.py b/iqdbc_repo/iqdbc/lvbs/car/subaru/creep_assist.py
index 8b7b735..29417e1 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/subaru/creep_assist.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/subaru/creep_assist.py
@@ -1,7 +1,11 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
-"""
+IQ.Pilot Subaru stop-and-go: nudges the ACC out of a standstill it would
+otherwise hold. Two variants gated by user flags — an electronic-parking-brake
+resume pulse (distance/lead triggered) and a manual-parking-brake hold-timer
+resume. Both work by spoofing the camera-bus throttle/brake frames.
+"""
import copy
from enum import StrEnum
@@ -10,97 +14,68 @@ from iqdbc.car.can_definitions import CanData
from iqdbc.car.interfaces import CarStateBase
from iqdbc.car.subaru.values import SubaruFlags
-from iqdbc.lvbs.car.subaru import subarucan_ext
-from iqdbc.lvbs.car.subaru.values_ext import SubaruFlagsIQ
+from iqdbc.lvbs.car.subaru import iq_subarucan
+from iqdbc.lvbs.car.subaru.iq_values import SubaruFlagsIQ
from iqdbc.can.parser import CANParser
-_SNG_ACC_MIN_DIST = 3
-_SNG_ACC_MAX_DIST = 4.5
+# EPB resume fires only while the lead is pulling away within this gap band (m).
+_RESUME_GAP_MIN = 3.0
+_RESUME_GAP_MAX = 4.5
+_EPB_PULSE_FRAMES = 15
class IQStopAndGoController:
def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
self.CP = CP
self.CP_IQ = CP_IQ
- self.enabled = CP_IQ.flags & (SubaruFlagsIQ.STOP_AND_GO | SubaruFlagsIQ.STOP_AND_GO_MANUAL_PARKING_BRAKE)
- self.manual_parking_brake = CP_IQ.flags & SubaruFlagsIQ.STOP_AND_GO_MANUAL_PARKING_BRAKE
+ self.enabled = bool(CP_IQ.flags & (SubaruFlagsIQ.STOP_AND_GO | SubaruFlagsIQ.STOP_AND_GO_MANUAL_PARKING_BRAKE))
+ self.manual_parking_brake = bool(CP_IQ.flags & SubaruFlagsIQ.STOP_AND_GO_MANUAL_PARKING_BRAKE)
- self.last_standstill_frame = 0
- self.epb_resume_frames_remaining = -1
- self.prev_close_distance = 0.0
+ self.standstill_since = 0
+ self._pulse_left = 0
+ self.prev_gap = 0.0
- def update_epb_resume_sequence(self, should_resume: bool) -> bool:
+ def _epb_pulse(self, trigger: bool) -> bool:
+ # A trigger arms a fixed-length resume pulse; the pulse then plays out frame by frame.
if self.manual_parking_brake:
return False
+ if trigger:
+ self._pulse_left = _EPB_PULSE_FRAMES
+ if self._pulse_left > 0:
+ self._pulse_left -= 1
+ return True
+ return False
- if should_resume:
- self.epb_resume_frames_remaining = 15
-
- send_resume = self.epb_resume_frames_remaining > 0
- if self.epb_resume_frames_remaining > 0:
- self.epb_resume_frames_remaining -= 1
-
- return send_resume
-
- def update_stop_and_go(self, CC: structs.CarControl, CS: CarStateBase, frame: int) -> bool:
- """
- Manages stop-and-go functionality for adaptive cruise control (ACC).
-
- Args:
- CC: Car control data
- CS: Car state data
- frame: Current frame number
-
- Returns:
- bool: True if resume command should be sent, False otherwise
- """
-
+ def _want_resume(self, CC: structs.CarControl, CS: CarStateBase, frame: int) -> bool:
if not CC.enabled or not CC.hudControl.leadVisible:
return False
- close_distance = CS.es_distance_msg["Close_Distance"]
- in_standstill = CS.out.standstill
+ gap = CS.es_distance_msg["Close_Distance"]
+ standing = CS.out.standstill
+ if not standing:
+ self.standstill_since = frame
- if not in_standstill:
- self.last_standstill_frame = frame
+ hold_arm, hold_reset = (0.75, 0.8) if self.CP.flags & SubaruFlags.PREGLOBAL else (0.5, 0.55)
+ held_for = (frame - self.standstill_since) * DT_CTRL
+ held_long_enough = held_for > hold_arm
+ if held_for >= hold_reset:
+ self.standstill_since = frame
- # Check if we've been in standstill long enough
- mpb_standstill_timers = (0.75, 0.8) if self.CP.flags & SubaruFlags.PREGLOBAL else (0.5, 0.55)
- standstill_duration = (frame - self.last_standstill_frame) * DT_CTRL
- in_standstill_hold = standstill_duration > mpb_standstill_timers[0]
- if (frame - self.last_standstill_frame) * DT_CTRL >= mpb_standstill_timers[1]:
- self.last_standstill_frame = frame
-
- # Car state distance-based conditions (EPB only)
- in_resume_distance = _SNG_ACC_MIN_DIST < close_distance < _SNG_ACC_MAX_DIST
- distance_increasing = close_distance > self.prev_close_distance
- distance_resume_allowed = in_resume_distance and distance_increasing
+ lead_pulling_away = _RESUME_GAP_MIN < gap < _RESUME_GAP_MAX and gap > self.prev_gap
+ self.prev_gap = gap
if self.manual_parking_brake:
- # Manual parking brake: Direct resume when the standstill hold threshold is reached to prevent ACC fault
- send_resume = in_standstill_hold
- else:
- # EPB: Resume sequence with trigger on distance with lead car increasing
- should_resume = CS.out.standstill and distance_resume_allowed
- send_resume = self.update_epb_resume_sequence(should_resume)
-
- self.prev_close_distance = close_distance
-
- return send_resume
+ return held_long_enough
+ return self._epb_pulse(standing and lead_pulling_away)
def create_creep_assist(self, packer, CC: structs.CarControl, CS: CarStateBase, frame: int) -> list[CanData]:
- can_sends = []
-
if not self.enabled:
- return can_sends
-
- send_resume = self.update_stop_and_go(CC, CS, frame)
-
- can_sends.append(subarucan_ext.create_throttle(packer, self.CP, CS.throttle_msg, send_resume and not self.manual_parking_brake))
+ return []
+ resume = self._want_resume(CC, CS, frame)
+ can_sends = [iq_subarucan.create_throttle(packer, self.CP, CS.throttle_msg, resume and not self.manual_parking_brake)]
if frame % 2 == 0:
- can_sends.append(subarucan_ext.create_brake_pedal(packer, self.CP, CS.brake_pedal_msg, send_resume and self.manual_parking_brake))
-
+ can_sends.append(iq_subarucan.create_brake_pedal(packer, self.CP, CS.brake_pedal_msg, resume and self.manual_parking_brake))
return can_sends
@@ -108,14 +83,11 @@ class IQStopAndGoState:
def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
self.CP = CP
self.CP_IQ = CP_IQ
-
self.brake_pedal_msg: dict[str, float] = {}
self.throttle_msg: dict[str, float] = {}
def update(self, ret: structs.CarState, can_parsers: dict[StrEnum, CANParser]) -> None:
cp = can_parsers[Bus.pt]
-
self.brake_pedal_msg = copy.copy(cp.vl["Brake_Pedal"])
-
if not self.CP.flags & SubaruFlags.HYBRID:
self.throttle_msg = copy.copy(cp.vl["Throttle"])
diff --git a/iqdbc_repo/iqdbc/lvbs/car/subaru/iq_subarucan.py b/iqdbc_repo/iqdbc/lvbs/car/subaru/iq_subarucan.py
new file mode 100644
index 0000000..5fd8e16
--- /dev/null
+++ b/iqdbc_repo/iqdbc/lvbs/car/subaru/iq_subarucan.py
@@ -0,0 +1,41 @@
+"""
+Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
+
+Camera-bus message spoofers for Subaru stop-and-go: re-emit the stock Throttle
+and Brake_Pedal frames, nudging a single field to trigger an ACC resume from a
+standstill. Field sets mirror the DBC message layout.
+"""
+from iqdbc.car.subaru.values import CanBus, SubaruFlags
+
+_THROTTLE_FIELDS_PREGLOBAL = ("Throttle_Pedal", "Signal1", "Not_Full_Throttle", "Signal2", "Engine_RPM",
+ "Off_Throttle", "Signal3", "Throttle_Cruise", "Throttle_Combo", "Throttle_Body",
+ "Off_Throttle_2", "Signal4")
+_THROTTLE_FIELDS_GLOBAL = ("CHECKSUM", "Signal1", "Engine_RPM", "Neutral", "Throttle_Pedal", "Throttle_Cruise",
+ "Throttle_Combo", "Signal3", "Off_Accel")
+_BRAKE_FIELDS_PREGLOBAL = ("Speed", "Brake_Pedal", "Signal1")
+_BRAKE_FIELDS_GLOBAL = ("CHECKSUM", "Signal1", "Speed", "Signal2", "Brake_Lights", "Signal3", "Brake_Pedal", "Signal4")
+
+
+def _next_counter(msg):
+ return (msg["COUNTER"] + 1) % 0x10
+
+
+def create_throttle(packer, CP, throttle_msg, send_resume):
+ preglobal = bool(CP.flags & SubaruFlags.PREGLOBAL)
+ fields = _THROTTLE_FIELDS_PREGLOBAL if preglobal else _THROTTLE_FIELDS_GLOBAL
+ values = {name: throttle_msg[name] for name in fields}
+ values["COUNTER"] = _next_counter(throttle_msg)
+ if send_resume:
+ values["Throttle_Pedal"] = 5
+ return packer.make_can_msg("Throttle", CanBus.camera, values)
+
+
+def create_brake_pedal(packer, CP, brake_pedal_msg, send_resume):
+ preglobal = bool(CP.flags & SubaruFlags.PREGLOBAL)
+ fields = _BRAKE_FIELDS_PREGLOBAL if preglobal else _BRAKE_FIELDS_GLOBAL
+ values = {name: brake_pedal_msg[name] for name in fields}
+ if not preglobal:
+ values["COUNTER"] = _next_counter(brake_pedal_msg)
+ if send_resume:
+ values["Speed"] = 1 if preglobal else 3
+ return packer.make_can_msg("Brake_Pedal", CanBus.camera, values)
diff --git a/iqdbc_repo/iqdbc/lvbs/car/subaru/values_ext.py b/iqdbc_repo/iqdbc/lvbs/car/subaru/iq_values.py
similarity index 63%
rename from iqdbc_repo/iqdbc/lvbs/car/subaru/values_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/subaru/iq_values.py
index a58d763..6536b0c 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/subaru/values_ext.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/subaru/iq_values.py
@@ -1,14 +1,16 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
+
+IQ.Pilot Subaru extension flags. Selected in apply_iq_car_config() from the user's
+stop-and-go params and consumed by the stop-and-go controller and panda safety.
"""
-
from enum import IntFlag
-class SubaruSafetyFlagsIQ:
- STOP_AND_GO = 1
-
-
class SubaruFlagsIQ(IntFlag):
STOP_AND_GO = 1
STOP_AND_GO_MANUAL_PARKING_BRAKE = 2
+
+
+class SubaruSafetyFlagsIQ:
+ STOP_AND_GO = 1
diff --git a/iqdbc_repo/iqdbc/lvbs/car/subaru/subarucan_ext.py b/iqdbc_repo/iqdbc/lvbs/car/subaru/subarucan_ext.py
deleted file mode 100644
index b6a710e..0000000
--- a/iqdbc_repo/iqdbc/lvbs/car/subaru/subarucan_ext.py
+++ /dev/null
@@ -1,68 +0,0 @@
-from iqdbc.car.subaru.values import CanBus, SubaruFlags
-
-
-def create_counter(msg):
- return (msg["COUNTER"] + 1) % 0x10
-
-
-def create_throttle(packer, CP, throttle_msg, send_resume):
- if CP.flags & SubaruFlags.PREGLOBAL:
- values = {s: throttle_msg[s] for s in [
- "Throttle_Pedal",
- "Signal1",
- "Not_Full_Throttle",
- "Signal2",
- "Engine_RPM",
- "Off_Throttle",
- "Signal3",
- "Throttle_Cruise",
- "Throttle_Combo",
- "Throttle_Body",
- "Off_Throttle_2",
- "Signal4",
- ]}
- else:
- values = {s: throttle_msg[s] for s in [
- "CHECKSUM",
- "Signal1",
- "Engine_RPM",
- "Neutral",
- "Throttle_Pedal",
- "Throttle_Cruise",
- "Throttle_Combo",
- "Signal3",
- "Off_Accel",
- ]}
-
- values["COUNTER"] = create_counter(throttle_msg)
-
- if send_resume:
- values["Throttle_Pedal"] = 5
-
- return packer.make_can_msg("Throttle", CanBus.camera, values)
-
-
-def create_brake_pedal(packer, CP, brake_pedal_msg, send_resume):
- if CP.flags & SubaruFlags.PREGLOBAL:
- values = {s: brake_pedal_msg[s] for s in [
- "Speed",
- "Brake_Pedal",
- "Signal1",
- ]}
- else:
- values = {s: brake_pedal_msg[s] for s in [
- "CHECKSUM",
- "Signal1",
- "Speed",
- "Signal2",
- "Brake_Lights",
- "Signal3",
- "Brake_Pedal",
- "Signal4",
- ]}
- values["COUNTER"] = create_counter(brake_pedal_msg)
-
- if send_resume:
- values["Speed"] = 1 if CP.flags & SubaruFlags.PREGLOBAL else 3
-
- return packer.make_can_msg("Brake_Pedal", CanBus.camera, values)
diff --git a/iqdbc_repo/iqdbc/lvbs/car/tesla/carstate_ext.py b/iqdbc_repo/iqdbc/lvbs/car/tesla/iq_carstate.py
similarity index 80%
rename from iqdbc_repo/iqdbc/lvbs/car/tesla/carstate_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/tesla/iq_carstate.py
index fc0da12..90be564 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/tesla/carstate_ext.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/tesla/iq_carstate.py
@@ -12,15 +12,24 @@ from iqdbc.lvbs.car.tesla.values import TeslaFlagsIQ
ButtonType = structs.CarState.ButtonEvent.Type
-class CarStateExt:
+class IQCarState:
def __init__(self, CP: structs.CarParams, CP_IQ: structs.IQCarParams):
self.CP = CP
self.CP_IQ = CP_IQ
self.infotainment_3_finger_press = 0
+ self.vehicle_bus_available = bool(CP_IQ.flags & TeslaFlagsIQ.HAS_VEHICLE_BUS)
def update(self, ret: structs.CarState, ret_iq: structs.IQCarState, can_parsers: dict[StrEnum, CANParser]) -> None:
- if self.CP_IQ.flags & TeslaFlagsIQ.HAS_VEHICLE_BUS:
+ if Bus.adas in can_parsers:
+ cp_adas = can_parsers[Bus.adas]
+
+ odometer_km = float(cp_adas.vl["ID3B6UI_odometer"].get("UI_odometer", 0.0))
+ if 0.0 < odometer_km < 4294967.296:
+ self.vehicle_bus_available = True
+ ret.odometer = odometer_km
+
+ if self.vehicle_bus_available and Bus.adas in can_parsers:
cp_adas = can_parsers[Bus.adas]
prev_infotainment_3_finger_press = self.infotainment_3_finger_press
@@ -66,7 +75,9 @@ class CarStateExt:
def get_parser(CP: structs.CarParams, CP_IQ: structs.IQCarParams) -> dict[StrEnum, CANParser]:
messages = {}
- if CP_IQ.flags & TeslaFlagsIQ.HAS_VEHICLE_BUS:
+ # Only tap the vehicle bus on cars where fingerprinting saw it: an always-on
+ # bus-1 parser trips bus_timeout -> canBusMissing on harnesses without the tap.
+ if CP_IQ.flags & TeslaFlagsIQ.HAS_VEHICLE_BUS and Bus.adas in DBC[CP.carFingerprint]:
messages[Bus.adas] = CANParser(DBC[CP.carFingerprint][Bus.adas], [], CANBUS.vehicle)
return messages
diff --git a/iqdbc_repo/iqdbc/lvbs/car/tests/test_car_catalog.py b/iqdbc_repo/iqdbc/lvbs/car/tests/test_car_catalog.py
index 40e4482..5ce5da3 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/tests/test_car_catalog.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/tests/test_car_catalog.py
@@ -1,12 +1,25 @@
import json
+import os
-from iqdbc.lvbs.car.car_catalog import build_car_catalog, CAR_LIST_JSON_OUT
+from iqdbc.car.common.basedir import BASEDIR
+from iqdbc.lvbs.car.car_catalog import build_car_catalog
+
+CATALOG_JSON = os.path.join(BASEDIR, "..", "..", "iqpilot", "selfdrive", "car", "vehicle_catalog.json")
+
+_KEY_TO_ATTR = {"id": "platform", "mk": "make", "grp": "brand", "mdl": "model", "yrs": "year", "req": "package"}
+
+
+def _decode(envelope) -> dict:
+ out = {}
+ for record in (envelope.get("vehicles") or {}).values():
+ out[record.get("label", "")] = {attr: record.get(key) for key, attr in _KEY_TO_ATTR.items()}
+ return out
class TestCarList:
def test_generator(self):
- generated_car_list = json.dumps(build_car_catalog(), indent=2, ensure_ascii=False)
- with open(CAR_LIST_JSON_OUT) as f:
- current_car_list = f.read()
+ generated = build_car_catalog()
+ with open(CATALOG_JSON) as f:
+ shipped = _decode(json.load(f))
- assert generated_car_list == current_car_list, "Run iqdbc/lvbs/car/car_catalog.py to update the car list"
+ assert shipped == generated, "Run: python -m openpilot.iqpilot.selfdrive.car.vehicle_catalog"
diff --git a/iqdbc_repo/iqdbc/lvbs/car/toyota/carstate_ext.py b/iqdbc_repo/iqdbc/lvbs/car/toyota/iq_carstate.py
similarity index 99%
rename from iqdbc_repo/iqdbc/lvbs/car/toyota/carstate_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/toyota/iq_carstate.py
index 3508cfe..df00cee 100644
--- a/iqdbc_repo/iqdbc/lvbs/car/toyota/carstate_ext.py
+++ b/iqdbc_repo/iqdbc/lvbs/car/toyota/iq_carstate.py
@@ -21,7 +21,7 @@ ZSS_DIFF_THRESHOLD = 4
ZSS_MAX_THRESHOLD = 10
-class CarStateExt:
+class IQCarState:
def __init__(self, CP, CP_IQ):
self.CP = CP
self.CP_IQ = CP_IQ
diff --git a/iqdbc_repo/iqdbc/lvbs/car/toyota/fingerprints_ext.py b/iqdbc_repo/iqdbc/lvbs/car/toyota/iq_fingerprints.py
similarity index 100%
rename from iqdbc_repo/iqdbc/lvbs/car/toyota/fingerprints_ext.py
rename to iqdbc_repo/iqdbc/lvbs/car/toyota/iq_fingerprints.py
diff --git a/iqdbc_repo/iqdbc/safety/lateral.h b/iqdbc_repo/iqdbc/safety/lateral.h
index 32e794d..6671584 100644
--- a/iqdbc_repo/iqdbc/safety/lateral.h
+++ b/iqdbc_repo/iqdbc/safety/lateral.h
@@ -6,7 +6,7 @@ static const float ISO_LATERAL_ACCEL = 3.0; // m/s^2
static const float EARTH_G = 9.81;
static const float AVERAGE_ROAD_ROLL = 0.06; // ~3.4 degrees, 6% superelevation
-static const float MAX_LATERAL_ACCEL = ISO_LATERAL_ACCEL + (EARTH_G * AVERAGE_ROAD_ROLL); // ~3.6 m/s^2
+static const float MAX_LATERAL_ACCEL = ISO_LATERAL_ACCEL + (EARTH_G * AVERAGE_ROAD_ROLL); // ~5.6 m/s^2
bool is_lat_active(void) {
return controls_allowed || aol_is_lateral_control_allowed_by_aol();
@@ -233,7 +233,7 @@ bool steer_angle_cmd_checks(int desired_angle, bool steer_control_enabled, const
if (limits.angle_is_curvature) {
// Limit to average banked road since safety doesn't have the roll
- static const float MAX_LATERAL_ACCEL = ISO_LATERAL_ACCEL - (EARTH_G * AVERAGE_ROAD_ROLL); // ~2.4 m/s^2
+ static const float MAX_LATERAL_ACCEL = ISO_LATERAL_ACCEL - (EARTH_G * AVERAGE_ROAD_ROLL); // ~4.4 m/s^2
// Allow small tolerance by using minimum speed and rounding curvature up
const float speed_lower = SAFETY_MAX(vehicle_speed.min / VEHICLE_SPEED_FACTOR, 1.0);
@@ -301,7 +301,7 @@ bool steer_angle_cmd_checks_vm(int desired_angle, bool steer_control_enabled, co
// TODO: remove the inaccurate breakpoint angle limiting function above and always use this one
// Highway curves are rolled in the direction of the turn, add tolerance to compensate
- static const float MAX_LATERAL_ACCEL = ISO_LATERAL_ACCEL + (EARTH_G * AVERAGE_ROAD_ROLL); // ~3.6 m/s^2
+ static const float MAX_LATERAL_ACCEL = ISO_LATERAL_ACCEL + (EARTH_G * AVERAGE_ROAD_ROLL); // ~5.6 m/s^2
// Lower than ISO 11270 lateral jerk limit, which is 5.0 m/s^3
static const float MAX_LATERAL_JERK = 3.0 + (EARTH_G * AVERAGE_ROAD_ROLL); // ~3.6 m/s^3
diff --git a/iqdbc_repo/iqdbc/safety/modes/hyundai.h b/iqdbc_repo/iqdbc/safety/modes/hyundai.h
index f37d9dc..deaff48 100644
--- a/iqdbc_repo/iqdbc/safety/modes/hyundai.h
+++ b/iqdbc_repo/iqdbc/safety/modes/hyundai.h
@@ -3,6 +3,8 @@
#include "iqdbc/safety/declarations.h"
#include "iqdbc/safety/modes/hyundai_common.h"
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+
#define HYUNDAI_LIMITS(steer, rate_up, rate_down) { \
.max_torque = (steer), \
.max_rate_up = (rate_up), \
@@ -21,96 +23,84 @@
extern const LongitudinalLimits HYUNDAI_LONG_LIMITS;
const LongitudinalLimits HYUNDAI_LONG_LIMITS = {
- .max_accel = 200, // 1/100 m/s2
- .min_accel = -350, // 1/100 m/s2
- .zero_accel = 0,
+ .max_accel = 250, // 1/100 m/s2
+ .min_accel = -400, // 1/100 m/s2
};
-#define HYUNDAI_COMMON_TX_MSGS(scc_bus) \
- {0x340, 0, 8, .check_relay = true}, /* LKAS11 Bus 0 */ \
- {0x4F1, scc_bus, 4, .check_relay = false}, /* CLU11 Bus 0 (radar-SCC) or 2 (camera-SCC) */ \
- {0x485, 0, 4, .check_relay = true}, /* LFAHDA_MFC Bus 0 */ \
-
-#define HYUNDAI_LONG_COMMON_TX_MSGS(scc_bus) \
- HYUNDAI_COMMON_TX_MSGS(scc_bus) \
- {0x420, 0, 8, .check_relay = true}, /* SCC11 Bus 0 */ \
- {0x421, 0, 8, .check_relay = true}, /* SCC12 Bus 0 */ \
- {0x50A, 0, 8, .check_relay = true}, /* SCC13 Bus 0 */ \
- {0x389, 0, 8, .check_relay = true}, /* SCC14 Bus 0 */ \
- {0x4A2, 0, 2, .check_relay = false}, /* FRT_RADAR11 Bus 0 */ \
-
-#define HYUNDAI_COMMON_RX_CHECKS(legacy) \
- {.msg = {{0x260, 0, 8, 100U, .max_counter = 3U, .ignore_quality_flag = true}, \
- {0x371, 0, 8, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }}}, \
- {.msg = {{0x386, 0, 8, 100U, .ignore_checksum = (legacy), .ignore_counter = (legacy), .max_counter = (legacy) ? 0U : 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
- {.msg = {{0x394, 0, 8, 100U, .ignore_checksum = (legacy), .ignore_counter = (legacy), .max_counter = (legacy) ? 0U : 7U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
- {.msg = {{0x251, 0, 8, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
- {.msg = {{0x4F1, 0, 4, 50U, .ignore_checksum = true, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
-
-#define HYUNDAI_SCC11_ADDR_CHECK(scc_bus) \
- {.msg = {{0x420, (scc_bus), 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
-
-#define HYUNDAI_SCC12_ADDR_CHECK(scc_bus) \
- {.msg = {{0x421, (scc_bus), 8, 50U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
-
-#define HYUNDAI_FCEV_GAS_ADDR_CHECK \
- {.msg = {{0x91, 0, 8, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
-
-#define HYUNDAI_LDA_BUTTON_ADDR_CHECK \
- {.msg = {{0x391, 0, 8, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true, .frequency = 50U}, { 0 }, { 0 }}}, \
-
-#define HYUNDAI_NON_SCC_HEV_ADDR_CHECK \
- {.msg = {{0x595U, 0, 8, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
-
-#define HYUNDAI_NON_SCC_EV_ADDR_CHECK \
- {.msg = {{0x592U, 0, 8, 10U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
-
static const CanMsg HYUNDAI_TX_MSGS[] = {
- HYUNDAI_COMMON_TX_MSGS(0)
+ {0x340, 0, 8}, // LKAS11 Bus 0
+ {0x4F1, 0, 4}, // CLU11 Bus 0
+ {0x485, 0, 8}, // LFAHDA_MFC Bus 0
+ {593, 2, 8}, // MDPS12, Bus 2
+ {1056, 0, 8}, // SCC11, Bus 0
+ {1057, 0, 8}, // SCC12, Bus 0
+ {1290, 0, 8}, // SCC13, Bus 0
+ {905, 0, 8}, // SCC14, Bus 0
+ {909, 0, 8}, // FCA11 Bus 0
+ {1155, 0, 8}, // FCA12 Bus 0
+ {1186, 0, 8}, // FRT_RADAR11, Bus 0
+ {1265, 2, 4}, // CLU11, Bus 0, 2
+ {0x7D0, 0, 8}, // radar UDS TX addr Bus 0 (for radar disable) // 2000
+ {0x7b1, 0, 8},
};
-static bool hyundai_legacy = false;
+#define HYUNDAI_COMMON_RX_CHECKS(legacy) \
+ {.msg = {{0x260, 0, 8, .max_counter = 3U, .frequency = 100U}, \
+ {0x371, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 100U}, \
+ {0x91, 0, 8, .ignore_checksum = true, .ignore_counter = true, .frequency = 100U}}}, \
+ {.msg = {{0x386, 0, 8, .ignore_checksum = (legacy), .ignore_counter = (legacy), .max_counter = (legacy) ? 0U : 15U, .frequency = 100U}, { 0 }, { 0 }}}, \
+ {.msg = {{0x394, 0, 8, .ignore_checksum = (legacy), .ignore_counter = (legacy), .max_counter = (legacy) ? 0U : 7U, .frequency = 100U}, { 0 }, { 0 }}}, \
-static uint8_t hyundai_get_counter(const CANPacket_t *msg) {
+#define HYUNDAI_SCC12_ADDR_CHECK(scc_bus) \
+ {.msg = {{0x421, (scc_bus), 8, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}}, \
+
+static bool hyundai_legacy = false;
+static bool hyundai_cruise_buttons_alt = false;
+
+static uint8_t hyundai_get_counter(const CANPacket_t *to_push) {
+ int addr = GET_ADDR(to_push);
uint8_t cnt = 0;
- if (msg->addr == 0x260U) {
- cnt = (msg->data[7] >> 4) & 0x3U;
- } else if (msg->addr == 0x386U) {
- cnt = ((msg->data[3] >> 6) << 2) | (msg->data[1] >> 6);
- } else if (msg->addr == 0x394U) {
- cnt = (msg->data[1] >> 5) & 0x7U;
- } else if (msg->addr == 0x421U) {
- cnt = msg->data[7] & 0xFU;
- } else if (msg->addr == 0x4F1U) {
- cnt = (msg->data[3] >> 4) & 0xFU;
+ if (addr == 0x260) {
+ cnt = (GET_BYTE(to_push, 7) >> 4) & 0x3U;
+ } else if (addr == 0x386) {
+ cnt = ((GET_BYTE(to_push, 3) >> 6) << 2) | (GET_BYTE(to_push, 1) >> 6);
+ } else if (addr == 0x394) {
+ cnt = (GET_BYTE(to_push, 1) >> 5) & 0x7U;
+ } else if (addr == 0x421) {
+ cnt = GET_BYTE(to_push, 7) & 0xFU;
+ } else if (addr == 0x4F1) {
+ cnt = (GET_BYTE(to_push, 3) >> 4) & 0xFU;
} else {
}
return cnt;
}
-static uint32_t hyundai_get_checksum(const CANPacket_t *msg) {
+static uint32_t hyundai_get_checksum(const CANPacket_t *to_push) {
+ int addr = GET_ADDR(to_push);
uint8_t chksum = 0;
- if (msg->addr == 0x260U) {
- chksum = msg->data[7] & 0xFU;
- } else if (msg->addr == 0x386U) {
- chksum = ((msg->data[7] >> 6) << 2) | (msg->data[5] >> 6);
- } else if (msg->addr == 0x394U) {
- chksum = msg->data[6] & 0xFU;
- } else if (msg->addr == 0x421U) {
- chksum = msg->data[7] >> 4;
+ if (addr == 0x260) {
+ chksum = GET_BYTE(to_push, 7) & 0xFU;
+ } else if (addr == 0x386) {
+ chksum = ((GET_BYTE(to_push, 7) >> 6) << 2) | (GET_BYTE(to_push, 5) >> 6);
+ } else if (addr == 0x394) {
+ chksum = GET_BYTE(to_push, 6) & 0xFU;
+ } else if (addr == 0x421) {
+ chksum = GET_BYTE(to_push, 7) >> 4;
} else {
}
return chksum;
}
-static uint32_t hyundai_compute_checksum(const CANPacket_t *msg) {
+static uint32_t hyundai_compute_checksum(const CANPacket_t *to_push) {
+ int addr = GET_ADDR(to_push);
+
uint8_t chksum = 0;
- if (msg->addr == 0x386U) {
+ if (addr == 0x386) {
// count the bits
for (int i = 0; i < 8; i++) {
- uint8_t b = msg->data[i];
+ uint8_t b = GET_BYTE(to_push, i);
for (int j = 0; j < 8; j++) {
uint8_t bit = 0;
// exclude checksum and counter
@@ -124,12 +114,12 @@ static uint32_t hyundai_compute_checksum(const CANPacket_t *msg) {
} else {
// sum of nibbles
for (int i = 0; i < 8; i++) {
- if ((msg->addr == 0x394U) && (i == 7)) {
+ if ((addr == 0x394) && (i == 7)) {
continue; // exclude
}
- uint8_t b = msg->data[i];
- if (((msg->addr == 0x260U) && (i == 7)) || ((msg->addr == 0x394U) && (i == 6)) || ((msg->addr == 0x421U) && (i == 7))) {
- b &= (msg->addr == 0x421U) ? 0x0FU : 0xF0U; // remove checksum
+ uint8_t b = GET_BYTE(to_push, i);
+ if (((addr == 0x260) && (i == 7)) || ((addr == 0x394) && (i == 6)) || ((addr == 0x421) && (i == 7))) {
+ b &= (addr == 0x421) ? 0x0FU : 0xF0U; // remove checksum
}
chksum += (b % 16U) + (b / 16U);
}
@@ -139,127 +129,115 @@ static uint32_t hyundai_compute_checksum(const CANPacket_t *msg) {
return chksum;
}
-static void hyundai_rx_hook(const CANPacket_t *msg) {
+static void hyundai_rx_hook(const CANPacket_t *to_push) {
+ int bus = GET_BUS(to_push);
+ int addr = GET_ADDR(to_push);
// SCC12 is on bus 2 for camera-based SCC cars, bus 0 on all others
- if (msg->addr == 0x421U) {
- if (((msg->bus == 0U) && !hyundai_camera_scc) || ((msg->bus == 2U) && hyundai_camera_scc)) {
+ if (addr == 0x421) {
+ if (((bus == 0) && !hyundai_camera_scc) || ((bus == 2) && hyundai_camera_scc)) {
// 2 bits: 13-14
- int cruise_engaged = (GET_BYTES(msg, 0, 4) >> 13) & 0x3U;
+ int cruise_engaged = (GET_BYTES(to_push, 0, 4) >> 13) & 0x3U;
hyundai_common_cruise_state_check(cruise_engaged);
}
}
- if (msg->addr == 0x420U) {
- if (((msg->bus == 0U) && !hyundai_camera_scc) || ((msg->bus == 2U) && hyundai_camera_scc)) {
- if (!hyundai_longitudinal) {
- acc_main_on = GET_BIT(msg, 0U);
- }
- }
- }
-
- if (msg->bus == 0U) {
- if (msg->addr == 0x251U) {
- int torque_driver_new = (GET_BYTES(msg, 0, 2) & 0x7ffU) - 1024U;
+ if (bus == 0) {
+ if (addr == 0x251) {
+ int torque_driver_new = (GET_BYTES(to_push, 0, 2) & 0x7ffU) - 1024U;
// update array of samples
update_sample(&torque_driver, torque_driver_new);
}
- if (msg->addr == 0x391U) {
- aol_button_press = GET_BIT(msg, 4U) ? AOL_BUTTON_PRESSED : AOL_BUTTON_NOT_PRESSED;
- }
-
// ACC steering wheel buttons
- if (msg->addr == 0x4F1U) {
- int cruise_button = msg->data[0] & 0x7U;
- bool main_button = GET_BIT(msg, 3U);
+ if (addr == 1007) hyundai_cruise_buttons_alt = true; // CASPER_EV: 1007
+ if (addr == 1007) {
+ int cruise_button = (GET_BYTE(to_push, 7) >> 4) & 0x07U;
+ bool main_button = GET_BIT(to_push, 58U);
+ hyundai_common_cruise_buttons_check(cruise_button, main_button);
+ }
+ else if (addr == 0x4F1 && !hyundai_cruise_buttons_alt) {
+ int cruise_button = GET_BYTE(to_push, 0) & 0x7U;
+ bool main_button = GET_BIT(to_push, 3U);
hyundai_common_cruise_buttons_check(cruise_button, main_button);
}
// gas press, different for EV, hybrid, and ICE models
- if ((msg->addr == 0x371U) && hyundai_ev_gas_signal) {
- gas_pressed = (((msg->data[4] & 0x7FU) << 1) | (msg->data[3] >> 7)) != 0U;
- } else if ((msg->addr == 0x371U) && hyundai_hybrid_gas_signal) {
- gas_pressed = msg->data[7] != 0U;
- } else if ((msg->addr == 0x91U) && hyundai_fcev_gas_signal) {
- gas_pressed = msg->data[6] != 0U;
- } else if ((msg->addr == 0x260U) && !hyundai_ev_gas_signal && !hyundai_hybrid_gas_signal) {
- gas_pressed = (msg->data[7] >> 6) != 0U;
+ if ((addr == 0x371) && hyundai_ev_gas_signal) {
+ gas_pressed = (((GET_BYTE(to_push, 4) & 0x7FU) << 1) | GET_BYTE(to_push, 3) >> 7) != 0U;
+ } else if ((addr == 0x371) && hyundai_hybrid_gas_signal) {
+ gas_pressed = GET_BYTE(to_push, 7) != 0U;
+ } else if ((addr == 0x91) && hyundai_fcev_gas_signal) {
+ gas_pressed = GET_BYTE(to_push, 6) != 0U;
+ } else if ((addr == 0x260) && !hyundai_ev_gas_signal && !hyundai_hybrid_gas_signal) {
+ gas_pressed = (GET_BYTE(to_push, 7) >> 6) != 0U;
} else {
}
// sample wheel speed, averaging opposite corners
- if (msg->addr == 0x386U) {
- uint32_t front_left_speed = GET_BYTES(msg, 0, 2) & 0x3FFFU;
- uint32_t rear_right_speed = GET_BYTES(msg, 6, 2) & 0x3FFFU;
+ if (addr == 0x386) {
+ uint32_t front_left_speed = GET_BYTES(to_push, 0, 2) & 0x3FFFU;
+ uint32_t rear_right_speed = GET_BYTES(to_push, 6, 2) & 0x3FFFU;
vehicle_moving = (front_left_speed > HYUNDAI_STANDSTILL_THRSLD) || (rear_right_speed > HYUNDAI_STANDSTILL_THRSLD);
}
- if (msg->addr == 0x394U) {
- brake_pressed = ((msg->data[5] >> 5U) & 0x3U) == 0x2U;
+ if (addr == 0x394) {
+ brake_pressed = ((GET_BYTE(to_push, 5) >> 5U) & 0x3U) == 0x2U;
}
- if (msg->addr == 0x592U) {
- acc_main_on = GET_BIT(msg, 34U);
- bool cruise_engaged = GET_BIT(msg, 35U);
- hyundai_common_cruise_state_check(cruise_engaged);
- }
+ bool stock_ecu_detected = (addr == 0x340);
- if (msg->addr == 0x595U) {
- acc_main_on = GET_BIT(msg, 50U);
- bool cruise_engaged = GET_BIT(msg, 51U);
- hyundai_common_cruise_state_check(cruise_engaged);
- }
-
- if ((msg->addr == 0x260U) && hyundai_non_scc && !hyundai_ev_gas_signal && !hyundai_hybrid_gas_signal) {
- acc_main_on = GET_BIT(msg, 25U);
- bool cruise_engaged = GET_BIT(msg, 26U);
- hyundai_common_cruise_state_check(cruise_engaged);
+ // If openpilot is controlling longitudinal we need to ensure the radar is turned off
+ // Enforce by checking we don't see SCC12
+ if (hyundai_longitudinal && (addr == 0x421)) {
+ stock_ecu_detected = true;
}
+ generic_rx_checks();
+ stock_ecu_check(stock_ecu_detected);
}
-
- hyundai_common_reset_acc_main_on_mismatches();
}
-static bool hyundai_tx_hook(const CANPacket_t *msg) {
- const TorqueSteeringLimits HYUNDAI_STEERING_LIMITS = HYUNDAI_LIMITS(384, 3, 7);
- const TorqueSteeringLimits HYUNDAI_STEERING_LIMITS_ALT = HYUNDAI_LIMITS(270, 2, 3);
+uint32_t last_ts_lkas11_from_op = 0;
+uint32_t last_ts_scc12_from_op = 0;
+uint32_t last_ts_scc13_from_op = 0;
+uint32_t last_ts_mdps12_from_op = 0;
+uint32_t last_ts_fca11_from_op = 0;
+uint32_t last_ts_fca12_from_op = 0;
+uint32_t last_ts_lfahda_mfc_from_op = 0;
+
+static bool hyundai_tx_hook(const CANPacket_t *to_send) {
+ const TorqueSteeringLimits HYUNDAI_STEERING_LIMITS = HYUNDAI_LIMITS(512, 10, 10);
+ const TorqueSteeringLimits HYUNDAI_STEERING_LIMITS_ALT = HYUNDAI_LIMITS(512, 10, 10);
const TorqueSteeringLimits HYUNDAI_STEERING_LIMITS_ALT_2 = HYUNDAI_LIMITS(170, 2, 3);
bool tx = true;
+ int addr = GET_ADDR(to_send);
// FCA11: Block any potential actuation
- if (msg->addr == 0x38DU) {
- int CR_VSM_DecCmd = msg->data[1];
- bool FCA_CmdAct = GET_BIT(msg, 20U);
- bool CF_VSM_DecCmdAct = GET_BIT(msg, 31U);
+ if (addr == 0x38D) {
+ int CR_VSM_DecCmd = GET_BYTE(to_send, 1);
+ bool FCA_CmdAct = GET_BIT(to_send, 20U);
+ bool CF_VSM_DecCmdAct = GET_BIT(to_send, 31U);
if ((CR_VSM_DecCmd != 0) || FCA_CmdAct || CF_VSM_DecCmdAct) {
tx = false;
}
}
- if (msg->addr == 0x420U) {
- acc_main_on_tx = GET_BIT(msg, 0U);
- hyundai_common_acc_main_on_sync();
- }
-
// ACCEL: safety check
- if (msg->addr == 0x421U) {
- int desired_accel_raw = (((msg->data[4] & 0x7U) << 8) | msg->data[3]) - 1023U;
- int desired_accel_val = ((msg->data[5] << 3) | (msg->data[4] >> 5)) - 1023U;
+ if (addr == 0x421) {
+ int desired_accel_raw = (((GET_BYTE(to_send, 4) & 0x7U) << 8) | GET_BYTE(to_send, 3)) - 1023U;
+ int desired_accel_val = ((GET_BYTE(to_send, 5) << 3) | (GET_BYTE(to_send, 4) >> 5)) - 1023U;
- int aeb_decel_cmd = msg->data[2];
- bool aeb_req = GET_BIT(msg, 54U);
+ int aeb_decel_cmd = GET_BYTE(to_send, 2);
+ bool aeb_req = GET_BIT(to_send, 54U);
bool violation = false;
violation |= longitudinal_accel_checks(desired_accel_raw, HYUNDAI_LONG_LIMITS);
violation |= longitudinal_accel_checks(desired_accel_val, HYUNDAI_LONG_LIMITS);
- if (!hyundai_escc) {
- violation |= (aeb_decel_cmd != 0);
- violation |= aeb_req;
- }
+ violation |= (aeb_decel_cmd != 0);
+ violation |= aeb_req;
if (violation) {
tx = false;
@@ -267,9 +245,9 @@ static bool hyundai_tx_hook(const CANPacket_t *msg) {
}
// LKA STEER: safety check
- if (msg->addr == 0x340U) {
- int desired_torque = ((GET_BYTES(msg, 0, 4) >> 16) & 0x7ffU) - 1024U;
- bool steer_req = GET_BIT(msg, 27U);
+ if (addr == 0x340) {
+ int desired_torque = ((GET_BYTES(to_send, 0, 4) >> 16) & 0x7ffU) - 1024U;
+ bool steer_req = GET_BIT(to_send, 27U);
const TorqueSteeringLimits limits = hyundai_alt_limits_2 ? HYUNDAI_STEERING_LIMITS_ALT_2 :
hyundai_alt_limits ? HYUNDAI_STEERING_LIMITS_ALT : HYUNDAI_STEERING_LIMITS;
@@ -280,220 +258,199 @@ static bool hyundai_tx_hook(const CANPacket_t *msg) {
}
// UDS: Only tester present ("\x02\x3E\x80\x00\x00\x00\x00\x00") allowed on diagnostics address
- if (msg->addr == 0x7D0U) {
- if ((GET_BYTES(msg, 0, 4) != 0x00803E02U) || (GET_BYTES(msg, 4, 4) != 0x0U)) {
+ if (addr == 0x7D0) {
+ if ((GET_BYTES(to_send, 0, 4) != 0x00803E02U) || (GET_BYTES(to_send, 4, 4) != 0x0U)) {
tx = false;
}
}
// BUTTONS: used for resume spamming and cruise cancellation
- if ((msg->addr == 0x4F1U) && !hyundai_longitudinal) {
- int button = msg->data[0] & 0x7U;
+ if ((addr == 0x4F1) && !hyundai_longitudinal) {
+ int button = GET_BYTE(to_send, 0) & 0x7U;
bool allowed_resume = (button == 1) && controls_allowed;
- bool allowed_set = (button == 2) && controls_allowed;
- bool allowed_cancel = (button == 4) && cruise_engaged_prev;
- if (!(allowed_resume || allowed_set || allowed_cancel)) {
+ bool allowed_cancel = (button == 4) && (cruise_engaged_prev || controls_allowed);
+ if (!(allowed_resume || allowed_cancel)) {
tx = false;
}
}
+ uint32_t now = microsecond_timer_get();
+ if(addr == 832)
+ last_ts_lkas11_from_op = (tx == 0 ? 0 : now);
+ else if(addr == 1057)
+ last_ts_scc12_from_op = (tx == 0 ? 0 : now);
+ else if(addr == 593)
+ last_ts_mdps12_from_op = (tx == 0 ? 0 : now);
+ else if (addr == 909)
+ last_ts_fca11_from_op = (tx == 0 ? 0 : now);
+ else if (addr == 1155)
+ last_ts_fca12_from_op = (tx == 0 ? 0 : now);
+ else if(addr == 1290)
+ last_ts_scc13_from_op = (tx == 0 ? 0 : now);
+ else if(addr == 0x485)
+ last_ts_lfahda_mfc_from_op = (tx == 0 ? 0 : now);
return tx;
}
-static safety_config hyundai_init(uint16_t param) {
- static const CanMsg HYUNDAI_LONG_TX_MSGS[] = {
- HYUNDAI_LONG_COMMON_TX_MSGS(0)
- {0x38D, 0, 8, .check_relay = false}, // FCA11 Bus 0
- {0x483, 0, 8, .check_relay = false}, // FCA12 Bus 0
- {0x7D0, 0, 8, .check_relay = false}, // radar UDS TX addr Bus 0 (for radar disable)
- };
+static bool hyundai_fwd_hook(int bus_num, int addr) {
+ int bus_fwd = -1;
- static const CanMsg HYUNDAI_CAMERA_SCC_TX_MSGS[] = {
- HYUNDAI_COMMON_TX_MSGS(2)
- };
+ uint32_t now = microsecond_timer_get();
- static const CanMsg HYUNDAI_CAMERA_SCC_LONG_TX_MSGS[] = {
- HYUNDAI_LONG_COMMON_TX_MSGS(2)
- };
+ // forward cam to ccan and viceversa, except lkas cmd
+ if (bus_num == 0) {
+ bus_fwd = 2;
- static const CanMsg HYUNDAI_LONG_ESCC_TX_MSGS[] = {
- HYUNDAI_LONG_COMMON_TX_MSGS(0)
- };
-
- hyundai_common_init(param);
- hyundai_legacy = false;
-
- safety_config ret;
- if (hyundai_longitudinal) {
- // Use CLU11 (buttons) to manage controls allowed instead of SCC cruise state
- static RxCheck hyundai_long_rx_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(false)
- };
-
- static RxCheck hyundai_lda_button_long_rx_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(false)
- HYUNDAI_LDA_BUTTON_ADDR_CHECK
- };
-
- static RxCheck hyundai_fcev_long_rx_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(false)
- HYUNDAI_FCEV_GAS_ADDR_CHECK
- };
-
- static RxCheck hyundai_fcev_lda_button_long_rx_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(false)
- HYUNDAI_FCEV_GAS_ADDR_CHECK
- HYUNDAI_LDA_BUTTON_ADDR_CHECK
- };
-
- if (hyundai_fcev_gas_signal) {
- if (hyundai_has_lda_button) {
- SET_RX_CHECKS(hyundai_fcev_lda_button_long_rx_checks, ret);
- } else {
- SET_RX_CHECKS(hyundai_fcev_long_rx_checks, ret);
- }
- } else {
- if (hyundai_has_lda_button) {
- SET_RX_CHECKS(hyundai_lda_button_long_rx_checks, ret);
- } else {
- SET_RX_CHECKS(hyundai_long_rx_checks, ret);
- }
- }
- if (hyundai_escc) {
- SET_TX_MSGS(HYUNDAI_LONG_ESCC_TX_MSGS, ret);
- } else if (hyundai_camera_scc) {
- SET_TX_MSGS(HYUNDAI_CAMERA_SCC_LONG_TX_MSGS, ret);
- } else {
- SET_TX_MSGS(HYUNDAI_LONG_TX_MSGS, ret);
- }
-
- } else if (hyundai_camera_scc) {
- static RxCheck hyundai_cam_scc_rx_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(false)
- HYUNDAI_SCC12_ADDR_CHECK(2)
- HYUNDAI_SCC11_ADDR_CHECK(2)
- HYUNDAI_LDA_BUTTON_ADDR_CHECK
- };
-
- ret = BUILD_SAFETY_CFG(hyundai_cam_scc_rx_checks, HYUNDAI_CAMERA_SCC_TX_MSGS);
- } else {
- static RxCheck hyundai_rx_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(false)
- HYUNDAI_SCC12_ADDR_CHECK(0)
- HYUNDAI_SCC11_ADDR_CHECK(0)
- };
-
- static RxCheck hyundai_lda_button_rx_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(false)
- HYUNDAI_SCC12_ADDR_CHECK(0)
- HYUNDAI_SCC11_ADDR_CHECK(0)
- HYUNDAI_LDA_BUTTON_ADDR_CHECK
- };
-
- static RxCheck hyundai_fcev_rx_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(false)
- HYUNDAI_SCC12_ADDR_CHECK(0)
- HYUNDAI_SCC11_ADDR_CHECK(0)
- HYUNDAI_FCEV_GAS_ADDR_CHECK
- };
-
- static RxCheck hyundai_fcev_lda_button_rx_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(false)
- HYUNDAI_SCC12_ADDR_CHECK(0)
- HYUNDAI_SCC11_ADDR_CHECK(0)
- HYUNDAI_FCEV_GAS_ADDR_CHECK
- HYUNDAI_LDA_BUTTON_ADDR_CHECK
- };
-
- static RxCheck hyundai_non_scc_addr_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(false)
- };
-
- static RxCheck hyundai_non_scc_lda_button_addr_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(false)
- HYUNDAI_LDA_BUTTON_ADDR_CHECK
- };
-
- static RxCheck hyundai_hev_non_scc_addr_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(false)
- HYUNDAI_NON_SCC_HEV_ADDR_CHECK
- };
-
- static RxCheck hyundai_hev_non_scc_lda_button_addr_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(false)
- HYUNDAI_NON_SCC_HEV_ADDR_CHECK
- HYUNDAI_LDA_BUTTON_ADDR_CHECK
- };
-
- static RxCheck hyundai_ev_non_scc_addr_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(false)
- HYUNDAI_NON_SCC_EV_ADDR_CHECK
- };
-
- static RxCheck hyundai_ev_non_scc_lda_button_addr_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(false)
- HYUNDAI_NON_SCC_EV_ADDR_CHECK
- HYUNDAI_LDA_BUTTON_ADDR_CHECK
- };
-
- SET_TX_MSGS(HYUNDAI_TX_MSGS, ret);
- if (hyundai_fcev_gas_signal) {
- if (hyundai_has_lda_button) {
- SET_RX_CHECKS(hyundai_fcev_lda_button_rx_checks, ret);
- } else {
- SET_RX_CHECKS(hyundai_fcev_rx_checks, ret);
- }
- } else if (hyundai_non_scc) {
- if (hyundai_ev_gas_signal) {
- if (hyundai_has_lda_button) {
- SET_RX_CHECKS(hyundai_ev_non_scc_lda_button_addr_checks, ret);
- } else {
- SET_RX_CHECKS(hyundai_ev_non_scc_addr_checks, ret);
- }
- } else if (hyundai_hybrid_gas_signal) {
- if (hyundai_has_lda_button) {
- SET_RX_CHECKS(hyundai_hev_non_scc_lda_button_addr_checks, ret);
- } else {
- SET_RX_CHECKS(hyundai_hev_non_scc_addr_checks, ret);
- }
- } else {
- if (hyundai_has_lda_button) {
- SET_RX_CHECKS(hyundai_non_scc_lda_button_addr_checks, ret);
- } else {
- SET_RX_CHECKS(hyundai_non_scc_addr_checks, ret);
- }
- }
- } else {
- if (hyundai_has_lda_button) {
- SET_RX_CHECKS(hyundai_lda_button_rx_checks, ret);
- } else {
- SET_RX_CHECKS(hyundai_rx_checks, ret);
+ if(addr == 593) {
+ if(now - last_ts_mdps12_from_op < 200000) {
+ bus_fwd = -1;
}
}
}
- return ret;
+
+ if (bus_num == 2) {
+ bool is_lkas_msg = addr == 832;
+ bool is_lfahda_msg = addr == 1157;
+ bool is_scc_msg = addr == 1056 || addr == 1057 || addr == 905;
+ bool is_scc13_msg = addr == 1290;
+ bool is_fca11_msg = addr == 909;
+ bool is_fca12_msg = addr == 1155;
+
+ bool block_msg = is_lkas_msg || is_lfahda_msg || is_scc_msg || is_scc13_msg || is_fca11_msg || is_fca12_msg;
+ if (!block_msg) {
+ bus_fwd = 0;
+ }
+ else {
+ if(is_lkas_msg) {
+ if(now - last_ts_lkas11_from_op >= 200000) {
+ bus_fwd = 0;
+ }
+ }
+ else if(is_lfahda_msg) {
+ if (now - last_ts_lfahda_mfc_from_op >= 200000)
+ bus_fwd = 0;
+ }
+ else if (is_scc_msg) {
+ if (now - last_ts_scc12_from_op >= 400000)
+ bus_fwd = 0;
+ }
+ else if (is_scc13_msg) {
+ if (now - last_ts_scc13_from_op >= 800000)
+ bus_fwd = 0;
+ }
+ else if (is_fca11_msg) {
+ if (now - last_ts_fca11_from_op >= 400000)
+ bus_fwd = 0;
+ }
+ else if (is_fca12_msg) {
+ if (now - last_ts_fca12_from_op >= 400000)
+ bus_fwd = 0;
+ }
+ }
+ }
+
+ return bus_fwd == -1;
+}
+
+/* case
+ - legacy(on/off) + camera_scc(allways longitudinal on) + longitudinal(scc off)
+*/
+static safety_config hyundai_init_carrot(bool legacy_car) {
+ static const CanMsg HYUNDAI_LONG_TX_MSGS[] = {
+ {0x340, 0, 8}, // LKAS11 Bus 0
+ {0x4F1, 0, 4}, // CLU11 Bus 0
+ {0x485, 0, 8}, // LFAHDA_MFC Bus 0
+ {0x251, 2, 8}, // MDPS12 Bus 2
+ {0x420, 0, 8}, // SCC11 Bus 0
+ {0x421, 0, 8}, // SCC12 Bus 0
+ {0x50A, 0, 8}, // SCC13 Bus 0
+ {0x389, 0, 8}, // SCC14 Bus 0
+ {0x4A2, 0, 2}, // FRT_RADAR11 Bus 0
+ {0x38D, 0, 8}, // FCA11 Bus 0
+ {0x483, 0, 8}, // FCA12 Bus 0
+ {0x7D0, 0, 8}, // radar UDS TX addr Bus 0 (for radar disable)
+ };
+
+ static const CanMsg HYUNDAI_CAMERA_SCC_TX_MSGS[] = {
+ {0x340, 0, 8}, // LKAS11 Bus 0
+ {0x4F1, 2, 4}, // CLU11 Bus 2
+ {0x485, 0, 8}, // LFAHDA_MFC Bus 0
+ {593, 2, 8}, // MDPS12, Bus 2
+ {1056, 0, 8}, // SCC11, Bus 0
+ {1057, 0, 8}, // SCC12, Bus 0
+ {1290, 0, 8}, // SCC13, Bus 0
+ {905, 0, 8}, // SCC14, Bus 0
+ {909, 0, 8}, // FCA11 Bus 0
+ {1155, 0, 8}, // FCA12 Bus 0
+ {1186, 0, 8}, // FRT_RADAR11, Bus 0
+ {0x4F1, 0, 4}, // CLU11 Bus 0
+ };
+
+ safety_config ret;
+ if (hyundai_camera_scc) {
+ static RxCheck hyundai_cam_scc_rx_checks[] = {
+ HYUNDAI_COMMON_RX_CHECKS(false)
+ HYUNDAI_SCC12_ADDR_CHECK(2)
+ };
+ static RxCheck hyundai_cam_scc_rx_checks_legacy[] = {
+ HYUNDAI_COMMON_RX_CHECKS(true)
+ HYUNDAI_SCC12_ADDR_CHECK(2)
+ };
+ if(legacy_car) ret = BUILD_SAFETY_CFG(hyundai_cam_scc_rx_checks_legacy, HYUNDAI_CAMERA_SCC_TX_MSGS);
+ else ret = BUILD_SAFETY_CFG(hyundai_cam_scc_rx_checks, HYUNDAI_CAMERA_SCC_TX_MSGS);
+ }
+ else if (hyundai_longitudinal) {
+ static RxCheck hyundai_long_rx_checks[] = {
+ HYUNDAI_COMMON_RX_CHECKS(false)
+ // Use CLU11 (buttons) to manage controls allowed instead of SCC cruise state
+ {.msg = {{0x4F1, 0, 4, .ignore_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}
+},
+ };
+ static RxCheck hyundai_long_rx_checks_legacy[] = {
+ HYUNDAI_COMMON_RX_CHECKS(true)
+ // Use CLU11 (buttons) to manage controls allowed instead of SCC cruise state
+ {.msg = {{0x4F1, 0, 4, .ignore_checksum = true, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}
+},
+ };
+
+ if(legacy_car) ret = BUILD_SAFETY_CFG(hyundai_long_rx_checks_legacy, HYUNDAI_LONG_TX_MSGS);
+ else ret = BUILD_SAFETY_CFG(hyundai_long_rx_checks, HYUNDAI_LONG_TX_MSGS);
+ }
+ else {
+ static RxCheck hyundai_rx_checks[] = {
+ HYUNDAI_COMMON_RX_CHECKS(false)
+ HYUNDAI_SCC12_ADDR_CHECK(0)
+ };
+ static RxCheck hyundai_rx_checks_legacy[] = {
+ HYUNDAI_COMMON_RX_CHECKS(true)
+ //HYUNDAI_SCC12_ADDR_CHECK(0)
+ };
+
+ if(legacy_car) ret = BUILD_SAFETY_CFG(hyundai_rx_checks_legacy, HYUNDAI_TX_MSGS);
+ else ret = BUILD_SAFETY_CFG(hyundai_rx_checks, HYUNDAI_TX_MSGS);
+ }
+ return ret;
+}
+
+
+static safety_config hyundai_init(uint16_t param) {
+ hyundai_common_init(param);
+ hyundai_legacy = false;
+ return hyundai_init_carrot(hyundai_legacy);
}
static safety_config hyundai_legacy_init(uint16_t param) {
- // older hyundai models have less checks due to missing counters and checksums
- static RxCheck hyundai_legacy_rx_checks[] = {
- HYUNDAI_COMMON_RX_CHECKS(true)
- HYUNDAI_SCC12_ADDR_CHECK(0)
- HYUNDAI_SCC11_ADDR_CHECK(0)
- };
-
hyundai_common_init(param);
hyundai_legacy = true;
- hyundai_longitudinal = false;
- hyundai_camera_scc = false;
- return BUILD_SAFETY_CFG(hyundai_legacy_rx_checks, HYUNDAI_TX_MSGS);
+ return hyundai_init_carrot(hyundai_legacy);
}
const safety_hooks hyundai_hooks = {
.init = hyundai_init,
.rx = hyundai_rx_hook,
.tx = hyundai_tx_hook,
+ .fwd = hyundai_fwd_hook,
.get_counter = hyundai_get_counter,
.get_checksum = hyundai_get_checksum,
.compute_checksum = hyundai_compute_checksum,
@@ -503,6 +460,7 @@ const safety_hooks hyundai_legacy_hooks = {
.init = hyundai_legacy_init,
.rx = hyundai_rx_hook,
.tx = hyundai_tx_hook,
+ .fwd = hyundai_fwd_hook,
.get_counter = hyundai_get_counter,
.get_checksum = hyundai_get_checksum,
.compute_checksum = hyundai_compute_checksum,
diff --git a/iqdbc_repo/iqdbc/safety/modes/hyundai_canfd.h b/iqdbc_repo/iqdbc/safety/modes/hyundai_canfd.h
index 9256cee..e3a6cbd 100644
--- a/iqdbc_repo/iqdbc/safety/modes/hyundai_canfd.h
+++ b/iqdbc_repo/iqdbc/safety/modes/hyundai_canfd.h
@@ -3,149 +3,550 @@
#include "iqdbc/safety/declarations.h"
#include "iqdbc/safety/modes/hyundai_common.h"
-#define HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(bus) \
- {0x1CF, bus, 8, .check_relay = false}, /* CRUISE_BUTTON */ \
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
+#pragma GCC diagnostic ignored "-Wunused-function"
-#define HYUNDAI_CANFD_LKA_STEERING_COMMON_TX_MSGS(a_can, e_can) \
- HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(e_can) \
- {0x50, a_can, 16, .check_relay = (a_can) == 0}, /* LKAS */ \
- {0x2A4, a_can, 24, .check_relay = (a_can) == 0}, /* CAM_0x2A4 */ \
+const TorqueSteeringLimits HYUNDAI_CANFD_STEERING_LIMITS = {
+ .max_torque = 512, //270,
+ .max_rt_delta = 112,
-#define HYUNDAI_CANFD_LKA_STEERING_ALT_COMMON_TX_MSGS(a_can, e_can) \
- HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(e_can) \
- {0x110, a_can, 32, .check_relay = (a_can) == 0}, /* LKAS_ALT */ \
- {0x362, a_can, 32, .check_relay = (a_can) == 0}, /* CAM_0x362 */ \
+ .max_rate_up = 2,
+ .max_rate_down = 3,
+ .driver_torque_allowance = 250,
+ .driver_torque_multiplier = 2,
+ .type = TorqueDriverLimited,
-#define HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(e_can) \
- {0x12A, e_can, 16, .check_relay = (e_can) == 0}, /* LFA */ \
- {0x1E0, e_can, 16, .check_relay = (e_can) == 0}, /* LFAHDA_CLUSTER */ \
+ // the EPS faults when the steering angle is above a certain threshold for too long. to prevent this,
+ // we allow setting torque actuation bit to 0 while maintaining the requested torque value for two consecutive frames
+ .min_valid_request_frames = 89,
+ .max_invalid_request_frames = 2,
+ .min_valid_request_rt_interval = 810000, // 810ms; a ~10% buffer on cutting every 90 frames
+ .has_steer_req_tolerance = true,
+};
+
+const CanMsg HYUNDAI_CANFD_HDA2_TX_MSGS[] = {
+ {0x50, 0, 16}, // LKAS
+ {0x1CF, 1, 8}, // CRUISE_BUTTON
+ {0x2A4, 0, 24}, // CAM_0x2A4
+};
+
+const CanMsg HYUNDAI_CANFD_HDA2_ALT_STEERING_TX_MSGS[] = {
+ {0x110, 0, 32}, // LKAS_ALT
+ {0x1CF, 1, 8}, // CRUISE_BUTTON
+ {0x362, 0, 32}, // CAM_0x362
+ {0x1AA, 1, 16}, // CRUISE_ALT_BUTTONS , carrot
+};
+
+const CanMsg HYUNDAI_CANFD_HDA2_LONG_TX_MSGS[] = {
+ {0x50, 0, 16}, // LKAS
+ {0x1CF, 0, 8}, // CRUISE_BUTTON
+ {0x1CF, 1, 8}, // CRUISE_BUTTON
+ {0x1CF, 2, 8}, // CRUISE_BUTTON
+ {0x1AA, 0, 16}, // CRUISE_ALT_BUTTONS , carrot
+ {0x1AA, 1, 16}, // CRUISE_ALT_BUTTONS , carrot
+ {0x1AA, 2, 16}, // CRUISE_ALT_BUTTONS , carrot
+ {0x2A4, 0, 24}, // CAM_0x2A4
+ {0x51, 0, 32}, // ADRV_0x51
+ {0x730, 1, 8}, // tester present for ADAS ECU disable
+ {0x12A, 1, 16}, // LFA
+ {0x160, 1, 16}, // ADRV_0x160
+ {0x1E0, 1, 16}, // LFAHDA_CLUSTER
+ {0x1A0, 1, 32}, // CRUISE_INFO
+ {0x1EA, 1, 32}, // ADRV_0x1ea
+ {0x200, 1, 8}, // ADRV_0x200
+ {0x345, 1, 8}, // ADRV_0x345
+ {0x1DA, 1, 32}, // ADRV_0x1da
+
+ {0x12A, 0, 16}, // LFA
+ {0x1E0, 0, 16}, // LFAHDA_CLUSTER
+ {0x160, 0, 16}, // ADRV_0x160
+ {0x1EA, 0, 32}, // ADRV_0x1ea
+ {0x200, 0, 8}, // ADRV_0x200
+ {0x1A0, 0, 32}, // CRUISE_INFO
+ {0x345, 0, 8}, // ADRV_0x345
+ {0x1DA, 0, 32}, // ADRV_0x1da
+
+ {0x362, 0, 32}, // CAM_0x362
+ {0x362, 1, 32}, // CAM_0x362
+ {0x2a4, 1, 24}, // CAM_0x2a4
+
+ {0x110, 0, 32}, // LKAS_ALT (272)
+ {0x110, 1, 32}, // LKAS_ALT (272)
+
+ {0x50, 1, 16}, //
+ {0x51, 1, 32}, //
+
+ {353, 0, 32}, // ADRV_353
+ {354, 0, 32}, // CORNER_RADAR_HIGHWAY
+ {512, 0, 8}, // ADRV_0x200
+ {1187, 2, 8}, // 4A3
+ {1204, 2, 8}, // 4B4
+
+ {203, 0, 24}, // CB
+ {373, 2, 24}, // TCS(0x175)
+ {506, 2, 32}, // CLUSTER_SPEED_LIMIT
+ {234, 2, 24}, // MDPS
+ {687, 2, 8}, // STEER_TOUCH_2AF
+
+ {0x4BE, 2, 8}, // NEW_MSG_4BE (may be corner radar enabler x)
+ {0x4B9, 2, 8}, // NEW_MSG_4B9 (may be corner radar enabler)
+};
+
+const CanMsg HYUNDAI_CANFD_HDA1_TX_MSGS[] = {
+ {0x12A, 0, 16}, // LFA
+ {0x1A0, 0, 32}, // CRUISE_INFO
+ {0x1CF, 0, 8}, // CRUISE_BUTTON
+ {0x1CF, 2, 8}, // CRUISE_BUTTON
+ {0x1E0, 0, 16}, // LFAHDA_CLUSTER
+ {0x160, 0, 16}, // ADRV_0x160
+ {0x7D0, 0, 8}, // tester present for radar ECU disable
+ {0x1AA, 2, 16}, // CRUISE_ALT_BUTTONS , carrot
+ {203, 0, 24}, // CB
+ {373, 2, 24}, // TCS(0x175)
+
+ {353, 0, 32}, // ADRV_353
+ {354, 0, 32}, // CORNER_RADAR_HIGHWAY
+ {512, 0, 8}, // ADRV_0x200
+ {1187, 2, 8}, // 4A3
+ {1204, 2, 8}, // 4B4
+ {373, 2, 24}, // TCS(0x175)
+ {234, 2, 24}, // MDPS
+ {687, 2, 8}, // STEER_TOUCH_2AF
+
+};
-#define HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(e_can, longitudinal) \
- {0x1A0, e_can, 32, .check_relay = (longitudinal)}, /* SCC_CONTROL */ \
// *** Addresses checked in rx hook ***
// EV, ICE, HYBRID: ACCELERATOR (0x35), ACCELERATOR_BRAKE_ALT (0x100), ACCELERATOR_ALT (0x105)
-#define HYUNDAI_CANFD_COMMON_RX_CHECKS(pt_bus) \
- {.msg = {{0x35, (pt_bus), 32, 100U, .max_counter = 0xffU, .ignore_quality_flag = true}, \
- {0x100, (pt_bus), 32, 100U, .max_counter = 0xffU, .ignore_quality_flag = true}, \
- {0x105, (pt_bus), 32, 100U, .max_counter = 0xffU, .ignore_quality_flag = true}}}, \
- {.msg = {{0x175, (pt_bus), 24, 50U, .max_counter = 0xffU, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
- {.msg = {{0xa0, (pt_bus), 24, 100U, .max_counter = 0xffU, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
- {.msg = {{0xea, (pt_bus), 24, 100U, .max_counter = 0xffU, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
+#define HYUNDAI_CANFD_COMMON_RX_CHECKS(pt_bus) \
+ {.msg = {{0x35, (pt_bus), 32, .max_counter = 0xffU, .frequency = 100U}, \
+ {0x100, (pt_bus), 32, .max_counter = 0xffU, .frequency = 100U}, \
+ {0x105, (pt_bus), 32, .max_counter = 0xffU, .frequency = 100U}}}, \
+ {.msg = {{0x175, (pt_bus), 24, .max_counter = 0xffU, .frequency = 50U}, { 0 }, { 0 }}}, \
+ {.msg = {{0xa0, (pt_bus), 24, .max_counter = 0xffU, .frequency = 100U}, { 0 }, { 0 }}}, \
+ {.msg = {{0xea, (pt_bus), 24, .max_counter = 0xffU, .frequency = 100U}, { 0 }, { 0 }}}, \
-#define HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(pt_bus) \
- HYUNDAI_CANFD_COMMON_RX_CHECKS(pt_bus) \
- {.msg = {{0x1cf, (pt_bus), 8, 50U, .ignore_checksum = true, .max_counter = 0xfU, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
+#define HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(pt_bus) \
+ {.msg = {{0x1cf, (pt_bus), 8, .ignore_checksum = true, .max_counter = 0xfU, .frequency = 50U}, { 0 }, { 0 }}}, \
-#define HYUNDAI_CANFD_ALT_BUTTONS_RX_CHECKS(pt_bus) \
- HYUNDAI_CANFD_COMMON_RX_CHECKS(pt_bus) \
- {.msg = {{0x1aa, (pt_bus), 16, 50U, .ignore_checksum = true, .max_counter = 0xffU, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
+#define HYUNDAI_CANFD_ALT_BUTTONS_ADDR_CHECK(pt_bus) \
+ {.msg = {{0x1aa, (pt_bus), 16, .ignore_checksum = true, .max_counter = 0xffU, .frequency = 50U}, { 0 }, { 0 }}}, \
// SCC_CONTROL (from ADAS unit or camera)
-#define HYUNDAI_CANFD_SCC_ADDR_CHECK(scc_bus) \
- {.msg = {{0x1a0, (scc_bus), 32, 50U, .max_counter = 0xffU, .ignore_quality_flag = true}, { 0 }, { 0 }}}, \
+#define HYUNDAI_CANFD_SCC_ADDR_CHECK(scc_bus) \
+ {.msg = {{0x1a0, (scc_bus), 32, .max_counter = 0xffU, .frequency = 50U}, { 0 }, { 0 }}}, \
-static bool hyundai_canfd_alt_buttons = false;
-static bool hyundai_canfd_lka_steering_alt = false;
+//static bool hyundai_canfd_alt_buttons = false;
+//static bool hyundai_canfd_hda2_alt_steering = false;
-static unsigned int hyundai_canfd_get_lka_addr(void) {
- return hyundai_canfd_lka_steering_alt ? 0x110U : 0x50U;
+// *** Non-HDA2 checks ***
+// Camera sends SCC messages on HDA1.
+// Both button messages exist on some platforms, so we ensure we track the correct one using flag
+RxCheck hyundai_canfd_rx_checks[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
+ HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(0)
+ HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
+};
+RxCheck hyundai_canfd_alt_buttons_rx_checks[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
+ HYUNDAI_CANFD_ALT_BUTTONS_ADDR_CHECK(0)
+ HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
+};
+
+// Longitudinal checks for HDA1
+RxCheck hyundai_canfd_long_rx_checks[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
+ HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(0)
+};
+RxCheck hyundai_canfd_long_alt_buttons_rx_checks[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
+ HYUNDAI_CANFD_ALT_BUTTONS_ADDR_CHECK(0)
+};
+
+// Radar sends SCC messages on these cars instead of camera
+RxCheck hyundai_canfd_radar_scc_rx_checks[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
+ HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(0)
+ HYUNDAI_CANFD_SCC_ADDR_CHECK(0)
+};
+RxCheck hyundai_canfd_radar_scc_alt_buttons_rx_checks[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
+ HYUNDAI_CANFD_ALT_BUTTONS_ADDR_CHECK(0)
+ HYUNDAI_CANFD_SCC_ADDR_CHECK(0)
+};
+
+
+// *** HDA2 checks ***
+// E-CAN is on bus 1, ADAS unit sends SCC messages on HDA2.
+// Does not use the alt buttons message
+RxCheck hyundai_canfd_hda2_rx_checks[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(1)
+ HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(1) // TODO: carrot: canival no 0x1cf
+ HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
+};
+RxCheck hyundai_canfd_hda2_rx_checks_scc2[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
+ HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(0) // TODO: carrot: canival no 0x1cf
+ HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
+};
+RxCheck hyundai_canfd_hda2_alt_buttons_rx_checks[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(1)
+ HYUNDAI_CANFD_ALT_BUTTONS_ADDR_CHECK(1)
+ HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
+};
+RxCheck hyundai_canfd_hda2_alt_buttons_rx_checks_scc2[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
+ HYUNDAI_CANFD_ALT_BUTTONS_ADDR_CHECK(0)
+ HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
+};
+RxCheck hyundai_canfd_hda2_long_rx_checks[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(1)
+ HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(1) // TODO: carrot: canival no 0x1cf
+};
+RxCheck hyundai_canfd_hda2_long_rx_checks_scc2[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
+ HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(0)
+};
+RxCheck hyundai_canfd_hda2_long_alt_buttons_rx_checks[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(1)
+ HYUNDAI_CANFD_ALT_BUTTONS_ADDR_CHECK(1)
+};
+RxCheck hyundai_canfd_hda2_long_alt_buttons_rx_checks_scc2[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
+ HYUNDAI_CANFD_ALT_BUTTONS_ADDR_CHECK(0)
+};
+
+
+const int HYUNDAI_PARAM_CANFD_ALT_BUTTONS = 32;
+const int HYUNDAI_PARAM_CANFD_HDA2_ALT_STEERING = 128;
+bool hyundai_canfd_alt_buttons = false;
+bool hyundai_canfd_hda2_alt_steering = false;
+bool hyundai_canfd_buffered_fwd = false;
+
+int hyundai_canfd_hda2_get_lkas_addr(void) {
+ return hyundai_canfd_hda2_alt_steering ? 0x110 : 0x50;
}
-static uint8_t hyundai_canfd_get_counter(const CANPacket_t *msg) {
+static uint8_t hyundai_canfd_get_counter(const CANPacket_t* to_push) {
uint8_t ret = 0;
- if (GET_LEN(msg) == 8U) {
- ret = msg->data[1] >> 4;
- } else {
- ret = msg->data[2];
+ if (GET_LEN(to_push) == 8U) {
+ ret = GET_BYTE(to_push, 1) >> 4;
+ }
+ else {
+ ret = GET_BYTE(to_push, 2);
}
return ret;
}
-static uint32_t hyundai_canfd_get_checksum(const CANPacket_t *msg) {
- uint32_t chksum = msg->data[0] | (msg->data[1] << 8);
+static uint32_t hyundai_canfd_get_checksum(const CANPacket_t* to_push) {
+ uint32_t chksum = GET_BYTE(to_push, 0) | (GET_BYTE(to_push, 1) << 8);
return chksum;
}
-static void hyundai_canfd_rx_hook(const CANPacket_t *msg) {
- const unsigned pt_bus = hyundai_canfd_lka_steering ? 1U : 0U;
- const unsigned int scc_bus = hyundai_camera_scc ? 2U : pt_bus;
+typedef struct {
+ int addr;
+ int bus; // forwarding block ��� tx bus: 0 or 2
+ int hz;
+ uint32_t timeout_us;
+ uint32_t last_tx_us;
+} CanfdTxState;
- if (msg->bus == pt_bus) {
+// forwarding block��: bus 0,2�� ���
+CanfdTxState canfd_tx_states[] = {
+ {0x50, 0, 100, 0U, 0U}, // 80: LKAS
+ {0x51, 0, 100, 0U, 0U}, // 81: ADRV_0x51
+ {0x110, 0, 100, 0U, 0U}, // 272: LKAS_ALT
+ {0x12A, 0, 100, 0U, 0U}, // 298: LFA
+ {0x160, 0, 50, 0U, 0U}, // 352: ADRV_0x160
+ {0x161, 0, 20, 0U, 0U}, // 353: ADRV_0x161
+ {0x162, 0, 20, 0U, 0U}, // 354: CCNC_0x162
+ {0x1A0, 0, 50, 0U, 0U}, // 416: SCC_CONTROL
+ {0x1DA, 0, 1, 0U, 0U}, // 474: ADRV_0x1da
+ {0x1E0, 0, 20, 0U, 0U}, // 480: LFAHDA_CLUSTER
+ {0x1EA, 0, 20, 0U, 0U}, // 490: ADRV_0x1ea
+ {0x200, 0, 20, 0U, 0U}, // 512: ADRV_0x200
+ {0x2A4, 0, 20, 0U, 0U}, // 676: CAM_0x2a4
+ {0x345, 0, 5, 0U, 0U}, // 837: ADRV_0x345
+ {0x362, 0, 10, 0U, 0U}, // 866: CAM_0x362
+ {0x0CB, 0, 100, 0U, 0U}, // 203: LFA_ALT
+
+ {0x175, 2, 50, 0U, 0U}, // 373: TCS
+ {0x1AA, 2, 50, 0U, 0U}, // 426: CRUISE_ALT_BUTTONS
+ {0x1CF, 2, 50, 0U, 0U}, // 463: CRUISE_BUTTON
+ {0x1FA, 2, 10, 0U, 0U}, // 506: CLUSTER_SPEED_LIMIT
+ {0x0EA, 2, 100, 0U, 0U}, // 234: MDPS
+ {0x2AF, 2, 10, 0U, 0U}, // 687: STEER_TOUCH_2AF
+ {0x4A3, 2, 5, 0U, 0U}, // 1187: HDA_INFO_4A3
+ {0x4B4, 2, 10, 0U, 0U}, // 1204: NEW_MSG_4B4
+ {0x4BE, 2, 10, 0U, 0U}, // 1214: NEW_MSG_4BE
+ {0x4B9, 2, 10, 0U, 0U}, // 1209: NEW_MSG_4B9
+
+ {0, 0, 0, 0U, 0U},
+};
+
+static CanfdTxState* find_canfd_tx_state(int bus, int addr) {
+ for (int i = 0; canfd_tx_states[i].addr > 0; i++) {
+ if ((canfd_tx_states[i].addr == addr) && (canfd_tx_states[i].bus == bus)) {
+ return &canfd_tx_states[i];
+ }
+ }
+ return NULL;
+}
+
+
+static void hyundai_canfd_set_counter(CANPacket_t* to_push, uint8_t counter) {
+ if (GET_LEN(to_push) == 8U) {
+ to_push->data[1] = (to_push->data[1] & 0x0FU) | ((counter & 0x0FU) << 4);
+ }
+ else {
+ to_push->data[2] = counter;
+ }
+}
+
+static void hyundai_canfd_set_checksum(CANPacket_t* to_push, uint16_t checksum) {
+ to_push->data[0] = (uint8_t)(checksum & 0xFFU);
+ to_push->data[1] = (uint8_t)((checksum >> 8U) & 0xFFU);
+}
+
+static void hyundai_canfd_update_checksum(CANPacket_t* to_push) {
+ to_push->data[0] = 0U;
+ to_push->data[1] = 0U;
+ uint32_t checksum = hyundai_common_canfd_compute_checksum(to_push);
+ hyundai_canfd_set_checksum(to_push, (uint16_t)checksum);
+}
+static void canfd_apply_counter_and_update_checksum(CANPacket_t* dst, uint8_t counter) {
+ hyundai_canfd_set_counter(dst, counter);
+ hyundai_canfd_update_checksum(dst);
+}
+static void canfd_record_tx_time(int bus, int addr, bool tx) {
+ CanfdTxState* st = find_canfd_tx_state(bus, addr);
+ if (st != NULL) {
+ st->last_tx_us = tx ? microsecond_timer_get() : 0U;
+ }
+}
+
+static bool canfd_should_block_fwd(int tx_bus, int addr, uint32_t now) {
+ CanfdTxState* st = find_canfd_tx_state(tx_bus, addr);
+ if (st == NULL) {
+ return false;
+ }
+ return (now - st->last_tx_us) < st->timeout_us;
+}
+
+#define CANFD_BFWD_MAX_QUEUE 2
+#define CANFD_BFWD_REUSE_MAX 2
+
+typedef struct {
+ int addr;
+ int dst_bus;
+ bool enabled;
+
+ bool started;
+ uint8_t head;
+ uint8_t tail;
+ uint8_t count;
+
+ uint8_t reuse_left;
+ bool has_last_pkt;
+ CANPacket_t last_pkt;
+
+ CANPacket_t q[CANFD_BFWD_MAX_QUEUE];
+} CanfdBufferedFwd;
+
+CanfdBufferedFwd canfd_bfwd[] = {
+ {.addr = 0x1A0, .dst_bus = 0, .enabled = true }, // SCC_CONTROL
+ {.addr = 0x12A, .dst_bus = 0, .enabled = true }, // LFA
+ {.addr = 0x0CB, .dst_bus = 0, .enabled = true }, // LFA_ALT
+ {.addr = 0x0EA, .dst_bus = 2, .enabled = true }, // MDPS
+ {.addr = 0x1AA, .dst_bus = 2, .enabled = true }, // CRUISE_ALT_BUTTONS
+ // {.addr = 0x1CF, .dst_bus = 2, .enabled = true }, // CRUISE_BUTTON
+ {.addr = 0x175, .dst_bus = 2, .enabled = true }, // TCS
+ { 0 },
+};
+
+static void canfd_copy_packet(CANPacket_t* dst, const CANPacket_t* src) {
+ dst->fd = src->fd;
+ dst->returned = 0U;
+ dst->rejected = 0U;
+ dst->extended = src->extended;
+ dst->addr = src->addr;
+ dst->bus = src->bus;
+ dst->data_len_code = src->data_len_code;
+ for (uint8_t i = 0U; i < GET_LEN(src); i++) {
+ dst->data[i] = src->data[i];
+ }
+}
+static CanfdBufferedFwd* canfd_bfwd_find(int addr, int dst_bus) {
+ for (int i = 0; canfd_bfwd[i].addr > 0; i++) {
+ if (canfd_bfwd[i].enabled &&
+ (canfd_bfwd[i].addr == addr) &&
+ (canfd_bfwd[i].dst_bus == dst_bus)) {
+ return &canfd_bfwd[i];
+ }
+ }
+ return NULL;
+}
+
+static void canfd_bfwd_reset(CanfdBufferedFwd* st) {
+ st->started = false;
+ st->head = 0U;
+ st->tail = 0U;
+ st->count = 0U;
+ st->reuse_left = 0U;
+ st->has_last_pkt = false;
+ st->last_pkt = (CANPacket_t){0};
+}
+static void canfd_bfwd_push(CanfdBufferedFwd* st, const CANPacket_t* pkt) {
+ if ((st == NULL) || !st->enabled) return;
+ if (GET_BUS(pkt) != st->dst_bus) return;
+
+ // queue�� �̹� 2���� �̹� �� packet�� ����
+ if (st->count >= CANFD_BFWD_MAX_QUEUE) {
+ return;
+ }
+
+ canfd_copy_packet(&st->q[st->tail], pkt);
+ st->tail = (st->tail + 1U) % CANFD_BFWD_MAX_QUEUE;
+ st->count++;
+ st->started = true;
+}
+
+static bool canfd_bfwd_pop(CanfdBufferedFwd* st, CANPacket_t* pkt) {
+ if ((st == NULL) || !st->enabled) {
+ return false;
+ }
+
+ if (!st->started || (st->count == 0U)) {
+ return false;
+ }
+
+ canfd_copy_packet(pkt, &st->q[st->head]);
+ st->head = (st->head + 1U) % CANFD_BFWD_MAX_QUEUE;
+ st->count--;
+
+ // ������ ���� packet ����
+ canfd_copy_packet(&st->last_pkt, pkt);
+ st->has_last_pkt = true;
+ st->reuse_left = CANFD_BFWD_REUSE_MAX;
+
+ if (st->count == 0U) {
+ st->started = false;
+ }
+
+ return true;
+}
+static bool canfd_bfwd_reuse_last(CanfdBufferedFwd* st, CANPacket_t* pkt) {
+ if ((st == NULL) || !st->enabled) {
+ return false;
+ }
+
+ if (!st->has_last_pkt || (st->reuse_left == 0U)) {
+ return false;
+ }
+
+ canfd_copy_packet(pkt, &st->last_pkt);
+ st->reuse_left--;
+
+ return true;
+}
+
+
+
+
+static void hyundai_canfd_rx_hook(const CANPacket_t *to_push) {
+ int bus = GET_BUS(to_push);
+ int addr = GET_ADDR(to_push);
+
+ int pt_bus = hyundai_canfd_hda2 ? 1 : 0;
+ const int scc_bus = hyundai_camera_scc ? 2 : pt_bus;
+
+ if (hyundai_camera_scc) pt_bus = 0;
+
+ if (bus == pt_bus) {
// driver torque
- if (msg->addr == 0xeaU) {
- int torque_driver_new = ((msg->data[11] & 0x1fU) << 8U) | msg->data[10];
+ if (addr == 0xea) {
+ int torque_driver_new = ((GET_BYTE(to_push, 11) & 0x1fU) << 8U) | GET_BYTE(to_push, 10);
torque_driver_new -= 4095;
update_sample(&torque_driver, torque_driver_new);
}
// cruise buttons
- const unsigned int button_addr = hyundai_canfd_alt_buttons ? 0x1aaU : 0x1cfU;
- if (msg->addr == button_addr) {
+ const int button_addr = hyundai_canfd_alt_buttons ? 0x1aa : 0x1cf;
+ if (addr == button_addr) {
bool main_button = false;
int cruise_button = 0;
- if (msg->addr == 0x1cfU) {
- cruise_button = msg->data[2] & 0x7U;
- main_button = GET_BIT(msg, 19U);
- aol_button_press = GET_BIT(msg, 23U) ? AOL_BUTTON_PRESSED : AOL_BUTTON_NOT_PRESSED;
+ if (addr == 0x1cf) {
+ cruise_button = GET_BYTE(to_push, 2) & 0x7U;
+ main_button = GET_BIT(to_push, 19U);
} else {
- cruise_button = (msg->data[4] >> 4) & 0x7U;
- main_button = GET_BIT(msg, 34U);
- aol_button_press = GET_BIT(msg, 39U) ? AOL_BUTTON_PRESSED : AOL_BUTTON_NOT_PRESSED;
+ cruise_button = (GET_BYTE(to_push, 4) >> 4) & 0x7U;
+ main_button = GET_BIT(to_push, 34U);
}
hyundai_common_cruise_buttons_check(cruise_button, main_button);
}
// gas press, different for EV, hybrid, and ICE models
- if ((msg->addr == 0x35U) && hyundai_ev_gas_signal) {
- gas_pressed = msg->data[5] != 0U;
- } else if ((msg->addr == 0x105U) && hyundai_hybrid_gas_signal) {
- gas_pressed = GET_BIT(msg, 103U) || (msg->data[13] != 0U) || GET_BIT(msg, 112U);
- } else if ((msg->addr == 0x100U) && !hyundai_ev_gas_signal && !hyundai_hybrid_gas_signal) {
- gas_pressed = GET_BIT(msg, 176U);
+ if ((addr == 0x35) && hyundai_ev_gas_signal) {
+ gas_pressed = GET_BYTE(to_push, 5) != 0U;
+ } else if ((addr == 0x105) && hyundai_hybrid_gas_signal) {
+ gas_pressed = GET_BIT(to_push, 103U) || (GET_BYTE(to_push, 13) != 0U) || GET_BIT(to_push, 112U);
+ } else if ((addr == 0x100) && !hyundai_ev_gas_signal && !hyundai_hybrid_gas_signal) {
+ gas_pressed = GET_BIT(to_push, 176U);
} else {
}
// brake press
- if (msg->addr == 0x175U) {
- brake_pressed = GET_BIT(msg, 81U);
+ if (addr == 0x175) {
+ brake_pressed = GET_BIT(to_push, 81U);
}
// vehicle moving
- if (msg->addr == 0xa0U) {
- uint32_t fl = (GET_BYTES(msg, 8, 2)) & 0x3FFFU;
- uint32_t fr = (GET_BYTES(msg, 10, 2)) & 0x3FFFU;
- uint32_t rl = (GET_BYTES(msg, 12, 2)) & 0x3FFFU;
- uint32_t rr = (GET_BYTES(msg, 14, 2)) & 0x3FFFU;
+ if (addr == 0xa0) {
+ uint32_t fl = (GET_BYTES(to_push, 8, 2)) & 0x3FFFU;
+ uint32_t fr = (GET_BYTES(to_push, 10, 2)) & 0x3FFFU;
+ uint32_t rl = (GET_BYTES(to_push, 12, 2)) & 0x3FFFU;
+ uint32_t rr = (GET_BYTES(to_push, 14, 2)) & 0x3FFFU;
vehicle_moving = (fl > HYUNDAI_STANDSTILL_THRSLD) || (fr > HYUNDAI_STANDSTILL_THRSLD) ||
(rl > HYUNDAI_STANDSTILL_THRSLD) || (rr > HYUNDAI_STANDSTILL_THRSLD);
// average of all 4 wheel speeds. Conversion: raw * 0.03125 / 3.6 = m/s
- UPDATE_VEHICLE_SPEED((fr + rr + rl + fl) / 4.0 * 0.03125 * KPH_TO_MS);
+ UPDATE_VEHICLE_SPEED((fr + rr + rl + fl) / 4.0 * 0.03125 / 3.6);
}
}
- if (msg->bus == scc_bus) {
+ if (bus == scc_bus) {
// cruise state
- if ((msg->addr == 0x1a0U) && !hyundai_longitudinal) {
+ if ((addr == 0x1a0) && !hyundai_longitudinal) {
// 1=enabled, 2=driver override
- int cruise_status = ((msg->data[8] >> 4) & 0x7U);
+ int cruise_status = ((GET_BYTE(to_push, 8) >> 4) & 0x7U);
bool cruise_engaged = (cruise_status == 1) || (cruise_status == 2);
hyundai_common_cruise_state_check(cruise_engaged);
- acc_main_on = GET_BIT(msg, 66U);
}
}
- hyundai_common_reset_acc_main_on_mismatches();
+ const int steer_addr = hyundai_canfd_hda2 ? hyundai_canfd_hda2_get_lkas_addr() : 0x12a;
+ bool stock_ecu_detected = (addr == steer_addr) && (bus == 0);
+ if (hyundai_longitudinal) {
+ // on HDA2, ensure ADRV ECU is still knocked out
+ // on others, ensure accel msg is blocked from camera
+ const int stock_scc_bus = hyundai_canfd_hda2 ? 1 : 0;
+ stock_ecu_detected = stock_ecu_detected || ((addr == 0x1a0) && (bus == stock_scc_bus));
+ }
+ generic_rx_checks();
+ stock_ecu_check(stock_ecu_detected);
+
}
-static bool hyundai_canfd_tx_hook(const CANPacket_t *msg) {
+static bool hyundai_canfd_tx_hook(const CANPacket_t *to_send_const) {
+ CANPacket_t* to_send = (CANPacket_t*)to_send_const;
+
const TorqueSteeringLimits HYUNDAI_CANFD_STEERING_LIMITS = {
- .max_torque = 270,
+ .max_torque = 512,
.max_rt_delta = 112,
- .max_rate_up = 2,
- .max_rate_down = 3,
+
+ .max_rate_up = 10,
+ .max_rate_down = 10,
.driver_torque_allowance = 250,
.driver_torque_multiplier = 2,
.type = TorqueDriverLimited,
@@ -159,12 +560,14 @@ static bool hyundai_canfd_tx_hook(const CANPacket_t *msg) {
};
bool tx = true;
+ int addr = GET_ADDR(to_send);
+ bool violation = false;
// steering
- const unsigned int steer_addr = (hyundai_canfd_lka_steering && !hyundai_longitudinal) ? hyundai_canfd_get_lka_addr() : 0x12aU;
- if (msg->addr == steer_addr) {
- int desired_torque = (((msg->data[6] & 0xFU) << 7U) | (msg->data[5] >> 1U)) - 1024U;
- bool steer_req = GET_BIT(msg, 52U);
+ const int steer_addr = (hyundai_canfd_hda2 && !hyundai_longitudinal) ? hyundai_canfd_hda2_get_lkas_addr() : 0x12a;
+ if (addr == steer_addr) {
+ int desired_torque = (((GET_BYTE(to_send, 6) & 0xFU) << 7U) | (GET_BYTE(to_send, 5) >> 1U)) - 1024U;
+ bool steer_req = GET_BIT(to_send, 52U);
if (steer_torque_cmd_checks(desired_torque, steer_req, HYUNDAI_CANFD_STEERING_LIMITS)) {
tx = false;
@@ -172,209 +575,166 @@ static bool hyundai_canfd_tx_hook(const CANPacket_t *msg) {
}
// cruise buttons check
- if (msg->addr == 0x1cfU) {
- int button = msg->data[2] & 0x7U;
+ if (addr == 0x1cf) {
+ int button = GET_BYTE(to_send, 2) & 0x7U;
bool is_cancel = (button == HYUNDAI_BTN_CANCEL);
bool is_resume = (button == HYUNDAI_BTN_RESUME);
- bool is_set = (button == HYUNDAI_BTN_SET);
- bool allowed = (is_cancel && cruise_engaged_prev) || ((is_resume || is_set) && controls_allowed);
+ bool allowed = (is_cancel && (cruise_engaged_prev || controls_allowed)) || (is_resume && controls_allowed);
if (!allowed) {
tx = false;
}
}
-
// UDS: only tester present ("\x02\x3E\x80\x00\x00\x00\x00\x00") allowed on diagnostics address
- if (((msg->addr == 0x730U) && hyundai_canfd_lka_steering) || ((msg->addr == 0x7D0U) && !hyundai_camera_scc)) {
- if ((GET_BYTES(msg, 0, 4) != 0x00803E02U) || (GET_BYTES(msg, 4, 4) != 0x0U)) {
+ if ((addr == 0x730) && hyundai_canfd_hda2) {
+ if ((GET_BYTES(to_send, 0, 4) != 0x00803E02U) || (GET_BYTES(to_send, 4, 4) != 0x0U)) {
tx = false;
}
}
// ACCEL: safety check
- if (msg->addr == 0x1a0U) {
- int desired_accel_raw = (((msg->data[17] & 0x7U) << 8) | msg->data[16]) - 1023U;
- int desired_accel_val = ((msg->data[18] << 4) | (msg->data[17] >> 4)) - 1023U;
+ if (addr == 0x1a0) {
+ int desired_accel_raw = (((GET_BYTE(to_send, 17) & 0x7U) << 8) | GET_BYTE(to_send, 16)) - 1023U;
+ int desired_accel_val = ((GET_BYTE(to_send, 18) << 4) | (GET_BYTE(to_send, 17) >> 4)) - 1023U;
- bool violation = false;
if (hyundai_longitudinal) {
violation |= longitudinal_accel_checks(desired_accel_raw, HYUNDAI_LONG_LIMITS);
violation |= longitudinal_accel_checks(desired_accel_val, HYUNDAI_LONG_LIMITS);
- } else {
+ }
+ else {
// only used to cancel on here
- const int acc_mode = (msg->data[8] >> 4) & 0x7U;
+ const int acc_mode = (GET_BYTE(to_send, 8) >> 4) & 0x7U;
if (acc_mode != 4) {
violation = true;
}
-
if ((desired_accel_raw != 0) || (desired_accel_val != 0)) {
violation = true;
}
}
-
- if (violation) {
- tx = false;
- }
-
- acc_main_on_tx = GET_BIT(msg, 66U);
- hyundai_common_acc_main_on_sync();
}
+ if (violation) {
+ tx = false;
+ }
+ else if (hyundai_canfd_buffered_fwd) {
+ CanfdBufferedFwd* bfwd = canfd_bfwd_find(addr, GET_BUS(to_send));
+ if (bfwd != NULL) {
+ canfd_bfwd_push(bfwd, to_send);
+ //tx = false;
+ return true;
+ }
+ }
+
+ canfd_record_tx_time(GET_BUS(to_send), addr, tx);
+
return tx;
}
+static bool hyundai_canfd_fwd_hook(int bus_num, int addr) {
+ uint32_t now = microsecond_timer_get();
+ if (bus_num == 0) {
+ if (canfd_should_block_fwd(2, addr, now)) {
+ return true;
+ }
+ if (addr == 0x4B9) {
+ return true;
+ }
+ return false;
+ }
+ return (bus_num != 2) || canfd_should_block_fwd(0, addr, now);
+}
+
static safety_config hyundai_canfd_init(uint16_t param) {
- const uint16_t HYUNDAI_PARAM_CANFD_LKA_STEERING_ALT = 128;
- const uint16_t HYUNDAI_PARAM_CANFD_ALT_BUTTONS = 32;
- static const CanMsg HYUNDAI_CANFD_LKA_STEERING_TX_MSGS[] = {
- HYUNDAI_CANFD_LKA_STEERING_COMMON_TX_MSGS(0, 1)
- };
+ for (int i = 0; canfd_tx_states[i].addr > 0; i++) {
+ canfd_tx_states[i].timeout_us = (uint32_t)(1000000.0 / canfd_tx_states[i].hz) + 20000U;
+ canfd_tx_states[i].last_tx_us = 0U;
+ }
- static const CanMsg HYUNDAI_CANFD_LKA_STEERING_ALT_TX_MSGS[] = {
- HYUNDAI_CANFD_LKA_STEERING_ALT_COMMON_TX_MSGS(0, 1)
- };
-
- static const CanMsg HYUNDAI_CANFD_LKA_STEERING_LONG_TX_MSGS[] = {
- HYUNDAI_CANFD_LKA_STEERING_COMMON_TX_MSGS(0, 1)
- HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(1)
- HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(1, true)
- {0x51, 0, 32, .check_relay = false}, // ADRV_0x51
- {0x730, 1, 8, .check_relay = false}, // tester present for ADAS ECU disable
- {0x160, 1, 16, .check_relay = false}, // ADRV_0x160
- {0x1EA, 1, 32, .check_relay = false}, // ADRV_0x1ea
- {0x200, 1, 8, .check_relay = false}, // ADRV_0x200
- {0x345, 1, 8, .check_relay = false}, // ADRV_0x345
- {0x1DA, 1, 32, .check_relay = false}, // ADRV_0x1da
- };
-
- static const CanMsg HYUNDAI_CANFD_LFA_STEERING_TX_MSGS[] = {
- HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(2)
- HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(0)
- HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(0, false)
- };
-
- // ADRV_0x160 is checked for radar liveness
- static const CanMsg HYUNDAI_CANFD_LFA_STEERING_LONG_TX_MSGS[] = {
- HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(2)
- HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(0)
- HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(0, true)
- {0x160, 0, 16, .check_relay = true}, // ADRV_0x160
- {0x7D0, 0, 8, .check_relay = false}, // tester present for radar ECU disable
- };
-
- // ADRV_0x160 is checked for relay malfunction
-#define HYUNDAI_CANFD_LFA_STEERING_CAMERA_SCC_TX_MSGS(longitudinal) \
- HYUNDAI_CANFD_CRUISE_BUTTON_TX_MSGS(2) \
- HYUNDAI_CANFD_LFA_STEERING_COMMON_TX_MSGS(0) \
- HYUNDAI_CANFD_SCC_CONTROL_COMMON_TX_MSGS(0, (longitudinal)) \
- {0x160, 0, 16, .check_relay = (longitudinal)}, /* ADRV_0x160 */ \
+ for (int i = 0; canfd_bfwd[i].addr > 0; i++) {
+ canfd_bfwd_reset(&canfd_bfwd[i]);
+ }
hyundai_common_init(param);
gen_crc_lookup_table_16(0x1021, hyundai_canfd_crc_lut);
hyundai_canfd_alt_buttons = GET_FLAG(param, HYUNDAI_PARAM_CANFD_ALT_BUTTONS);
- hyundai_canfd_lka_steering_alt = GET_FLAG(param, HYUNDAI_PARAM_CANFD_LKA_STEERING_ALT);
+ hyundai_canfd_hda2_alt_steering = GET_FLAG(param, HYUNDAI_PARAM_CANFD_HDA2_ALT_STEERING);
+ hyundai_canfd_buffered_fwd = hyundai_camera_scc;
+ // no long for radar-SCC HDA1 yet
+ //if (!hyundai_canfd_hda2 && !hyundai_camera_scc) {
+ // hyundai_longitudinal = false;
+ //}
safety_config ret;
if (hyundai_longitudinal) {
- if (hyundai_canfd_lka_steering) {
- static RxCheck hyundai_canfd_lka_steering_long_rx_checks[] = {
- HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(1)
- };
-
- ret = BUILD_SAFETY_CFG(hyundai_canfd_lka_steering_long_rx_checks, HYUNDAI_CANFD_LKA_STEERING_LONG_TX_MSGS);
-
+ if (hyundai_canfd_hda2) {
+ if (hyundai_canfd_alt_buttons) { // carrot : for CANIVAL 4TH HDA2
+ if (hyundai_camera_scc) ret = BUILD_SAFETY_CFG(hyundai_canfd_hda2_long_alt_buttons_rx_checks_scc2, HYUNDAI_CANFD_HDA2_LONG_TX_MSGS);
+ else ret = BUILD_SAFETY_CFG(hyundai_canfd_hda2_long_alt_buttons_rx_checks, HYUNDAI_CANFD_HDA2_LONG_TX_MSGS);
+ }
+ else {
+ if (hyundai_camera_scc) ret = BUILD_SAFETY_CFG(hyundai_canfd_hda2_long_rx_checks_scc2, HYUNDAI_CANFD_HDA2_LONG_TX_MSGS);
+ else ret = BUILD_SAFETY_CFG(hyundai_canfd_hda2_long_rx_checks, HYUNDAI_CANFD_HDA2_LONG_TX_MSGS);
+ }
} else {
- // Longitudinal checks for LFA steering
- static RxCheck hyundai_canfd_long_rx_checks[] = {
- HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(0)
- };
-
- static RxCheck hyundai_canfd_alt_buttons_long_rx_checks[] = {
- HYUNDAI_CANFD_ALT_BUTTONS_RX_CHECKS(0)
- };
-
- static CanMsg hyundai_canfd_lfa_steering_camera_scc_tx_msgs[] = {
- HYUNDAI_CANFD_LFA_STEERING_CAMERA_SCC_TX_MSGS(true)
- };
-
- if (hyundai_canfd_alt_buttons) {
- SET_RX_CHECKS(hyundai_canfd_alt_buttons_long_rx_checks, ret);
- } else {
- SET_RX_CHECKS(hyundai_canfd_long_rx_checks, ret);
- }
-
- if (hyundai_camera_scc) {
- SET_TX_MSGS(hyundai_canfd_lfa_steering_camera_scc_tx_msgs, ret);
- } else {
- SET_TX_MSGS(HYUNDAI_CANFD_LFA_STEERING_LONG_TX_MSGS, ret);
- }
+ ret = hyundai_canfd_alt_buttons ? BUILD_SAFETY_CFG(hyundai_canfd_long_alt_buttons_rx_checks, HYUNDAI_CANFD_HDA1_TX_MSGS) : \
+ BUILD_SAFETY_CFG(hyundai_canfd_long_rx_checks, HYUNDAI_CANFD_HDA1_TX_MSGS);
}
-
} else {
- if (hyundai_canfd_lka_steering) {
- // *** LKA steering checks ***
- // E-CAN is on bus 1, SCC messages are sent on cars with ADRV ECU.
- // Does not use the alt buttons message
- static RxCheck hyundai_canfd_lka_steering_rx_checks[] = {
- HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(1)
- HYUNDAI_CANFD_SCC_ADDR_CHECK(1)
+ if (hyundai_canfd_hda2 && hyundai_camera_scc) {
+ if (hyundai_canfd_alt_buttons) { // carrot : for CANIVAL 4TH HDA2
+ ret = hyundai_canfd_hda2_alt_steering ? BUILD_SAFETY_CFG(hyundai_canfd_hda2_alt_buttons_rx_checks_scc2, HYUNDAI_CANFD_HDA2_LONG_TX_MSGS) : \
+ BUILD_SAFETY_CFG(hyundai_canfd_hda2_alt_buttons_rx_checks_scc2, HYUNDAI_CANFD_HDA2_LONG_TX_MSGS);
+ }
+ else {
+ ret = hyundai_canfd_hda2_alt_steering ? BUILD_SAFETY_CFG(hyundai_canfd_hda2_rx_checks_scc2, HYUNDAI_CANFD_HDA2_LONG_TX_MSGS) : \
+ BUILD_SAFETY_CFG(hyundai_canfd_hda2_rx_checks_scc2, HYUNDAI_CANFD_HDA2_LONG_TX_MSGS);
+ }
+ }else if (hyundai_canfd_hda2) {
+ if (hyundai_canfd_alt_buttons) { // carrot : for CANIVAL 4TH HDA2
+ ret = hyundai_canfd_hda2_alt_steering ? BUILD_SAFETY_CFG(hyundai_canfd_hda2_alt_buttons_rx_checks, HYUNDAI_CANFD_HDA2_LONG_TX_MSGS) : \
+ BUILD_SAFETY_CFG(hyundai_canfd_hda2_alt_buttons_rx_checks, HYUNDAI_CANFD_HDA2_LONG_TX_MSGS);
+ }
+ else {
+ ret = hyundai_canfd_hda2_alt_steering ? BUILD_SAFETY_CFG(hyundai_canfd_hda2_rx_checks, HYUNDAI_CANFD_HDA2_LONG_TX_MSGS) : \
+ BUILD_SAFETY_CFG(hyundai_canfd_hda2_rx_checks, HYUNDAI_CANFD_HDA2_LONG_TX_MSGS);
+ }
+ } else if (!hyundai_camera_scc) {
+ static RxCheck hyundai_canfd_radar_scc_alt_buttons_rx_checks[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
+ HYUNDAI_CANFD_ALT_BUTTONS_ADDR_CHECK(0)
+ HYUNDAI_CANFD_SCC_ADDR_CHECK(0)
};
- SET_RX_CHECKS(hyundai_canfd_lka_steering_rx_checks, ret);
- if (hyundai_canfd_lka_steering_alt) {
- SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_ALT_TX_MSGS, ret);
- } else {
- SET_TX_MSGS(HYUNDAI_CANFD_LKA_STEERING_TX_MSGS, ret);
- }
-
- } else if (!hyundai_camera_scc) {
// Radar sends SCC messages on these cars instead of camera
static RxCheck hyundai_canfd_radar_scc_rx_checks[] = {
- HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(0)
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
+ HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(0)
HYUNDAI_CANFD_SCC_ADDR_CHECK(0)
};
- static RxCheck hyundai_canfd_alt_buttons_radar_scc_rx_checks[] = {
- HYUNDAI_CANFD_ALT_BUTTONS_RX_CHECKS(0)
- HYUNDAI_CANFD_SCC_ADDR_CHECK(0)
- };
-
- SET_TX_MSGS(HYUNDAI_CANFD_LFA_STEERING_TX_MSGS, ret);
-
- if (hyundai_canfd_alt_buttons) {
- SET_RX_CHECKS(hyundai_canfd_alt_buttons_radar_scc_rx_checks, ret);
- } else {
- SET_RX_CHECKS(hyundai_canfd_radar_scc_rx_checks, ret);
- }
-
+ ret = hyundai_canfd_alt_buttons ? BUILD_SAFETY_CFG(hyundai_canfd_radar_scc_alt_buttons_rx_checks, HYUNDAI_CANFD_HDA1_TX_MSGS) : \
+ BUILD_SAFETY_CFG(hyundai_canfd_radar_scc_rx_checks, HYUNDAI_CANFD_HDA1_TX_MSGS);
} else {
- // *** LFA steering checks ***
- // Camera sends SCC messages on LFA steering cars.
+ // *** Non-HDA2 checks ***
+ static RxCheck hyundai_canfd_alt_buttons_rx_checks[] = {
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
+ HYUNDAI_CANFD_ALT_BUTTONS_ADDR_CHECK(0)
+ HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
+ };
+
+ // Camera sends SCC messages on HDA1.
// Both button messages exist on some platforms, so we ensure we track the correct one using flag
static RxCheck hyundai_canfd_rx_checks[] = {
- HYUNDAI_CANFD_STD_BUTTONS_RX_CHECKS(0)
+ HYUNDAI_CANFD_COMMON_RX_CHECKS(0)
+ HYUNDAI_CANFD_BUTTONS_ADDR_CHECK(0)
HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
};
- static RxCheck hyundai_canfd_alt_buttons_rx_checks[] = {
- HYUNDAI_CANFD_ALT_BUTTONS_RX_CHECKS(0)
- HYUNDAI_CANFD_SCC_ADDR_CHECK(2)
- };
-
- static CanMsg hyundai_canfd_lfa_steering_camera_scc_tx_msgs[] = {
- HYUNDAI_CANFD_LFA_STEERING_CAMERA_SCC_TX_MSGS(false)
- };
-
- SET_TX_MSGS(hyundai_canfd_lfa_steering_camera_scc_tx_msgs, ret);
-
- if (hyundai_canfd_alt_buttons) {
- SET_RX_CHECKS(hyundai_canfd_alt_buttons_rx_checks, ret);
- } else {
- SET_RX_CHECKS(hyundai_canfd_rx_checks, ret);
- }
+ ret = hyundai_canfd_alt_buttons ? BUILD_SAFETY_CFG(hyundai_canfd_alt_buttons_rx_checks, HYUNDAI_CANFD_HDA1_TX_MSGS) : \
+ BUILD_SAFETY_CFG(hyundai_canfd_rx_checks, HYUNDAI_CANFD_HDA1_TX_MSGS);
}
}
@@ -385,6 +745,7 @@ const safety_hooks hyundai_canfd_hooks = {
.init = hyundai_canfd_init,
.rx = hyundai_canfd_rx_hook,
.tx = hyundai_canfd_tx_hook,
+ .fwd = hyundai_canfd_fwd_hook,
.get_counter = hyundai_canfd_get_counter,
.get_checksum = hyundai_canfd_get_checksum,
.compute_checksum = hyundai_common_canfd_compute_checksum,
diff --git a/iqdbc_repo/iqdbc/safety/modes/hyundai_common.h b/iqdbc_repo/iqdbc/safety/modes/hyundai_common.h
index 36253f3..2cbb2c8 100644
--- a/iqdbc_repo/iqdbc/safety/modes/hyundai_common.h
+++ b/iqdbc_repo/iqdbc/safety/modes/hyundai_common.h
@@ -2,11 +2,20 @@
#include "iqdbc/safety/declarations.h"
+#define GET_ADDR(msg) ((msg)->addr)
+#define GET_BUS(msg) ((msg)->bus)
+#define GET_BYTE(msg, b) ((msg)->data[(b)])
+
+static int cruise_main_prev = 0;
+
+static void generic_rx_checks(void);
+static void stock_ecu_check(bool stock_ecu_detected);
+
extern uint16_t hyundai_canfd_crc_lut[256];
uint16_t hyundai_canfd_crc_lut[256];
static const uint8_t HYUNDAI_PREV_BUTTON_SAMPLES = 8; // roughly 160 ms
-
+ //
extern const uint32_t HYUNDAI_STANDSTILL_THRSLD;
const uint32_t HYUNDAI_STANDSTILL_THRSLD = 12; // 0.375 kph
@@ -17,13 +26,6 @@ enum {
HYUNDAI_BTN_CANCEL = 4,
};
-enum {
- HYUNDAI_PARAM_IQ_ESCC = 1,
- HYUNDAI_PARAM_IQ_LONGITUDINAL_MAIN_CRUISE_TOGGLEABLE = 2,
- HYUNDAI_PARAM_IQ_HAS_LDA_BUTTON = 4,
- HYUNDAI_PARAM_IQ_NON_SCC = 8,
-};
-
// common state
extern bool hyundai_ev_gas_signal;
bool hyundai_ev_gas_signal = false;
@@ -37,8 +39,8 @@ bool hyundai_longitudinal = false;
extern bool hyundai_camera_scc;
bool hyundai_camera_scc = false;
-extern bool hyundai_canfd_lka_steering;
-bool hyundai_canfd_lka_steering = false;
+extern bool hyundai_canfd_hda2;
+bool hyundai_canfd_hda2 = false;
extern bool hyundai_alt_limits;
bool hyundai_alt_limits = false;
@@ -49,57 +51,29 @@ bool hyundai_fcev_gas_signal = false;
extern bool hyundai_alt_limits_2;
bool hyundai_alt_limits_2 = false;
-// ESCC
-extern bool hyundai_escc;
-bool hyundai_escc = false;
-
-extern bool hyundai_longitudinal_main_cruise_toggleable;
-bool hyundai_longitudinal_main_cruise_toggleable = false;
-
-extern bool hyundai_has_lda_button;
-bool hyundai_has_lda_button = false;
-
-extern bool hyundai_non_scc;
-bool hyundai_non_scc = false;
-
static uint8_t hyundai_last_button_interaction; // button messages since the user pressed an enable button
-static bool main_button_prev;
-static bool acc_main_on_prev;
-static bool acc_main_on_tx;
-static uint32_t acc_main_on_mismatches;
-
void hyundai_common_init(uint16_t param) {
- const uint16_t HYUNDAI_PARAM_EV_GAS = 1;
- const uint16_t HYUNDAI_PARAM_HYBRID_GAS = 2;
- const uint16_t HYUNDAI_PARAM_CAMERA_SCC = 8;
- const uint16_t HYUNDAI_PARAM_CANFD_LKA_STEERING = 16;
- const uint16_t HYUNDAI_PARAM_ALT_LIMITS = 64; // TODO: shift this down with the rest of the common flags
- const uint16_t HYUNDAI_PARAM_FCEV_GAS = 256;
- const uint16_t HYUNDAI_PARAM_ALT_LIMITS_2 = 512;
+ const int HYUNDAI_PARAM_EV_GAS = 1;
+ const int HYUNDAI_PARAM_HYBRID_GAS = 2;
+ const int HYUNDAI_PARAM_CAMERA_SCC = 8;
+ const int HYUNDAI_PARAM_CANFD_HDA2 = 16;
+ const int HYUNDAI_PARAM_ALT_LIMITS = 64; // TODO: shift this down with the rest of the common flags
+ const int HYUNDAI_PARAM_FCEV_GAS = 256;
+ const int HYUNDAI_PARAM_ALT_LIMITS_2 = 512;
hyundai_ev_gas_signal = GET_FLAG(param, HYUNDAI_PARAM_EV_GAS);
hyundai_hybrid_gas_signal = !hyundai_ev_gas_signal && GET_FLAG(param, HYUNDAI_PARAM_HYBRID_GAS);
hyundai_camera_scc = GET_FLAG(param, HYUNDAI_PARAM_CAMERA_SCC);
- hyundai_canfd_lka_steering = GET_FLAG(param, HYUNDAI_PARAM_CANFD_LKA_STEERING);
+ hyundai_canfd_hda2 = GET_FLAG(param, HYUNDAI_PARAM_CANFD_HDA2);
hyundai_alt_limits = GET_FLAG(param, HYUNDAI_PARAM_ALT_LIMITS);
hyundai_fcev_gas_signal = GET_FLAG(param, HYUNDAI_PARAM_FCEV_GAS);
hyundai_alt_limits_2 = GET_FLAG(param, HYUNDAI_PARAM_ALT_LIMITS_2);
- hyundai_escc = GET_FLAG(current_safety_param_iq, HYUNDAI_PARAM_IQ_ESCC);
- hyundai_longitudinal_main_cruise_toggleable = GET_FLAG(current_safety_param_iq, HYUNDAI_PARAM_IQ_LONGITUDINAL_MAIN_CRUISE_TOGGLEABLE);
- hyundai_has_lda_button = GET_FLAG(current_safety_param_iq, HYUNDAI_PARAM_IQ_HAS_LDA_BUTTON);
- hyundai_non_scc = GET_FLAG(current_safety_param_iq, HYUNDAI_PARAM_IQ_NON_SCC);
-
hyundai_last_button_interaction = HYUNDAI_PREV_BUTTON_SAMPLES;
- main_button_prev = false;
- acc_main_on_prev = false;
- acc_main_on_tx = false;
- acc_main_on_mismatches = 0U;
-
#ifdef ALLOW_DEBUG
- const uint16_t HYUNDAI_PARAM_LONGITUDINAL = 4;
+ const int HYUNDAI_PARAM_LONGITUDINAL = 4;
hyundai_longitudinal = GET_FLAG(param, HYUNDAI_PARAM_LONGITUDINAL);
#else
hyundai_longitudinal = false;
@@ -112,19 +86,27 @@ void hyundai_common_cruise_state_check(const bool cruise_engaged) {
// enter controls on rising edge of ACC and recent user button press, exit controls when ACC off
if (!hyundai_longitudinal) {
- if (cruise_engaged && !cruise_engaged_prev && (hyundai_last_button_interaction < HYUNDAI_PREV_BUTTON_SAMPLES)) {
+ hyundai_last_button_interaction = 0U; // carrot
+ //if (cruise_engaged && !cruise_engaged_prev && (hyundai_last_button_interaction < HYUNDAI_PREV_BUTTON_SAMPLES)) {
+ if (cruise_engaged) {
controls_allowed = true;
}
if (!cruise_engaged) {
controls_allowed = false;
+
}
cruise_engaged_prev = cruise_engaged;
}
}
void hyundai_common_cruise_buttons_check(const int cruise_button, const bool main_button) {
- if ((cruise_button == HYUNDAI_BTN_RESUME) || (cruise_button == HYUNDAI_BTN_SET) || (cruise_button == HYUNDAI_BTN_CANCEL) || main_button) {
+ if(main_button && main_button != cruise_main_prev) {
+ acc_main_on = !acc_main_on;
+ }
+ cruise_main_prev = main_button;
+ if ((cruise_button == HYUNDAI_BTN_RESUME) || (cruise_button == HYUNDAI_BTN_SET) || (cruise_button == HYUNDAI_BTN_CANCEL) ||
+ (main_button)) {
hyundai_last_button_interaction = 0U;
} else {
hyundai_last_button_interaction = SAFETY_MIN(hyundai_last_button_interaction + 1U, HYUNDAI_PREV_BUTTON_SAMPLES);
@@ -141,66 +123,38 @@ void hyundai_common_cruise_buttons_check(const int cruise_button, const bool mai
// exit controls on cancel press
if (cruise_button == HYUNDAI_BTN_CANCEL) {
controls_allowed = false;
- }
- // toggle main cruise state on rising edge of main cruise button
- if (main_button && !main_button_prev && hyundai_longitudinal_main_cruise_toggleable) {
- acc_main_on = !acc_main_on;
}
cruise_button_prev = cruise_button;
- main_button_prev = main_button;
}
}
-uint32_t hyundai_common_canfd_compute_checksum(const CANPacket_t *msg) {
- int len = GET_LEN(msg);
- uint32_t address = msg->addr;
+uint32_t hyundai_common_canfd_compute_checksum(const CANPacket_t *to_push) {
+ int len = GET_LEN(to_push);
+ uint32_t address = GET_ADDR(to_push);
uint16_t crc = 0;
for (int i = 2; i < len; i++) {
- crc = (crc << 8U) ^ hyundai_canfd_crc_lut[(crc >> 8U) ^ msg->data[i]];
+ crc = (crc << 8U) ^ hyundai_canfd_crc_lut[(crc >> 8U) ^ GET_BYTE(to_push, i)];
}
- // Add address to crc
crc = (crc << 8U) ^ hyundai_canfd_crc_lut[(crc >> 8U) ^ ((address >> 0U) & 0xFFU)];
crc = (crc << 8U) ^ hyundai_canfd_crc_lut[(crc >> 8U) ^ ((address >> 8U) & 0xFFU)];
- if (len == 24) {
+ if (len == 8) {
+ crc ^= 0x5f29U;
+ }
+ else if (len == 16) {
+ crc ^= 0x041dU;
+ }
+ else if (len == 24) {
crc ^= 0x819dU;
- } else if (len == 32) {
+ }
+ else if (len == 32) {
crc ^= 0x9f5bU;
- } else {
-
}
return crc;
}
-
-// reset mismatches on rising edge of acc_main_on to avoid rare race conditions when using non-PCM main cruise state
-void hyundai_common_reset_acc_main_on_mismatches(void) {
- if (acc_main_on && !acc_main_on_prev) {
- acc_main_on_mismatches = 0U;
- }
-
- acc_main_on_prev = acc_main_on;
-}
-
-// exit lateral controls allowed if iqpilot and panda main cruise states are desynced
-void hyundai_common_acc_main_on_sync(void) {
- if (acc_main_on && !acc_main_on_tx) {
- acc_main_on_mismatches += 1U;
-
- if (acc_main_on_mismatches >= 3U) { // desync by 3 frames
- acc_main_on = false;
- aol_exit_controls(AOL_DISENGAGE_REASON_NON_PCM_ACC_MAIN_DESYNC);
- }
- } else {
- acc_main_on_mismatches = 0U;
- }
-}
-
-uint32_t get_acc_main_on_mismatches(void) {
- return acc_main_on_mismatches;
-}
diff --git a/iqdbc_repo/iqdbc/safety/modes/tesla.h b/iqdbc_repo/iqdbc/safety/modes/tesla.h
index 11db0ae..38d7d90 100644
--- a/iqdbc_repo/iqdbc/safety/modes/tesla.h
+++ b/iqdbc_repo/iqdbc/safety/modes/tesla.h
@@ -17,7 +17,7 @@
{.msg = {{0x3DF, 1, 8, 2U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, /* UI_status2 */ \
static bool tesla_longitudinal = false;
-static bool tesla_fsd_14 = false;
+static bool tesla_legacy_das_steering = false;
static bool tesla_stock_aeb = false;
// Only rising edges while controls are not allowed are considered for these systems:
@@ -50,6 +50,9 @@ static uint8_t tesla_get_counter(const CANPacket_t *msg) {
} else if (msg->addr == 0x370U) {
// Signal: EPAS3S_sysStatusCounter
cnt = msg->data[6] & 0x0FU;
+ } else if (msg->addr == 0x3E9U) {
+ // Signal: DAS_bodyControlsCounter
+ cnt = msg->data[6] >> 4;
} else {
}
return cnt;
@@ -57,8 +60,8 @@ static uint8_t tesla_get_counter(const CANPacket_t *msg) {
static int _tesla_get_checksum_byte(const int addr) {
int checksum_byte = -1;
- if ((addr == 0x370) || (addr == 0x2b9) || (addr == 0x155)) {
- // Signal: EPAS3S_sysStatusChecksum, DAS_controlChecksum, ESP_wheelRotationChecksum
+ if ((addr == 0x370) || (addr == 0x2b9) || (addr == 0x155) || (addr == 0x3E9)) {
+ // Signal: EPAS3S_sysStatusChecksum, DAS_controlChecksum, ESP_wheelRotationChecksum, DAS_bodyControlsChecksum
checksum_byte = 7;
} else if (addr == 0x488) {
// Signal: DAS_steeringControlChecksum
@@ -109,18 +112,9 @@ static bool tesla_get_quality_flag_valid(const CANPacket_t *msg) {
return valid;
}
-static int tesla_get_steer_ctrl_type(const int ctrl_type) {
- // Returns ANGLE_CONTROL-equivalent control type for FSD 14
- int steer_ctrl_type = ctrl_type;
- if (tesla_fsd_14) {
- if (ctrl_type == 1) {
- steer_ctrl_type = 2;
- } else if (ctrl_type == 2) {
- steer_ctrl_type = 1;
- } else {
- }
- }
- return steer_ctrl_type;
+static int tesla_get_steer_ctrl_type(const uint8_t byte2) {
+ // Older Tesla firmware used a 2-bit field (now 3-bit) for DAS_steeringControlType
+ return tesla_legacy_das_steering ? (byte2 >> 6) : ((byte2 >> 5) & 0x07U);
}
static void tesla_rx_hook(const CANPacket_t *msg) {
@@ -263,19 +257,17 @@ static bool tesla_tx_hook(const CANPacket_t *msg) {
// We use 1/10 deg as a unit here
int raw_angle_can = ((msg->data[0] & 0x7FU) << 8) | msg->data[1];
int desired_angle = raw_angle_can - 16384;
- int steer_control_type = msg->data[2] >> 6;
- const int angle_ctrl_type = tesla_get_steer_ctrl_type(1);
- const int lkas_ctrl_type = tesla_get_steer_ctrl_type(2);
- bool steer_control_enabled = (steer_control_type == angle_ctrl_type) || // ANGLE_CONTROL
- (steer_control_type == lkas_ctrl_type); // LANE_KEEP_ASSIST
+ int steer_control_type = tesla_get_steer_ctrl_type(msg->data[2]);
+ bool steer_control_enabled = (steer_control_type == 1) || // ANGLE_CONTROL
+ (steer_control_type == 2); // LANE_KEEP_ASSIST
if (steer_angle_cmd_checks_vm(desired_angle, steer_control_enabled, TESLA_STEERING_LIMITS, TESLA_STEERING_PARAMS)) {
violation = true;
}
- bool valid_steer_control_type = (steer_control_type == 0) || // NONE
- (steer_control_type == angle_ctrl_type) || // ANGLE_CONTROL
- (steer_control_type == lkas_ctrl_type); // LANE_KEEP_ASSIST
+ bool valid_steer_control_type = (steer_control_type == 0) || // NONE
+ (steer_control_type == 1) || // ANGLE_CONTROL
+ (steer_control_type == 2); // LANE_KEEP_ASSIST
if (!valid_steer_control_type) {
violation = true;
}
@@ -325,6 +317,11 @@ static bool tesla_tx_hook(const CANPacket_t *msg) {
}
}
+ // DAS_bodyControls (blinker MITM on vehicle bus) is body control only, not motion
+ // actuation. openpilot copies the stock frame verbatim and only flips the turn-indicator
+ // bits, so we don't value-check it here — rejecting a frame would break the counter
+ // sequence the body controller validates. The TX whitelist still gates the address/bus.
+
if (violation) {
tx = false;
}
@@ -351,9 +348,11 @@ static bool tesla_fwd_hook(int bus_num, int addr) {
if (tesla_longitudinal && (addr == 0x2b9) && !tesla_stock_aeb) {
block_msg = true;
}
+
}
}
+
return block_msg;
}
@@ -371,8 +370,23 @@ static safety_config tesla_init(uint16_t param) {
{0x27D, 0, 3, .check_relay = true, .disable_static_blocking = true}, // APS_eacMonitor
};
- const uint16_t TESLA_FLAG_FSD_14 = 2;
- tesla_fsd_14 = GET_FLAG(param, TESLA_FLAG_FSD_14);
+ // With vehicle bus harness: adds DAS_bodyControls on bus 1 for blinker control
+ static const CanMsg TESLA_VEHICLE_BUS_TX_MSGS[] = {
+ {0x488, 0, 4, .check_relay = true, .disable_static_blocking = true}, // DAS_steeringControl
+ {0x2b9, 0, 8, .check_relay = false}, // DAS_control (for cancel)
+ {0x27D, 0, 3, .check_relay = true, .disable_static_blocking = true}, // APS_eacMonitor
+ {0x3E9, 1, 8, .check_relay = false}, // DAS_bodyControls (blinker)
+ };
+
+ static const CanMsg TESLA_VEHICLE_BUS_LONG_TX_MSGS[] = {
+ {0x488, 0, 4, .check_relay = true, .disable_static_blocking = true}, // DAS_steeringControl
+ {0x2b9, 0, 8, .check_relay = true, .disable_static_blocking = true}, // DAS_control
+ {0x27D, 0, 3, .check_relay = true, .disable_static_blocking = true}, // APS_eacMonitor
+ {0x3E9, 1, 8, .check_relay = false}, // DAS_bodyControls (blinker)
+ };
+
+ const uint16_t TESLA_FLAG_LEGACY_DAS_STEERING = 2;
+ tesla_legacy_das_steering = GET_FLAG(param, TESLA_FLAG_LEGACY_DAS_STEERING);
#ifdef ALLOW_DEBUG
const uint16_t TESLA_FLAG_LONGITUDINAL_CONTROL = 1;
@@ -401,7 +415,11 @@ static safety_config tesla_init(uint16_t param) {
};
safety_config ret;
- if (tesla_longitudinal) {
+ if (tesla_has_vehicle_bus && tesla_longitudinal) {
+ SET_TX_MSGS(TESLA_VEHICLE_BUS_LONG_TX_MSGS, ret);
+ } else if (tesla_has_vehicle_bus) {
+ SET_TX_MSGS(TESLA_VEHICLE_BUS_TX_MSGS, ret);
+ } else if (tesla_longitudinal) {
SET_TX_MSGS(TESLA_M3_Y_LONG_TX_MSGS, ret);
} else {
SET_TX_MSGS(TESLA_M3_Y_TX_MSGS, ret);
diff --git a/iqdbc_repo/iqdbc/safety/modes/toyota.h b/iqdbc_repo/iqdbc/safety/modes/toyota.h
index 0bbc9f8..ddf69fe 100644
--- a/iqdbc_repo/iqdbc/safety/modes/toyota.h
+++ b/iqdbc_repo/iqdbc/safety/modes/toyota.h
@@ -375,11 +375,15 @@ static bool toyota_tx_hook(const CANPacket_t *msg) {
}
}
- // UDS: Only tester present ("\x0F\x02\x3E\x00\x00\x00\x00\x00") allowed on diagnostics address
+ // UDS: Only tester present and door lock/unlock allowed on diagnostics address
if (msg->addr == 0x750U) {
// this address is sub-addressed. only allow tester present to radar (0xF)
- bool invalid_uds_msg = (GET_BYTES(msg, 0, 4) != 0x003E020FU) || (GET_BYTES(msg, 4, 4) != 0x0U);
- if (invalid_uds_msg) {
+ bool valid_tester_present = (GET_BYTES(msg, 0, 4) == 0x003E020FU) && (GET_BYTES(msg, 4, 4) == 0x0U);
+ // BCM door lock/unlock routine (0x40=BCM sub-addr, 0x05=len, 0x30 0x11=routine ID)
+ // Byte 5: 0x80=lock, 0x40=unlock. Only these two values allowed.
+ bool valid_door_lock = (GET_BYTES(msg, 0, 4) == 0x11300540U) &&
+ ((GET_BYTES(msg, 5, 1) == 0x80U) || (GET_BYTES(msg, 5, 1) == 0x40U));
+ if (!valid_tester_present && !valid_door_lock) {
tx = 0;
}
}
diff --git a/iqdbc_repo/iqdbc/safety/modes/volkswagen_common.h b/iqdbc_repo/iqdbc/safety/modes/volkswagen_common.h
index b1e8f44..f2a5ac7 100644
--- a/iqdbc_repo/iqdbc/safety/modes/volkswagen_common.h
+++ b/iqdbc_repo/iqdbc/safety/modes/volkswagen_common.h
@@ -10,6 +10,14 @@ extern const uint16_t FLAG_VOLKSWAGEN_ALLOW_LONG_ACCEL_WITH_GAS_PRESSED;
const uint16_t FLAG_VOLKSWAGEN_ALLOW_LONG_ACCEL_WITH_GAS_PRESSED = 8;
extern const uint16_t FLAG_VOLKSWAGEN_PQ_ALC_MODULE;
const uint16_t FLAG_VOLKSWAGEN_PQ_ALC_MODULE = 32;
+extern const uint16_t FLAG_VOLKSWAGEN_PQ_LOWLINE;
+const uint16_t FLAG_VOLKSWAGEN_PQ_LOWLINE = 64;
+extern const uint16_t FLAG_VOLKSWAGEN_PQ_NO_CAM_BUS;
+const uint16_t FLAG_VOLKSWAGEN_PQ_NO_CAM_BUS = 128;
+extern const uint16_t FLAG_VOLKSWAGEN_PQ_ACC_FTS_EPB;
+const uint16_t FLAG_VOLKSWAGEN_PQ_ACC_FTS_EPB = 256;
+extern const uint16_t FLAG_VOLKSWAGEN_PQ_SNG_ECD;
+const uint16_t FLAG_VOLKSWAGEN_PQ_SNG_ECD = 512;
static uint8_t volkswagen_crc8_lut_8h2f[256]; // Static lookup table for CRC8 poly 0x2F, aka 8H2F/AUTOSAR
@@ -55,6 +63,9 @@ float vw_iq_measured_angle_deg = 0.0f;
extern bool vw_iq_aol_active;
bool vw_iq_aol_active = false;
+extern bool vw_iq_no_cam;
+bool vw_iq_no_cam = false;
+
extern float vw_iq_angle_offset_deg;
float vw_iq_angle_offset_deg = 0.0f;
@@ -103,6 +114,7 @@ static void volkswagen_common_init(void) {
vw_iq_apd_wheelbase = 0.0f;
vw_iq_apd_params_valid = false;
vw_iq_aol_active = false;
+ vw_iq_no_cam = false;
vw_iq_angle_offset_deg = 0.0f;
vw_iq_alc_desired_angle_deg = 0.0f;
vw_iq_alc_active = false;
@@ -214,7 +226,7 @@ static void volkswagen_iq_send_debug_la(uint32_t debug_addr, uint8_t bus) {
float speed_kmh = ((float)(vehicle_speed.min) / VEHICLE_SPEED_FACTOR) * 3.6f;
uint16_t spd_raw = (uint16_t)(speed_kmh * 100.0f);
int16_t ang_raw = (int16_t)(vw_iq_measured_angle_deg * 100.0f);
- uint8_t flags = (vw_iq_apd_params_valid ? 0x01U : 0x00U);
+ uint8_t flags = (vw_iq_apd_params_valid ? 0x01U : 0x00U) | (vw_iq_aol_active ? 0x02U : 0x00U) | (vw_iq_no_cam ? 0x04U : 0x00U);
msg.data[0] = (uint8_t)(la_raw & 0xFFU);
msg.data[1] = (uint8_t)((la_raw >> 8) & 0xFFU);
diff --git a/iqdbc_repo/iqdbc/safety/modes/volkswagen_meb.h b/iqdbc_repo/iqdbc/safety/modes/volkswagen_meb.h
index a88d6d3..daac23f 100644
--- a/iqdbc_repo/iqdbc/safety/modes/volkswagen_meb.h
+++ b/iqdbc_repo/iqdbc/safety/modes/volkswagen_meb.h
@@ -236,6 +236,16 @@ static void volkswagen_meb_rx_hook(const CANPacket_t *msg) {
}
}
+// Lateral limits for curvature-based steering (HCA_03)
+// max_power matches 50% (~125/255) of the byte range, safely above Python's STEERING_POWER_MAX of 90
+static const CurvatureSteeringLimits VOLKSWAGEN_MEB_STEERING_LIMITS = {
+ .max_curvature = 29105, // 0.195 rad/m
+ .curvature_to_can = 149253.7313f, // 1 / 6.7e-6 rad/m to CAN units
+ .send_rate = 0.02f,
+ .inactive_curvature_is_zero = true,
+ .max_power = 125, // ~50% of byte range; Python STEERING_POWER_MAX is 90
+};
+
static bool volkswagen_meb_tx_hook(const CANPacket_t *msg) {
const LongitudinalLimits VOLKSWAGEN_MEB_LONG_LIMITS = {
.max_accel = 2000,
@@ -243,14 +253,6 @@ static bool volkswagen_meb_tx_hook(const CANPacket_t *msg) {
.inactive_accel = 3010,
};
- const CurvatureSteeringLimits VOLKSWAGEN_MEB_STEERING_LIMITS = {
- .max_curvature = 29105,
- .curvature_to_can = 149253.7313f,
- .send_rate = 0.02f,
- .inactive_curvature_is_zero = true,
- .max_power = 225, // 90% (raw byte, 0.4 %/bit; matches Python STEERING_POWER_MAX = 90)
- };
-
bool tx = true;
if (msg->addr == MSG_HCA_03) {
diff --git a/iqdbc_repo/iqdbc/safety/modes/volkswagen_pq.h b/iqdbc_repo/iqdbc/safety/modes/volkswagen_pq.h
index f0d7ab3..ab733db 100644
--- a/iqdbc_repo/iqdbc/safety/modes/volkswagen_pq.h
+++ b/iqdbc_repo/iqdbc/safety/modes/volkswagen_pq.h
@@ -6,6 +6,7 @@
#define MSG_LENKHILFE_3 0x0D0U // RX from EPS, for steering angle and driver steering torque
#define MSG_HCA_1 0x0D2U // TX by OP, Heading Control Assist steering torque
#define MSG_BREMSE_1 0x1A0U // RX from ABS, for ego speed
+#define MSG_MOTOR_3 0x380U // RX from ECU
#define MSG_MOTOR_2 0x288U // RX from ECU, for CC state and brake switch state
#define MSG_ACC_SYSTEM 0x368U // TX by OP, longitudinal acceleration controls
#define MSG_MOTOR_3 0x380U // RX from ECU, for driver throttle input
@@ -15,10 +16,16 @@
#define MSG_LDW_1 0x5BEU // TX by OP, Lane line recognition and text alerts
#define MSG_BLINKMODI_02 0x0AAU // TX by OP, Blinker control
#define MSG_APD_1 0x3D6U // TX by OP, CarParams
+#define MSG_SNG_1 0x3D7U // TX by OP
#define MSG_PQ_SAFETY_1 0x6A0U // RX by OP
+#define MSG_PQ_DEBUG_LA 0x6A1U // TX by panda, internal safety state debug
+#define MSG_IQ 0x6A1U // TX by OP
static bool volkswagen_pq_alc_module_present = false;
static bool volkswagen_pq_acc_tsk_ready = false;
+static bool volkswagen_pq_lowline = false;
+static bool volkswagen_pq_acc_fts_epb = false;
+static bool volkswagen_pq_sng_ecd = false;
static uint32_t volkswagen_pq_get_checksum(const CANPacket_t *msg) {
return (uint32_t)msg->data[(msg->addr == MSG_MOTOR_5) ? 7 : 0];
@@ -57,26 +64,39 @@ static safety_config volkswagen_pq_init(uint16_t param) {
static const CanMsg VOLKSWAGEN_PQ_STOCK_TX_MSGS[] = {{MSG_HCA_1, 0, 5, .check_relay = true}, {MSG_LDW_1, 0, 8, .check_relay = true},
{MSG_GRA_NEU, 0, 4, .check_relay = false}, {MSG_GRA_NEU, 1, 4, .check_relay = false},
{MSG_GRA_NEU, 2, 4, .check_relay = false}, {MSG_BLINKMODI_02, 0, 8, .check_relay = false},
- {MSG_APD_1, 1, 8, .check_relay = false}};
+ {MSG_APD_1, 1, 8, .check_relay = false}, {MSG_IQ, 1, 8, .check_relay = false}};
+
+ // Lowline (non-ECAN) lateral-only cars: ptCAN (bus 1) is the only active bus, no J533 gateway.
+ // HCA_1 and lateral messages go directly on bus 1 to the EPS. GRA_Neu bus 0 dropped (dead).
+ static const CanMsg VOLKSWAGEN_PQ_STOCK_TX_MSGS_BUS1[] = {{MSG_HCA_1, 1, 5, .check_relay = true}, {MSG_LDW_1, 1, 8, .check_relay = true},
+ {MSG_GRA_NEU, 1, 4, .check_relay = false}, {MSG_GRA_NEU, 2, 4, .check_relay = false},
+ {MSG_BLINKMODI_02, 1, 8, .check_relay = false},
+ {MSG_APD_1, 1, 8, .check_relay = false}, {MSG_IQ, 1, 8, .check_relay = false}};
static const CanMsg VOLKSWAGEN_PQ_LONG_TX_MSGS[] = {{MSG_HCA_1, 0, 5, .check_relay = true}, {MSG_LDW_1, 0, 8, .check_relay = true},
{MSG_ACC_SYSTEM, 0, 8, .check_relay = true}, {MSG_ACC_GRA_ANZEIGE, 0, 8, .check_relay = true},
{MSG_GRA_NEU, 1, 4, .check_relay = false}, {MSG_GRA_NEU, 2, 4, .check_relay = true},
{MSG_BLINKMODI_02, 0, 8, .check_relay = false}, {MSG_MOTOR_2, 2, 8, .check_relay = true},
- {MSG_APD_1, 1, 8, .check_relay = false}};
+ {MSG_MOTOR_5, 2, 8, .check_relay = true}, {MSG_MOTOR_3, 1, 8, .check_relay = false},
+ {MSG_APD_1, 1, 8, .check_relay = false}, {MSG_IQ, 1, 8, .check_relay = false},
+ {MSG_SNG_1, 1, 8, .check_relay = false}};
static RxCheck volkswagen_pq_rx_checks[] = {
- {.msg = {{MSG_LENKHILFE_3, 0, 6, 100U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
- {.msg = {{MSG_BREMSE_1, 0, 8, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
- {.msg = {{MSG_MOTOR_2, 0, 8, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
- {.msg = {{MSG_MOTOR_3, 0, 8, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
- {.msg = {{MSG_MOTOR_5, 0, 8, 50U, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
- {.msg = {{MSG_GRA_NEU, 0, 4, 30U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
+ {.msg = {{MSG_LENKHILFE_3, 1, 6, 100U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
+ {.msg = {{MSG_BREMSE_1, 1, 8, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
+ {.msg = {{MSG_MOTOR_2, 1, 8, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
+ {.msg = {{MSG_MOTOR_3, 1, 8, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
+ {.msg = {{MSG_MOTOR_5, 1, 8, 50U, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
+ {.msg = {{MSG_GRA_NEU, 1, 4, 30U, .max_counter = 15U, .ignore_quality_flag = true}, { 0 }, { 0 }}},
{.msg = {{MSG_PQ_SAFETY_1, 1, 8, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}},
};
volkswagen_common_init();
volkswagen_pq_alc_module_present = GET_FLAG(param, FLAG_VOLKSWAGEN_PQ_ALC_MODULE);
+ volkswagen_pq_lowline = GET_FLAG(param, FLAG_VOLKSWAGEN_PQ_LOWLINE);
+ vw_iq_no_cam = GET_FLAG(param, FLAG_VOLKSWAGEN_PQ_NO_CAM_BUS);
+ volkswagen_pq_acc_fts_epb = GET_FLAG(param, FLAG_VOLKSWAGEN_PQ_ACC_FTS_EPB);
+ volkswagen_pq_sng_ecd = GET_FLAG(param, FLAG_VOLKSWAGEN_PQ_SNG_ECD);
volkswagen_pq_acc_tsk_ready = false;
#ifdef ALLOW_DEBUG
@@ -86,7 +106,8 @@ static safety_config volkswagen_pq_init(uint16_t param) {
SAFETY_UNUSED(param);
#endif
safety_config ret = volkswagen_longitudinal ? BUILD_SAFETY_CFG(volkswagen_pq_rx_checks, VOLKSWAGEN_PQ_LONG_TX_MSGS) : \
- BUILD_SAFETY_CFG(volkswagen_pq_rx_checks, VOLKSWAGEN_PQ_STOCK_TX_MSGS);
+ volkswagen_pq_lowline ? BUILD_SAFETY_CFG(volkswagen_pq_rx_checks, VOLKSWAGEN_PQ_STOCK_TX_MSGS_BUS1) : \
+ BUILD_SAFETY_CFG(volkswagen_pq_rx_checks, VOLKSWAGEN_PQ_STOCK_TX_MSGS);
if (!volkswagen_pq_alc_module_present) {
ret.rx_checks_len -= 1;
}
@@ -94,7 +115,9 @@ static safety_config volkswagen_pq_init(uint16_t param) {
}
static void volkswagen_pq_rx_hook(const CANPacket_t *msg) {
- if (msg->bus == 0U) {
+ // All PQ RX processing is on bus 1 (ptCAN). Messages exist on both bus 0 and bus 1 for ECAN
+ // gateway cars; on lowline non-ECAN cars bus 1 is the only active bus.
+ if (msg->bus == 1U) {
// Update in-motion state from speed value.
// Signal: Bremse_1.BR1_Rad_kmh
if (msg->addr == MSG_BREMSE_1) {
@@ -119,9 +142,14 @@ static void volkswagen_pq_rx_hook(const CANPacket_t *msg) {
vw_iq_measured_angle_deg = angle_sign ? -angle_deg : angle_deg;
}
+ // acc_main_on tracked unconditionally so main-switch disengagement works for both long
+ // and lateral-only (pcmCruise) configurations.
+ if (msg->addr == MSG_MOTOR_5) {
+ acc_main_on = GET_BIT(msg, 50U);
+ }
+
if (volkswagen_longitudinal) {
if (msg->addr == MSG_MOTOR_5) {
- acc_main_on = GET_BIT(msg, 50U);
if (!acc_main_on && !volkswagen_pq_acc_tsk_ready) {
controls_allowed = false;
}
@@ -161,8 +189,7 @@ static void volkswagen_pq_rx_hook(const CANPacket_t *msg) {
if (msg->addr == MSG_MOTOR_2) {
brake_pressed = (msg->data[2] & 0x1U);
}
- }
- if (msg->bus == 1U) {
+
if (volkswagen_pq_alc_module_present && (msg->addr == MSG_PQ_SAFETY_1)) {
const uint16_t desired_angle_raw = (uint16_t)msg->data[6] | (((uint16_t)msg->data[7] & 0x7FU) << 8);
const bool desired_angle_sign = (msg->data[7] & 0x80U) != 0U;
@@ -180,6 +207,7 @@ static bool volkswagen_pq_tx_hook(const CANPacket_t *msg) {
}
if (msg->addr == MSG_HCA_1) {
+ volkswagen_iq_send_debug_la(MSG_PQ_DEBUG_LA, 1U);
const uint8_t hca_status = (msg->data[1] >> 4) & 0x0FU;
if (volkswagen_pq_alc_module_present && (hca_status == 8U)) {
@@ -214,13 +242,31 @@ static bool volkswagen_pq_tx_hook(const CANPacket_t *msg) {
}
}
+ if (msg->addr == MSG_MOTOR_3) {
+ if (!volkswagen_pq_acc_fts_epb) {
+ tx = false;
+ }
+ }
+
+ if (msg->addr == MSG_SNG_1) {
+ if (!volkswagen_pq_sng_ecd) {
+ tx = false;
+ }
+ }
+
return tx;
}
+static bool volkswagen_pq_fwd_hook(int bus_num, int addr) {
+ SAFETY_UNUSED(addr);
+ return vw_iq_no_cam && (bus_num == 0);
+}
+
const safety_hooks volkswagen_pq_hooks = {
.init = volkswagen_pq_init,
.rx = volkswagen_pq_rx_hook,
.tx = volkswagen_pq_tx_hook,
+ .fwd = volkswagen_pq_fwd_hook,
.get_counter = volkswagen_pq_get_counter,
.get_checksum = volkswagen_pq_get_checksum,
.compute_checksum = volkswagen_pq_compute_checksum,
diff --git a/iqdbc_repo/iqdbc/safety/tests/hyundai_common.py b/iqdbc_repo/iqdbc/safety/tests/hyundai_common.py
index 54ae84a..b5ea09d 100644
--- a/iqdbc_repo/iqdbc/safety/tests/hyundai_common.py
+++ b/iqdbc_repo/iqdbc/safety/tests/hyundai_common.py
@@ -1,296 +1,46 @@
-import unittest
-
-from iqdbc.lvbs.car.hyundai.values import HyundaiSafetyFlagsIQ
-import iqdbc.safety.tests.common as common
from iqdbc.safety.tests.libsafety import libsafety_py
-from iqdbc.safety.tests.common import make_msg
-class Buttons:
- NONE = 0
- RESUME = 1
- SET = 2
- CANCEL = 4
+def packet(addr: int, bus: int, length: int, updates: dict[int, int] | None = None):
+ data = bytearray(length)
+ for index, value in (updates or {}).items():
+ data[index] = value
+ return libsafety_py.make_CANPacket(addr, bus, data)
-PREV_BUTTON_SAMPLES = 8
-ENABLE_BUTTONS = (Buttons.RESUME, Buttons.SET, Buttons.CANCEL)
+def classic_steer(torque: int, request: bool = True):
+ value = torque + 1024
+ word = (value << 16) | (int(request) << 27)
+ return packet(0x340, 0, 8, {i: (word >> (8 * i)) & 0xFF for i in range(4)})
-class HyundaiButtonBase:
- BUTTONS_TX_BUS = 0 # tx on this bus, rx on 0
- SCC_BUS = 0 # rx on this bus
-
- def test_button_sends(self):
- """
- RES, SET and CANCEL buttons are allowed
- - RES and SET allowed while controls allowed
- - CANCEL allowed while cruise is enabled
- """
- self.safety.set_controls_allowed(0)
- self.assertFalse(self._tx(self._button_msg(Buttons.RESUME, bus=self.BUTTONS_TX_BUS)))
- self.assertFalse(self._tx(self._button_msg(Buttons.SET, bus=self.BUTTONS_TX_BUS)))
-
- self.safety.set_controls_allowed(1)
- self.assertTrue(self._tx(self._button_msg(Buttons.RESUME, bus=self.BUTTONS_TX_BUS)))
- self.assertTrue(self._tx(self._button_msg(Buttons.SET, bus=self.BUTTONS_TX_BUS)))
-
- for enabled in (True, False):
- self._rx(self._pcm_status_msg(enabled))
- self.assertEqual(enabled, self._tx(self._button_msg(Buttons.CANCEL, bus=self.BUTTONS_TX_BUS)))
-
- def test_enable_control_allowed_from_cruise(self):
- """
- Hyundai non-longitudinal only enables on PCM rising edge and recent button press. Tests PCM enabling with:
- - disallowed: No buttons
- - disallowed: Buttons that don't enable cruise
- - allowed: Buttons that do enable cruise
- - allowed: Main button with all above combinations
- """
- for main_button in (0, 1):
- for btn in range(8):
- for _ in range(PREV_BUTTON_SAMPLES): # reset
- self._rx(self._button_msg(Buttons.NONE))
-
- self._rx(self._pcm_status_msg(False))
- self.assertFalse(self.safety.get_controls_allowed())
- self._rx(self._button_msg(btn, main_button=main_button))
- self._rx(self._pcm_status_msg(True))
- controls_allowed = btn in ENABLE_BUTTONS or main_button
- self.assertEqual(controls_allowed, self.safety.get_controls_allowed())
-
- def test_sampling_cruise_buttons(self):
- """
- Test that we allow controls on recent button press, but not as button leaves sliding window
- """
- self._rx(self._button_msg(Buttons.SET))
- for i in range(2 * PREV_BUTTON_SAMPLES):
- self._rx(self._pcm_status_msg(False))
- self.assertFalse(self.safety.get_controls_allowed())
- self._rx(self._pcm_status_msg(True))
- controls_allowed = i < PREV_BUTTON_SAMPLES
- self.assertEqual(controls_allowed, self.safety.get_controls_allowed())
- self._rx(self._button_msg(Buttons.NONE))
+def canfd_steer(addr: int, length: int, torque: int, request: bool = True):
+ value = torque + 1024
+ return packet(addr, 0, length, {
+ 5: (value & 0x7F) << 1,
+ 6: ((value >> 7) & 0xF) | (int(request) << 4),
+ })
-class HyundaiLongitudinalBase(common.LongitudinalAccelSafetyTest):
+def classic_accel(accel: int, *, aeb_decel: int = 0, aeb_request: bool = False):
+ value = accel + 1023
+ return packet(0x421, 0, 8, {
+ 2: aeb_decel,
+ 3: value & 0xFF,
+ 4: ((value >> 8) & 0x7) | ((value & 0x7) << 5),
+ 5: (value >> 3) & 0xFF,
+ 6: int(aeb_request) << 6,
+ })
- DISABLED_ECU_UDS_MSG: tuple[int, int]
- DISABLED_ECU_ACTUATION_MSG: tuple[int, int]
- @classmethod
- def setUpClass(cls):
- if cls.__name__ == "HyundaiLongitudinalBase":
- cls.safety = None
- raise unittest.SkipTest
+def canfd_accel(accel: int, *, acc_mode: int = 0, bus: int = 0):
+ value = accel + 1023
+ return packet(0x1A0, bus, 32, {
+ 8: (acc_mode & 0x7) << 4,
+ 16: value & 0xFF,
+ 17: ((value >> 8) & 0x7) | ((value & 0xF) << 4),
+ 18: (value >> 4) & 0xFF,
+ })
- # override these tests from CarSafetyTest, hyundai longitudinal uses button enable
- def test_disable_control_allowed_from_cruise(self):
- pass
- def test_enable_control_allowed_from_cruise(self):
- pass
-
- def test_sampling_cruise_buttons(self):
- pass
-
- def test_cruise_engaged_prev(self):
- pass
-
- def test_button_sends(self):
- pass
-
- def _pcm_status_msg(self, enable):
- raise Exception
-
- def _accel_msg(self, accel, aeb_req=False, aeb_decel=0):
- raise NotImplementedError
-
- def _acc_state_msg(self, enable):
- raise NotImplementedError
-
- def _tx_acc_state_msg(self, enable):
- raise NotImplementedError
-
- def test_pcm_main_cruise_state_availability(self):
- pass
-
- def test_set_resume_buttons(self):
- """
- SET and RESUME enter controls allowed on their falling edge.
- """
- for btn_prev in range(8):
- for btn_cur in range(8):
- self._rx(self._button_msg(Buttons.NONE))
- self.safety.set_controls_allowed(0)
- for _ in range(10):
- self._rx(self._button_msg(btn_prev))
- self.assertFalse(self.safety.get_controls_allowed())
-
- # should enter controls allowed on falling edge and not transitioning to cancel
- should_enable = btn_cur != btn_prev and \
- btn_cur != Buttons.CANCEL and \
- btn_prev in (Buttons.RESUME, Buttons.SET)
-
- self._rx(self._button_msg(btn_cur))
- self.assertEqual(should_enable, self.safety.get_controls_allowed())
-
- def test_cancel_button(self):
- self.safety.set_controls_allowed(1)
- self._rx(self._button_msg(Buttons.CANCEL))
- self.assertFalse(self.safety.get_controls_allowed())
-
- def test_main_cruise_button(self):
- """Test that main cruise button correctly toggles acc_main_on state"""
- default_safety_mode = self.safety.get_current_safety_mode()
- default_safety_param = self.safety.get_current_safety_param()
- default_safety_param_iq = self.safety.get_current_safety_param_iq()
-
- for enable_aol in (True, False):
- with self.subTest("enable_aol", aol_enabled=enable_aol):
- for main_cruise_toggleable in (True, False):
- with self.subTest("main_cruise_toggleable", main_cruise_toggleable=main_cruise_toggleable):
- main_cruise_toggleable_flag = HyundaiSafetyFlagsIQ.LONG_MAIN_CRUISE_TOGGLEABLE if main_cruise_toggleable else 0
- self.safety.set_current_safety_param_iq(default_safety_param_iq | main_cruise_toggleable_flag)
- self.safety.set_safety_hooks(default_safety_mode, default_safety_param)
-
- # Test initial state
- self.safety.set_aol_params(enable_aol, False, False)
-
- self.assertFalse(self.safety.get_acc_main_on())
-
- self._rx(self._main_cruise_button_msg(0))
- self._rx(self._main_cruise_button_msg(1))
- self.assertEqual(enable_aol and main_cruise_toggleable, self.safety.get_controls_allowed_lat())
-
- self._rx(self._main_cruise_button_msg(0))
- self.assertEqual(enable_aol and main_cruise_toggleable, self.safety.get_controls_allowed_lat())
-
- self._rx(self._main_cruise_button_msg(1))
- self.assertFalse(self.safety.get_controls_allowed_lat())
-
- for _ in range(10):
- self._rx(self._main_cruise_button_msg(1))
- self.assertFalse(self.safety.get_controls_allowed_lat())
- self.safety.set_current_safety_param_iq(default_safety_param_iq)
-
- def test_acc_main_sync_mismatches_reset(self):
- """Test that acc_main_on_mismatches resets properly on rising edge of main button"""
- default_safety_mode = self.safety.get_current_safety_mode()
- default_safety_param = self.safety.get_current_safety_param()
- default_safety_param_iq = self.safety.get_current_safety_param_iq()
-
- for enable_aol in (True, False):
- with self.subTest("enable_aol", aol_enabled=enable_aol):
- main_cruise_toggleable_flag = HyundaiSafetyFlagsIQ.LONG_MAIN_CRUISE_TOGGLEABLE
- self.safety.set_current_safety_param_iq(default_safety_param_iq | main_cruise_toggleable_flag)
- self.safety.set_safety_hooks(default_safety_mode, default_safety_param)
-
- self.safety.set_aol_params(enable_aol, False, False)
-
- # Initial state
- self._rx(self._main_cruise_button_msg(0))
- self.assertFalse(self.safety.get_acc_main_on())
-
- # Set up mismatch condition
- self._rx(self._main_cruise_button_msg(1)) # Press button - acc_main_on = True
- self._rx(self._main_cruise_button_msg(0)) # Release button
- self._tx(self._tx_acc_state_msg(False)) # acc_main_on_tx = False
- self.assertTrue(self.safety.get_acc_main_on())
- self.assertEqual(1, self.safety.get_acc_main_on_mismatches())
-
- # Rising edge of acc_main_on should reset
- self._rx(self._main_cruise_button_msg(1)) # Press button again
- self._rx(self._main_cruise_button_msg(0)) # Release button
- self._tx(self._tx_acc_state_msg(False)) # acc_main_on_tx = False
- self.assertFalse(self.safety.get_acc_main_on())
- self.assertEqual(0, self.safety.get_acc_main_on_mismatches())
- self.safety.set_current_safety_param_iq(default_safety_param_iq)
-
- def test_acc_main_sync_mismatch_counter(self):
- """Test mismatch counter behavior and disengagement"""
- default_safety_mode = self.safety.get_current_safety_mode()
- default_safety_param = self.safety.get_current_safety_param()
- default_safety_param_iq = self.safety.get_current_safety_param_iq()
-
- for enable_aol in (True, False):
- with self.subTest("enable_aol", aol_enabled=enable_aol):
- main_cruise_toggleable_flag = HyundaiSafetyFlagsIQ.LONG_MAIN_CRUISE_TOGGLEABLE
- self.safety.set_current_safety_param_iq(default_safety_param_iq | main_cruise_toggleable_flag)
- self.safety.set_safety_hooks(default_safety_mode, default_safety_param)
-
- self.safety.set_aol_params(enable_aol, False, False)
- self.safety.set_controls_allowed_lat(True)
-
- # Start with matched states
- self._rx(self._main_cruise_button_msg(0))
- self._tx(self._tx_acc_state_msg(False))
- self.assertEqual(0, self.safety.get_acc_main_on_mismatches())
-
- # Create mismatch by enabling acc_main_on
- self._rx(self._main_cruise_button_msg(1)) # Press button
- self._rx(self._main_cruise_button_msg(0)) # Release button
- self._tx(self._tx_acc_state_msg(False)) # acc_main_on_tx stays false
- self.assertTrue(self.safety.get_acc_main_on())
- self.assertEqual(1, self.safety.get_acc_main_on_mismatches())
-
- # Second mismatch
- self._tx(self._tx_acc_state_msg(False))
- self.assertTrue(self.safety.get_acc_main_on())
- self.assertEqual(2, self.safety.get_acc_main_on_mismatches())
-
- # Third mismatch should trigger disengagement
- self._tx(self._tx_acc_state_msg(False))
- self.assertFalse(self.safety.get_acc_main_on())
- self.assertFalse(self.safety.get_controls_allowed_lat())
- # Counter should reset after disengagement
- self._tx(self._tx_acc_state_msg(False))
- self.assertEqual(0, self.safety.get_acc_main_on_mismatches())
- self.safety.set_current_safety_param_iq(default_safety_param_iq)
-
- def test_acc_main_sync_mismatch_recovery(self):
- default_safety_mode = self.safety.get_current_safety_mode()
- default_safety_param = self.safety.get_current_safety_param()
- default_safety_param_iq = self.safety.get_current_safety_param_iq()
-
- """Test that mismatch counter resets when states resync"""
- for enable_aol in (True, False):
- with self.subTest("enable_aol", aol_enabled=enable_aol):
- main_cruise_toggleable_flag = HyundaiSafetyFlagsIQ.LONG_MAIN_CRUISE_TOGGLEABLE
- self.safety.set_current_safety_param_iq(default_safety_param_iq | main_cruise_toggleable_flag)
- self.safety.set_safety_hooks(default_safety_mode, default_safety_param)
-
- self.safety.set_aol_params(enable_aol, False, False)
-
- # Create initial mismatch
- self._rx(self._main_cruise_button_msg(1)) # Press button
- self._rx(self._main_cruise_button_msg(0)) # Release button
- self._tx(self._tx_acc_state_msg(False)) # acc_main_on_tx = False
- self.assertEqual(1, self.safety.get_acc_main_on_mismatches())
-
- # Sync states
- self._tx(self._tx_acc_state_msg(True)) # Match acc_main_on_tx to acc_main_on
- self.assertEqual(0, self.safety.get_acc_main_on_mismatches())
- self.safety.set_current_safety_param_iq(default_safety_param_iq)
-
- def test_tester_present_allowed(self, ecu_disable: bool = True):
- """
- Ensure tester present diagnostic message is allowed to keep ECU knocked out
- for longitudinal control.
- """
-
- addr, bus = self.DISABLED_ECU_UDS_MSG
- for should_tx, msg in ((True, b"\x02\x3E\x80\x00\x00\x00\x00\x00"),
- (False, b"\x03\xAA\xAA\x00\x00\x00\x00\x00")):
- tester_present = libsafety_py.make_CANPacket(addr, bus, msg)
- self.assertEqual(should_tx and ecu_disable, self._tx(tester_present))
-
- def test_disabled_ecu_alive(self):
- """
- If the ECU knockout failed, make sure the relay malfunction is shown
- """
-
- addr, bus = self.DISABLED_ECU_ACTUATION_MSG
- self.assertFalse(self.safety.get_relay_malfunction())
- self._rx(make_msg(bus, addr, 8))
- self.assertTrue(self.safety.get_relay_malfunction())
+TESTER_PRESENT = bytes.fromhex("023e800000000000")
diff --git a/iqdbc_repo/iqdbc/safety/tests/libsafety/SConscript b/iqdbc_repo/iqdbc/safety/tests/libsafety/SConscript
index e0a8a4e..4962d2f 100644
--- a/iqdbc_repo/iqdbc/safety/tests/libsafety/SConscript
+++ b/iqdbc_repo/iqdbc/safety/tests/libsafety/SConscript
@@ -25,6 +25,11 @@ env = Environment(
tools=["default", "compilation_db"],
)
+# 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])
+
# The Mull plugin injects mutations that are dormant unless run with mull-runner
if system == "Darwin":
mull_plugin = Dir('#').abspath + '/.mull/lib/mull-ir-frontend-18'
diff --git a/iqdbc_repo/iqdbc/safety/tests/test_ford.py b/iqdbc_repo/iqdbc/safety/tests/test_ford.py
index 63fca32..ee54328 100755
--- a/iqdbc_repo/iqdbc/safety/tests/test_ford.py
+++ b/iqdbc_repo/iqdbc/safety/tests/test_ford.py
@@ -22,7 +22,7 @@ MSG_LateralMotionControl = 0x3D3 # TX by OP, Lateral Control message
MSG_LateralMotionControl2 = 0x3D6 # TX by OP, alternate Lateral Control message
MSG_IPMA_Data = 0x3D8 # TX by OP, IPMA and LKAS user interface
-SAFETY_ISO_LATERAL_ACCEL = 3.0
+SAFETY_ISO_LATERAL_ACCEL = 5.0
EARTH_G = 9.81
AVERAGE_ROAD_ROLL = 0.06
MAX_LATERAL_ACCEL = SAFETY_ISO_LATERAL_ACCEL - (EARTH_G * AVERAGE_ROAD_ROLL)
diff --git a/iqdbc_repo/iqdbc/safety/tests/test_gm.py b/iqdbc_repo/iqdbc/safety/tests/test_gm.py
index 925f357..705bd3f 100755
--- a/iqdbc_repo/iqdbc/safety/tests/test_gm.py
+++ b/iqdbc_repo/iqdbc/safety/tests/test_gm.py
@@ -7,7 +7,8 @@ from iqdbc.safety.tests.libsafety import libsafety_py
import iqdbc.safety.tests.common as common
from iqdbc.safety.tests.common import CANPackerSafety
-from iqdbc.lvbs.car.gm.values_ext import GMSafetyFlagsIQ
+# GM_PARAM_IQ_NON_ACC in safety/modes/gm.h (IQ safety framework flag)
+GM_PARAM_IQ_NON_ACC = 1
class Buttons:
@@ -236,7 +237,7 @@ class TestGmCameraNonACCSafety(TestGmCameraSafety):
self.packer = CANPackerSafety("gm_global_a_powertrain_generated")
self.packer_chassis = CANPackerSafety("gm_global_a_chassis")
self.safety = libsafety_py.libsafety
- self.safety.set_current_safety_param_iq(GMSafetyFlagsIQ.NON_ACC)
+ self.safety.set_current_safety_param_iq(GM_PARAM_IQ_NON_ACC)
self.safety.set_safety_hooks(CarParams.SafetyModel.gm, GMSafetyFlags.HW_CAM | self.EXTRA_SAFETY_PARAM)
self.safety.init_tests()
diff --git a/iqdbc_repo/iqdbc/safety/tests/test_honda.py b/iqdbc_repo/iqdbc/safety/tests/test_honda.py
index de5c3a6..a12ea52 100755
--- a/iqdbc_repo/iqdbc/safety/tests/test_honda.py
+++ b/iqdbc_repo/iqdbc/safety/tests/test_honda.py
@@ -9,7 +9,7 @@ from iqdbc.car.structs import CarParams
from iqdbc.safety.tests.common import CANPackerSafety, MAX_WRONG_COUNTERS
from iqdbc.safety.tests.gas_interceptor_common import GasInterceptorSafetyTest
-from iqdbc.lvbs.car.honda.values_ext import HondaSafetyFlagsIQ
+from iqdbc.lvbs.car.honda.iq_values import HondaSafetyFlagsIQ
HONDA_N_COMMON_TX_MSGS = [[0xE4, 0], [0x194, 0], [0x1FA, 0], [0x30C, 0], [0x33D, 0]]
diff --git a/iqdbc_repo/iqdbc/safety/tests/test_hyundai.py b/iqdbc_repo/iqdbc/safety/tests/test_hyundai.py
old mode 100755
new mode 100644
index 22db74a..398d03a
--- a/iqdbc_repo/iqdbc/safety/tests/test_hyundai.py
+++ b/iqdbc_repo/iqdbc/safety/tests/test_hyundai.py
@@ -1,569 +1,107 @@
-#!/usr/bin/env python3
-from parameterized import parameterized_class
-import random
-import unittest
+import pytest
from iqdbc.car.hyundai.values import HyundaiSafetyFlags
from iqdbc.car.structs import CarParams
+from iqdbc.safety.tests.hyundai_common import TESTER_PRESENT, classic_accel, classic_steer, packet
from iqdbc.safety.tests.libsafety import libsafety_py
-import iqdbc.safety.tests.common as common
-from iqdbc.safety.tests.common import CANPackerSafety
-from iqdbc.safety.tests.hyundai_common import HyundaiButtonBase, HyundaiLongitudinalBase
-from iqdbc.lvbs.car.hyundai.values import HyundaiSafetyFlagsIQ
-# LDA button availability
-LDA_BUTTON = [
- {"SAFETY_PARAM_IQ": HyundaiSafetyFlagsIQ.DEFAULT},
- {"SAFETY_PARAM_IQ": HyundaiSafetyFlagsIQ.HAS_LDA_BUTTON},
-]
-
-# All combinations of non-SCC HEV/PHEV/EV cars
-_ALL_NON_SCC_HEV_EV_COMBOS = [
- # Hybrid
- {"PCM_STATUS_MSG": ("E_CRUISE_CONTROL", "CRUISE_LAMP_S"),
- "ACC_STATE_MSG": ("E_CRUISE_CONTROL", "CRUISE_LAMP_M"),
- "GAS_MSG": ("E_EMS11", "CR_Vcu_AccPedDep_Pos"),
- "SAFETY_PARAM": HyundaiSafetyFlags.HYBRID_GAS},
- # EV
- {"PCM_STATUS_MSG": ("LABEL11", "CC_ACT"),
- "ACC_STATE_MSG": ("LABEL11", "CC_React"),
- "GAS_MSG": ("E_EMS11", "Accel_Pedal_Pos"),
- "SAFETY_PARAM": HyundaiSafetyFlags.EV_GAS},
-]
-ALL_NON_SCC_HEV_EV_COMBOS = [{**p, **lda} for lda in LDA_BUTTON for p in _ALL_NON_SCC_HEV_EV_COMBOS]
-
-
-# 4 bit checkusm used in some hyundai messages
-# lives outside the can packer because we never send this msg
-def checksum(msg):
- addr, dat, bus = msg
-
- chksum = 0
- if addr == 0x386:
- for i, b in enumerate(dat):
- for j in range(8):
- # exclude checksum and counter bits
- if (i != 1 or j < 6) and (i != 3 or j < 6) and (i != 5 or j < 6) and (i != 7 or j < 6):
- bit = (b >> j) & 1
- else:
- bit = 0
- chksum += bit
- chksum = (chksum ^ 9) & 0xF
- ret = bytearray(dat)
- ret[5] |= (chksum & 0x3) << 6
- ret[7] |= (chksum & 0xc) << 4
- else:
- for i, b in enumerate(dat):
- if addr in [0x260, 0x421] and i == 7:
- b &= 0x0F if addr == 0x421 else 0xF0
- elif addr == 0x394 and i == 6:
- b &= 0xF0
- elif addr == 0x394 and i == 7:
- continue
- chksum += sum(divmod(b, 16))
- chksum = (16 - chksum) % 16
- ret = bytearray(dat)
- ret[6 if addr == 0x394 else 7] |= chksum << (4 if addr == 0x421 else 0)
-
- return addr, ret, bus
-
-
-@parameterized_class(LDA_BUTTON)
-class TestHyundaiSafety(HyundaiButtonBase, common.CarSafetyTest, common.DriverTorqueSteeringSafetyTest, common.SteerRequestCutSafetyTest):
- TX_MSGS = [[0x340, 0], [0x4F1, 0], [0x485, 0]]
- STANDSTILL_THRESHOLD = 12 # 0.375 kph
- RELAY_MALFUNCTION_ADDRS = {0: (0x340, 0x485)} # LKAS11
- FWD_BLACKLISTED_ADDRS = {2: [0x340, 0x485]}
-
- MAX_RATE_UP = 3
- MAX_RATE_DOWN = 7
- MAX_TORQUE_LOOKUP = [0], [384]
- MAX_RT_DELTA = 112
- DRIVER_TORQUE_ALLOWANCE = 50
- DRIVER_TORQUE_FACTOR = 2
-
- # Safety around steering req bit
- MIN_VALID_STEERING_FRAMES = 89
- MAX_INVALID_STEERING_FRAMES = 2
-
- cnt_gas = 0
- cnt_speed = 0
- cnt_brake = 0
- cnt_cruise = 0
- cnt_button = 0
-
- SAFETY_PARAM_IQ: int = 0
-
- @classmethod
- def setUpClass(cls):
- if cls.__name__ == "TestHyundaiSafety":
- cls.safety = None
- raise unittest.SkipTest
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_kia_generic")
- self.safety = libsafety_py.libsafety
- self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, 0)
- self.safety.init_tests()
-
- def _button_msg(self, buttons, main_button=0, bus=0):
- values = {"CF_Clu_CruiseSwState": buttons, "CF_Clu_CruiseSwMain": main_button, "CF_Clu_AliveCnt1": self.cnt_button}
- self.__class__.cnt_button += 1
- return self.packer.make_can_msg_safety("CLU11", bus, values)
-
- def _user_gas_msg(self, gas):
- values = {"CF_Ems_AclAct": gas, "AliveCounter": self.cnt_gas % 4}
- self.__class__.cnt_gas += 1
- return self.packer.make_can_msg_safety("EMS16", 0, values, fix_checksum=checksum)
-
- def _user_brake_msg(self, brake):
- values = {"DriverOverride": 2 if brake else random.choice((0, 1, 3)),
- "AliveCounterTCS": self.cnt_brake % 8}
- self.__class__.cnt_brake += 1
- return self.packer.make_can_msg_safety("TCS13", 0, values, fix_checksum=checksum)
-
- def _speed_msg(self, speed):
- # safety doesn't scale, so undo the scaling
- values = {"WHL_SPD_%s" % s: speed * 0.03125 for s in ["FL", "FR", "RL", "RR"]}
- values["WHL_SPD_AliveCounter_LSB"] = (self.cnt_speed % 16) & 0x3
- values["WHL_SPD_AliveCounter_MSB"] = (self.cnt_speed % 16) >> 2
- self.__class__.cnt_speed += 1
- return self.packer.make_can_msg_safety("WHL_SPD11", 0, values, fix_checksum=checksum)
-
- def _pcm_status_msg(self, enable):
- values = {"ACCMode": enable, "CR_VSM_Alive": self.cnt_cruise % 16}
- self.__class__.cnt_cruise += 1
- return self.packer.make_can_msg_safety("SCC12", self.SCC_BUS, values, fix_checksum=checksum)
-
- def _torque_driver_msg(self, torque):
- values = {"CR_Mdps_StrColTq": torque}
- return self.packer.make_can_msg_safety("MDPS12", 0, values)
-
- def _torque_cmd_msg(self, torque, steer_req=1):
- values = {"CR_Lkas_StrToqReq": torque, "CF_Lkas_ActToi": steer_req}
- return self.packer.make_can_msg_safety("LKAS11", 0, values)
-
- def _acc_state_msg(self, enable):
- values = {"MainMode_ACC": enable}
- return self.packer.make_can_msg_safety("SCC11", self.SCC_BUS, values)
-
- def _lkas_button_msg(self, enabled):
- if self.SAFETY_PARAM_IQ & HyundaiSafetyFlagsIQ.HAS_LDA_BUTTON:
- values = {"LDA_BTN": enabled}
- return self.packer.make_can_msg_safety("BCM_PO_11", 0, values)
- else:
- raise NotImplementedError
-
- def _main_cruise_button_msg(self, enabled):
- return self._button_msg(0, enabled)
-
- def test_pcm_main_cruise_state_availability(self):
- """Test that ACC main state is correctly set when receiving 0x420 message, toggling HYUNDAI_LONG flag"""
- prior_safety_mode = self.safety.get_current_safety_mode()
- prior_safety_param = self.safety.get_current_safety_param()
-
- for hyundai_longitudinal in (True, False):
- with self.subTest("hyundai_longitudinal", hyundai_longitudinal=hyundai_longitudinal):
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, 0 if hyundai_longitudinal else HyundaiSafetyFlags.LONG)
- for should_turn_acc_main_on in (True, False):
- with self.subTest("acc_main_on", should_turn_acc_main_on=should_turn_acc_main_on):
- self._rx(self._acc_state_msg(should_turn_acc_main_on)) # Send the ACC state message
- expected_acc_main = should_turn_acc_main_on and hyundai_longitudinal # ACC main should only be set if hyundai_longitudinal is True
- self.assertEqual(expected_acc_main, self.safety.get_acc_main_on())
- self.safety.set_safety_hooks(prior_safety_mode, prior_safety_param)
-
- def test_enable_control_allowed_with_aol_button(self):
- default_safety_mode = self.safety.get_current_safety_mode()
- default_safety_param = self.safety.get_current_safety_param()
- default_safety_param_iq = self.safety.get_current_safety_param_iq()
- """Toggle AOL with AOL button"""
- try:
- self._lkas_button_msg(False)
- except NotImplementedError as err:
- raise unittest.SkipTest("Skipping test because LDA button is not supported") from err
-
- try:
- for enable_aol in (True, False):
- with self.subTest("enable_aol", aol_enabled=enable_aol):
- for has_lda_button_param in (True, False):
- with self.subTest("has_lda_button", has_lda_button_param=has_lda_button_param):
- has_lda_button = HyundaiSafetyFlagsIQ.HAS_LDA_BUTTON if has_lda_button_param else 0
- self.safety.set_current_safety_param_iq(has_lda_button)
- self.safety.set_safety_hooks(default_safety_mode, default_safety_param)
-
- self.safety.set_aol_params(enable_aol, False, False)
- self.assertEqual(enable_aol, self.safety.get_enable_aol())
-
- self._rx(self._lkas_button_msg(True))
- self._rx(self._speed_msg(0))
- self._rx(self._lkas_button_msg(False))
- self._rx(self._speed_msg(0))
- self.assertEqual(enable_aol and has_lda_button_param, self.safety.get_controls_allowed_lat())
- finally:
- self.safety.set_current_safety_param_iq(default_safety_param_iq)
-
-
-@parameterized_class(LDA_BUTTON)
-class TestHyundaiSafetyAltLimits(TestHyundaiSafety):
- MAX_RATE_UP = 2
- MAX_RATE_DOWN = 3
- MAX_TORQUE_LOOKUP = [0], [270]
-
- @classmethod
- def setUpClass(cls):
- if cls.__name__ == "TestHyundaiSafetyAltLimits":
- cls.safety = None
- raise unittest.SkipTest
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_kia_generic")
- self.safety = libsafety_py.libsafety
- self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.ALT_LIMITS)
- self.safety.init_tests()
-
-
-@parameterized_class(LDA_BUTTON)
-class TestHyundaiSafetyAltLimits2(TestHyundaiSafety):
- MAX_RATE_UP = 2
- MAX_RATE_DOWN = 3
- MAX_TORQUE_LOOKUP = [0], [170]
-
- @classmethod
- def setUpClass(cls):
- if cls.__name__ == "TestHyundaiSafetyAltLimits2":
- cls.safety = None
- raise unittest.SkipTest
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_kia_generic")
- self.safety = libsafety_py.libsafety
- self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.ALT_LIMITS_2)
- self.safety.init_tests()
-
-
-@parameterized_class(LDA_BUTTON)
-class TestHyundaiSafetyCameraSCC(TestHyundaiSafety):
- BUTTONS_TX_BUS = 2 # tx on 2, rx on 0
- SCC_BUS = 2 # rx on 2
-
- @classmethod
- def setUpClass(cls):
- if cls.__name__ == "TestHyundaiSafetyCameraSCC":
- cls.safety = None
- raise unittest.SkipTest
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_kia_generic")
- self.safety = libsafety_py.libsafety
- self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.CAMERA_SCC)
- self.safety.init_tests()
-
- def test_pcm_main_cruise_state_availability(self):
- """
- Test that ACC main state is correctly set when receiving 0x420 message.
- For camera SCC, ACC main should always be on when receiving 0x420 message
- """
-
- for should_turn_acc_main_on in (True, False):
- with self.subTest("acc_main_on", should_turn_acc_main_on=should_turn_acc_main_on):
- self._rx(self._acc_state_msg(should_turn_acc_main_on))
- self.assertEqual(should_turn_acc_main_on, self.safety.get_acc_main_on())
-
-
-@parameterized_class(LDA_BUTTON)
-class TestHyundaiSafetyFCEV(TestHyundaiSafety):
- @classmethod
- def setUpClass(cls):
- if cls.__name__ == "TestHyundaiSafetyFCEV":
- cls.safety = None
- raise unittest.SkipTest
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_kia_generic")
- self.safety = libsafety_py.libsafety
- self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.FCEV_GAS)
- self.safety.init_tests()
-
- def _user_gas_msg(self, gas):
- values = {"ACCELERATOR_PEDAL": gas}
- return self.packer.make_can_msg_safety("FCEV_ACCELERATOR", 0, values)
-
-
-class TestHyundaiLegacySafety(TestHyundaiSafety):
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_kia_generic")
- self.safety = libsafety_py.libsafety
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiLegacy, 0)
- self.safety.init_tests()
-
-
-class TestHyundaiLegacySafetyEV(TestHyundaiSafety):
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_kia_generic")
- self.safety = libsafety_py.libsafety
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiLegacy, HyundaiSafetyFlags.EV_GAS)
- self.safety.init_tests()
-
- def _user_gas_msg(self, gas):
- values = {"Accel_Pedal_Pos": gas}
- return self.packer.make_can_msg_safety("E_EMS11", 0, values, fix_checksum=checksum)
-
-
-class TestHyundaiLegacySafetyHEV(TestHyundaiSafety):
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_kia_generic")
- self.safety = libsafety_py.libsafety
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiLegacy, HyundaiSafetyFlags.HYBRID_GAS)
- self.safety.init_tests()
-
- def _user_gas_msg(self, gas):
- values = {"CR_Vcu_AccPedDep_Pos": gas}
- return self.packer.make_can_msg_safety("E_EMS11", 0, values, fix_checksum=checksum)
-
-
-@parameterized_class(LDA_BUTTON)
-class TestHyundaiLongitudinalSafety(HyundaiLongitudinalBase, TestHyundaiSafety):
- TX_MSGS = [[0x340, 0], [0x4F1, 0], [0x485, 0], [0x420, 0], [0x421, 0], [0x50A, 0], [0x389, 0], [0x4A2, 0], [0x38D, 0], [0x483, 0], [0x7D0, 0]]
-
- FWD_BLACKLISTED_ADDRS = {2: [0x340, 0x485, 0x421, 0x420, 0x50A, 0x389]}
-
- RELAY_MALFUNCTION_ADDRS = {0: (0x340, 0x485, 0x421, 0x420, 0x50A, 0x389)} # LKAS11, LFAHDA_MFC, SCC12, SCC11, SCC13, SCC14
-
- DISABLED_ECU_UDS_MSG = (0x7D0, 0)
- DISABLED_ECU_ACTUATION_MSG = (0x421, 0)
-
- @classmethod
- def setUpClass(cls):
- if cls.__name__ == "TestHyundaiLongitudinalSafety":
- cls.safety = None
- raise unittest.SkipTest
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_kia_generic")
- self.safety = libsafety_py.libsafety
- self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.LONG)
- self.safety.init_tests()
-
- def _accel_msg(self, accel, aeb_req=False, aeb_decel=0):
- values = {
- "aReqRaw": accel,
- "aReqValue": accel,
- "AEB_CmdAct": int(aeb_req),
- "CR_VSM_DecCmd": aeb_decel,
- }
- return self.packer.make_can_msg_safety("SCC12", self.SCC_BUS, values)
-
- def _fca11_msg(self, idx=0, vsm_aeb_req=False, fca_aeb_req=False, aeb_decel=0):
- values = {
- "CR_FCA_Alive": idx % 0xF,
- "FCA_Status": 2,
- "CR_VSM_DecCmd": aeb_decel,
- "CF_VSM_DecCmdAct": int(vsm_aeb_req),
- "FCA_CmdAct": int(fca_aeb_req),
- }
- return self.packer.make_can_msg_safety("FCA11", 0, values)
-
- def _tx_acc_state_msg(self, enable):
- values = {"MainMode_ACC": enable}
- return self.packer.make_can_msg_safety("SCC11", 0, values)
-
- def test_no_aeb_fca11(self):
- self.assertTrue(self._tx(self._fca11_msg()))
- self.assertFalse(self._tx(self._fca11_msg(vsm_aeb_req=True)))
- self.assertFalse(self._tx(self._fca11_msg(fca_aeb_req=True)))
- self.assertFalse(self._tx(self._fca11_msg(aeb_decel=1.0)))
-
- def test_no_aeb_scc12(self):
- self.assertTrue(self._tx(self._accel_msg(0)))
- self.assertFalse(self._tx(self._accel_msg(0, aeb_req=True)))
- self.assertFalse(self._tx(self._accel_msg(0, aeb_decel=1.0)))
-
-
-class TestHyundaiLongitudinalSafetyCameraSCC(HyundaiLongitudinalBase, TestHyundaiSafety):
- TX_MSGS = [[0x340, 0], [0x4F1, 2], [0x485, 0], [0x420, 0], [0x421, 0], [0x50A, 0], [0x389, 0], [0x4A2, 0]]
-
- FWD_BLACKLISTED_ADDRS = {2: [0x340, 0x485, 0x420, 0x421, 0x50A, 0x389]}
- RELAY_MALFUNCTION_ADDRS = {0: (0x340, 0x485, 0x421, 0x420, 0x50A, 0x389)} # LKAS11, LFAHDA_MFC, SCC12, SCC11, SCC13, SCC14
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_kia_generic")
- self.safety = libsafety_py.libsafety
- self.safety.set_current_safety_param_iq(HyundaiSafetyFlagsIQ.HAS_LDA_BUTTON)
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.CAMERA_SCC)
- self.safety.init_tests()
-
- def _accel_msg(self, accel, aeb_req=False, aeb_decel=0):
- values = {
- "aReqRaw": accel,
- "aReqValue": accel,
- "AEB_CmdAct": int(aeb_req),
- "CR_VSM_DecCmd": aeb_decel,
- }
- return self.packer.make_can_msg_safety("SCC12", self.SCC_BUS, values)
-
- def _tx_acc_state_msg(self, enable):
- values = {"MainMode_ACC": enable}
- return self.packer.make_can_msg_safety("SCC11", self.SCC_BUS, values)
-
- def test_no_aeb_scc12(self):
- self.assertTrue(self._tx(self._accel_msg(0)))
- self.assertFalse(self._tx(self._accel_msg(0, aeb_req=True)))
- self.assertFalse(self._tx(self._accel_msg(0, aeb_decel=1.0)))
-
- def test_tester_present_allowed(self):
- pass
-
- def test_disabled_ecu_alive(self):
- pass
-
-
-@parameterized_class(LDA_BUTTON)
-class TestHyundaiSafetyFCEVLong(TestHyundaiLongitudinalSafety, TestHyundaiSafetyFCEV):
- @classmethod
- def setUpClass(cls):
- if cls.__name__ == "TestHyundaiSafetyFCEVLong":
- cls.safety = None
- raise unittest.SkipTest
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_kia_generic")
- self.safety = libsafety_py.libsafety
- self.safety.set_current_safety_param_iq(self.SAFETY_PARAM_IQ)
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.FCEV_GAS | HyundaiSafetyFlags.LONG)
- self.safety.init_tests()
-
-
-@parameterized_class(LDA_BUTTON)
-class TestHyundaiLongitudinalESCCSafety(HyundaiLongitudinalBase, TestHyundaiSafety):
- TX_MSGS = [[0x340, 0], [0x4F1, 0], [0x485, 0], [0x420, 0], [0x421, 0], [0x50A, 0], [0x389, 0]]
-
- FWD_BLACKLISTED_ADDRS = {2: [0x340, 0x485, 0x420, 0x421, 0x50A, 0x389]}
- RELAY_MALFUNCTION_ADDRS = {0: (0x340, 0x485, 0x420, 0x421, 0x50A, 0x389)} # LKAS11, LFAHDA_MFC, SCC12, SCC11, SCC13, SCC14
-
- @classmethod
- def setUpClass(cls):
- if cls.__name__ == "TestHyundaiLongitudinalESCCSafety":
- cls.safety = None
- raise unittest.SkipTest
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_kia_generic")
- self.safety = libsafety_py.libsafety
- self.safety.set_current_safety_param_iq(HyundaiSafetyFlagsIQ.ESCC | self.SAFETY_PARAM_IQ)
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.LONG)
- self.safety.init_tests()
-
- def _accel_msg(self, accel, aeb_req=False, aeb_decel=0):
- values = {
- "aReqRaw": accel,
- "aReqValue": accel,
- }
- return self.packer.make_can_msg_safety("SCC12", self.SCC_BUS, values)
-
- def _tx_acc_state_msg(self, enable):
- values = {"MainMode_ACC": enable}
- return self.packer.make_can_msg_safety("SCC11", 0, values)
-
- def test_tester_present_allowed(self):
- pass
-
- def test_disabled_ecu_alive(self):
- pass
-
-
-@parameterized_class(LDA_BUTTON)
-class TestHyundaiNonSCCSafety(TestHyundaiSafety):
-
- @classmethod
- def setUpClass(cls):
- if cls.__name__ == "TestHyundaiNonSCCSafety":
- cls.safety = None
- raise unittest.SkipTest
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_kia_generic")
- self.safety = libsafety_py.libsafety
- self.safety.set_current_safety_param_iq(HyundaiSafetyFlagsIQ.NON_SCC | self.SAFETY_PARAM_IQ)
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, 0)
- self.safety.init_tests()
-
- def _pcm_status_msg(self, enable):
- values = {"CRUISE_LAMP_S": enable, "AliveCounter": self.cnt_gas % 4}
- self.__class__.cnt_gas += 1
- return self.packer.make_can_msg_safety("EMS16", 0, values, fix_checksum=checksum)
-
- def _acc_state_msg(self, enable):
- values = {"CRUISE_LAMP_M": enable, "AliveCounter": self.cnt_gas % 4}
- self.__class__.cnt_gas += 1
- return self.packer.make_can_msg_safety("EMS16", 0, values, fix_checksum=checksum)
-
- def _user_gas_msg(self, gas: float, controls_allowed: bool = True):
- values = {"CF_Ems_AclAct": gas, "CRUISE_LAMP_M": 1, "CRUISE_LAMP_S": controls_allowed, "AliveCounter": self.cnt_gas % 4}
- self.__class__.cnt_gas += 1
- return self.packer.make_can_msg_safety("EMS16", 0, values, fix_checksum=checksum)
-
- def test_allow_engage_with_gas_pressed(self):
- self._rx(self._user_gas_msg(1, self.safety.get_controls_allowed()))
- self.safety.set_controls_allowed(True)
- self._rx(self._user_gas_msg(1, self.safety.get_controls_allowed()))
- self.assertTrue(self.safety.get_controls_allowed())
- self._rx(self._user_gas_msg(1, self.safety.get_controls_allowed()))
- self.assertTrue(self.safety.get_controls_allowed())
-
- def test_no_disengage_on_gas(self):
- self._rx(self._user_gas_msg(0, self.safety.get_controls_allowed()))
- self.safety.set_controls_allowed(True)
- self._rx(self._user_gas_msg(self.GAS_PRESSED_THRESHOLD + 1, self.safety.get_controls_allowed()))
- # Test we allow lateral, but not longitudinal
- self.assertTrue(self.safety.get_controls_allowed())
- self.assertFalse(self.safety.get_longitudinal_brake_allowed())
- self.assertTrue(self.safety.get_longitudinal_gas_allowed())
- # Make sure we can re-gain longitudinal actuation
- self._rx(self._user_gas_msg(0, self.safety.get_controls_allowed()))
- self.assertTrue(self.safety.get_longitudinal_brake_allowed())
- self.assertTrue(self.safety.get_longitudinal_gas_allowed())
-
-
-@parameterized_class(ALL_NON_SCC_HEV_EV_COMBOS)
-class TestHyundaiNonSCCSafety_HEV_EV(TestHyundaiSafety):
-
- PCM_STATUS_MSG = ("", "")
- ACC_STATE_MSG = ("", "")
- GAS_MSG = ("", "")
- SAFETY_PARAM = 0
-
- @classmethod
- def setUpClass(cls):
- if cls.__name__ == "TestHyundaiNonSCCSafety_HEV_EV":
- cls.safety = None
- raise unittest.SkipTest
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_kia_generic")
- self.safety = libsafety_py.libsafety
- self.safety.set_current_safety_param_iq(HyundaiSafetyFlagsIQ.NON_SCC | self.SAFETY_PARAM_IQ)
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundai, self.SAFETY_PARAM)
- self.safety.init_tests()
-
- def _pcm_status_msg(self, enable):
- values = {self.PCM_STATUS_MSG[1]: enable}
- return self.packer.make_can_msg_safety(self.PCM_STATUS_MSG[0], 0, values)
-
- def _acc_state_msg(self, enable):
- values = {self.ACC_STATE_MSG[1]: enable}
- return self.packer.make_can_msg_safety(self.ACC_STATE_MSG[0], 0, values)
-
- def _user_gas_msg(self, gas):
- values = {self.GAS_MSG[1]: gas}
- return self.packer.make_can_msg_safety(self.GAS_MSG[0], 0, values, fix_checksum=checksum)
-
-
-if __name__ == "__main__":
- unittest.main()
+@pytest.fixture
+def safety():
+ return libsafety_py.libsafety
+
+
+@pytest.mark.parametrize("mode", (CarParams.SafetyModel.hyundai, CarParams.SafetyModel.hyundaiLegacy))
+@pytest.mark.parametrize("param", (
+ 0,
+ HyundaiSafetyFlags.EV_GAS,
+ HyundaiSafetyFlags.HYBRID_GAS,
+ HyundaiSafetyFlags.LONG,
+ HyundaiSafetyFlags.CAMERA_SCC,
+ HyundaiSafetyFlags.ALT_LIMITS,
+ HyundaiSafetyFlags.FCEV_GAS,
+ HyundaiSafetyFlags.ALT_LIMITS_2,
+))
+def test_classic_safety_configurations_initialize(safety, mode, param):
+ assert safety.set_safety_hooks(mode, param) == 0
+ safety.init_tests()
+ assert safety.get_current_safety_param() == param
+
+
+@pytest.mark.parametrize("mode", (CarParams.SafetyModel.hyundai, CarParams.SafetyModel.hyundaiLegacy))
+def test_classic_tx_whitelist_and_steering_limits(safety, mode):
+ safety.set_safety_hooks(mode, 0)
+ safety.init_tests()
+
+ assert not safety.safety_tx_hook(packet(0x123, 0, 8))
+ assert not safety.safety_tx_hook(packet(0x340, 1, 8))
+
+ safety.set_controls_allowed(False)
+ assert safety.safety_tx_hook(classic_steer(0, False))
+ assert not safety.safety_tx_hook(classic_steer(1))
+
+ safety.set_controls_allowed(True)
+ assert safety.safety_tx_hook(classic_steer(10))
+ safety.set_desired_torque_last(512)
+ safety.set_rt_torque_last(512)
+ assert safety.safety_tx_hook(classic_steer(512))
+ assert not safety.safety_tx_hook(classic_steer(513))
+ assert not safety.safety_tx_hook(classic_steer(-513))
+
+
+def test_classic_alt_limits_2(safety):
+ safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.ALT_LIMITS_2)
+ safety.init_tests()
+ safety.set_controls_allowed(True)
+ safety.set_desired_torque_last(170)
+ safety.set_rt_torque_last(170)
+ assert safety.safety_tx_hook(classic_steer(170))
+ assert not safety.safety_tx_hook(classic_steer(171))
+
+
+def test_classic_longitudinal_accel_and_aeb_guards(safety):
+ safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.LONG)
+ safety.init_tests()
+
+ safety.set_controls_allowed(False)
+ assert safety.safety_tx_hook(classic_accel(0))
+ assert not safety.safety_tx_hook(classic_accel(1))
+
+ safety.set_controls_allowed(True)
+ for accel in (-400, 0, 250):
+ assert safety.safety_tx_hook(classic_accel(accel))
+ for accel in (-401, 251):
+ assert not safety.safety_tx_hook(classic_accel(accel))
+ assert not safety.safety_tx_hook(classic_accel(0, aeb_decel=1))
+ assert not safety.safety_tx_hook(classic_accel(0, aeb_request=True))
+
+ assert safety.safety_tx_hook(packet(0x38D, 0, 8))
+ assert not safety.safety_tx_hook(packet(0x38D, 0, 8, {1: 1}))
+ assert not safety.safety_tx_hook(packet(0x38D, 0, 8, {2: 1 << 4}))
+ assert not safety.safety_tx_hook(packet(0x38D, 0, 8, {3: 1 << 7}))
+
+
+def test_classic_buttons(safety):
+ safety.set_safety_hooks(CarParams.SafetyModel.hyundai, 0)
+ safety.init_tests()
+
+ safety.set_controls_allowed(False)
+ assert not safety.safety_tx_hook(packet(0x4F1, 0, 4, {0: 1}))
+ assert not safety.safety_tx_hook(packet(0x4F1, 0, 4, {0: 2}))
+ assert not safety.safety_tx_hook(packet(0x4F1, 0, 4, {0: 4}))
+
+ safety.set_controls_allowed(True)
+ assert safety.safety_tx_hook(packet(0x4F1, 0, 4, {0: 1}))
+ assert not safety.safety_tx_hook(packet(0x4F1, 0, 4, {0: 2}))
+ assert safety.safety_tx_hook(packet(0x4F1, 0, 4, {0: 4}))
+
+ safety.set_controls_allowed(False)
+ safety.set_cruise_engaged_prev(True)
+ assert safety.safety_tx_hook(packet(0x4F1, 0, 4, {0: 4}))
+
+
+def test_classic_diagnostic_payload_is_restricted(safety):
+ safety.set_safety_hooks(CarParams.SafetyModel.hyundai, HyundaiSafetyFlags.LONG)
+ safety.init_tests()
+ assert safety.safety_tx_hook(packet(0x7D0, 0, 8, dict(enumerate(TESTER_PRESENT))))
+ assert not safety.safety_tx_hook(packet(0x7D0, 0, 8, {0: 3, 1: 0x22}))
diff --git a/iqdbc_repo/iqdbc/safety/tests/test_hyundai_canfd.py b/iqdbc_repo/iqdbc/safety/tests/test_hyundai_canfd.py
old mode 100755
new mode 100644
index fbdf2dd..b0c0f27
--- a/iqdbc_repo/iqdbc/safety/tests/test_hyundai_canfd.py
+++ b/iqdbc_repo/iqdbc/safety/tests/test_hyundai_canfd.py
@@ -1,312 +1,104 @@
-#!/usr/bin/env python3
-from parameterized import parameterized_class
-import unittest
+import pytest
from iqdbc.car.hyundai.values import HyundaiSafetyFlags
from iqdbc.car.structs import CarParams
+from iqdbc.safety.tests.hyundai_common import TESTER_PRESENT, canfd_accel, canfd_steer, packet
from iqdbc.safety.tests.libsafety import libsafety_py
-import iqdbc.safety.tests.common as common
-from iqdbc.safety.tests.common import CANPackerSafety
-from iqdbc.safety.tests.hyundai_common import HyundaiButtonBase, HyundaiLongitudinalBase
-# All combinations of radar/camera-SCC and gas/hybrid/EV cars
-ALL_GAS_EV_HYBRID_COMBOS = [
- # Radar SCC
- {"GAS_MSG": ("ACCELERATOR_BRAKE_ALT", "ACCELERATOR_PEDAL_PRESSED"), "SCC_BUS": 0, "SAFETY_PARAM": 0},
- {"GAS_MSG": ("ACCELERATOR", "ACCELERATOR_PEDAL"), "SCC_BUS": 0, "SAFETY_PARAM": HyundaiSafetyFlags.EV_GAS},
- {"GAS_MSG": ("ACCELERATOR_ALT", "ACCELERATOR_PEDAL"), "SCC_BUS": 0, "SAFETY_PARAM": HyundaiSafetyFlags.HYBRID_GAS},
- # Camera SCC
- {"GAS_MSG": ("ACCELERATOR_BRAKE_ALT", "ACCELERATOR_PEDAL_PRESSED"), "SCC_BUS": 2, "SAFETY_PARAM": HyundaiSafetyFlags.CAMERA_SCC},
- {"GAS_MSG": ("ACCELERATOR", "ACCELERATOR_PEDAL"), "SCC_BUS": 2, "SAFETY_PARAM": HyundaiSafetyFlags.EV_GAS | HyundaiSafetyFlags.CAMERA_SCC},
- {"GAS_MSG": ("ACCELERATOR_ALT", "ACCELERATOR_PEDAL"), "SCC_BUS": 2, "SAFETY_PARAM": HyundaiSafetyFlags.HYBRID_GAS | HyundaiSafetyFlags.CAMERA_SCC},
-]
-
-class TestHyundaiCanfdBase(HyundaiButtonBase, common.CarSafetyTest, common.DriverTorqueSteeringSafetyTest, common.SteerRequestCutSafetyTest):
-
- TX_MSGS = [[0x50, 0], [0x1CF, 1], [0x2A4, 0]]
- STANDSTILL_THRESHOLD = 12 # 0.375 kph
- FWD_BLACKLISTED_ADDRS = {2: [0x50, 0x2a4]}
-
- MAX_RATE_UP = 2
- MAX_RATE_DOWN = 3
- MAX_TORQUE_LOOKUP = [0], [270]
-
- MAX_RT_DELTA = 112
-
- DRIVER_TORQUE_ALLOWANCE = 250
- DRIVER_TORQUE_FACTOR = 2
-
- # Safety around steering req bit
- MIN_VALID_STEERING_FRAMES = 89
- MAX_INVALID_STEERING_FRAMES = 2
-
- PT_BUS = 0
- SCC_BUS = 2
- STEER_BUS = 0
- STEER_MSG = ""
- GAS_MSG = ("", "")
- BUTTONS_TX_BUS = 1
-
- def _torque_driver_msg(self, torque):
- values = {"STEERING_COL_TORQUE": torque}
- return self.packer.make_can_msg_safety("MDPS", self.PT_BUS, values)
-
- def _torque_cmd_msg(self, torque, steer_req=1):
- values = {"TORQUE_REQUEST": torque, "STEER_REQ": steer_req}
- return self.packer.make_can_msg_safety(self.STEER_MSG, self.STEER_BUS, values)
-
- def _speed_msg(self, speed):
- values = {f"WHL_Spd{pos}Val": speed * 0.03125 for pos in ["FL", "FR", "RL", "RR"]}
- return self.packer.make_can_msg_safety("WHEEL_SPEEDS", self.PT_BUS, values)
-
- def _user_brake_msg(self, brake):
- values = {"DriverBraking": brake}
- return self.packer.make_can_msg_safety("TCS", self.PT_BUS, values)
-
- def _user_gas_msg(self, gas):
- values = {self.GAS_MSG[1]: gas}
- return self.packer.make_can_msg_safety(self.GAS_MSG[0], self.PT_BUS, values)
-
- def _pcm_status_msg(self, enable):
- values = {"ACCMode": 1 if enable else 0}
- return self.packer.make_can_msg_safety("SCC_CONTROL", self.SCC_BUS, values)
-
- def _button_msg(self, buttons, main_button=0, bus=None):
- if bus is None:
- bus = self.PT_BUS
- values = {
- "CRUISE_BUTTONS": buttons,
- "ADAPTIVE_CRUISE_MAIN_BTN": main_button,
- }
- return self.packer.make_can_msg_safety("CRUISE_BUTTONS", bus, values)
-
- def _acc_state_msg(self, enable):
- values = {"MainMode_ACC": enable}
- return self.packer.make_can_msg_safety("SCC_CONTROL", self.SCC_BUS, values)
-
- def _lkas_button_msg(self, enabled):
- values = {"LDA_BTN": enabled}
- return self.packer.make_can_msg_safety("CRUISE_BUTTONS", self.PT_BUS, values)
-
- def _main_cruise_button_msg(self, enabled):
- return self._button_msg(0, enabled)
-
-
-class TestHyundaiCanfdLFASteeringBase(TestHyundaiCanfdBase):
-
- TX_MSGS = [[0x12A, 0], [0x1A0, 1], [0x1CF, 0], [0x1E0, 0]]
- RELAY_MALFUNCTION_ADDRS = {0: (0x12A, 0x1E0)} # LFA, LFAHDA_CLUSTER
- FWD_BLACKLISTED_ADDRS = {2: [0x12A, 0x1E0]}
-
- STEER_MSG = "LFA"
- BUTTONS_TX_BUS = 2
- SAFETY_PARAM: int
-
- @classmethod
- def setUpClass(cls):
- super().setUpClass()
- if cls.__name__ in ("TestHyundaiCanfdLFASteering", "TestHyundaiCanfdLFASteeringAltButtons"):
- cls.packer = None
- cls.safety = None
- raise unittest.SkipTest
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_canfd_generated")
- self.safety = libsafety_py.libsafety
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, self.SAFETY_PARAM)
- self.safety.init_tests()
-
-
-@parameterized_class(ALL_GAS_EV_HYBRID_COMBOS)
-class TestHyundaiCanfdLFASteering(TestHyundaiCanfdLFASteeringBase):
- pass
-
-
-class TestHyundaiCanfdLFASteeringAltButtonsBase(TestHyundaiCanfdLFASteeringBase):
-
- SAFETY_PARAM: int
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_canfd_generated")
- self.safety = libsafety_py.libsafety
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, HyundaiSafetyFlags.CANFD_ALT_BUTTONS | self.SAFETY_PARAM)
- self.safety.init_tests()
-
- def _button_msg(self, buttons, main_button=0, bus=1):
- values = {
- "CRUISE_BUTTONS": buttons,
- "ADAPTIVE_CRUISE_MAIN_BTN": main_button,
- }
- return self.packer.make_can_msg_safety("CRUISE_BUTTONS_ALT", self.PT_BUS, values)
-
- def _lkas_button_msg(self, enabled):
- values = {"LDA_BTN": enabled}
- return self.packer.make_can_msg_safety("CRUISE_BUTTONS_ALT", self.PT_BUS, values)
-
- def _acc_cancel_msg(self, cancel, accel=0):
- values = {"ACCMode": 4 if cancel else 0, "aReqRaw": accel, "aReqValue": accel}
- return self.packer.make_can_msg_safety("SCC_CONTROL", self.PT_BUS, values)
-
- def test_button_sends(self):
- """
- No button send allowed with alt buttons.
- """
- for enabled in (True, False):
- for btn in range(8):
- self.safety.set_controls_allowed(enabled)
- self.assertFalse(self._tx(self._button_msg(btn)))
-
- def test_acc_cancel(self):
- # FIXME: the CANFD_ALT_BUTTONS cars are the only ones that use SCC_CONTROL to cancel, why can't we use buttons?
- for enabled in (True, False):
- self.safety.set_controls_allowed(enabled)
- self.assertTrue(self._tx(self._acc_cancel_msg(True)))
- self.assertFalse(self._tx(self._acc_cancel_msg(True, accel=1)))
- self.assertFalse(self._tx(self._acc_cancel_msg(False)))
-
-
-@parameterized_class(ALL_GAS_EV_HYBRID_COMBOS)
-class TestHyundaiCanfdLFASteeringAltButtons(TestHyundaiCanfdLFASteeringAltButtonsBase):
- pass
-
-
-class TestHyundaiCanfdLKASteeringEV(TestHyundaiCanfdBase):
-
- TX_MSGS = [[0x50, 0], [0x1CF, 1], [0x2A4, 0]]
- RELAY_MALFUNCTION_ADDRS = {0: (0x50, 0x2a4)} # LKAS, CAM_0x2A4
- FWD_BLACKLISTED_ADDRS = {2: [0x50, 0x2a4]}
-
- PT_BUS = 1
- SCC_BUS = 1
- STEER_MSG = "LKAS"
- GAS_MSG = ("ACCELERATOR", "ACCELERATOR_PEDAL")
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_canfd_generated")
- self.safety = libsafety_py.libsafety
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, HyundaiSafetyFlags.CANFD_LKA_STEERING | HyundaiSafetyFlags.EV_GAS)
- self.safety.init_tests()
-
-
-# TODO: Handle ICE and HEV configurations once we see cars that use the new messages
-class TestHyundaiCanfdLKASteeringAltEV(TestHyundaiCanfdBase):
-
- TX_MSGS = [[0x110, 0], [0x1CF, 1], [0x362, 0]]
- RELAY_MALFUNCTION_ADDRS = {0: (0x110, 0x362)} # LKAS_ALT, CAM_0x362
- FWD_BLACKLISTED_ADDRS = {2: [0x110, 0x362]}
-
- PT_BUS = 1
- SCC_BUS = 1
- STEER_MSG = "LKAS_ALT"
- GAS_MSG = ("ACCELERATOR", "ACCELERATOR_PEDAL")
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_canfd_generated")
- self.safety = libsafety_py.libsafety
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, HyundaiSafetyFlags.CANFD_LKA_STEERING | HyundaiSafetyFlags.EV_GAS |
- HyundaiSafetyFlags.CANFD_LKA_STEERING_ALT)
- self.safety.init_tests()
-
-
-class TestHyundaiCanfdLKASteeringLongEV(HyundaiLongitudinalBase, TestHyundaiCanfdLKASteeringEV):
-
- TX_MSGS = [[0x50, 0], [0x1CF, 1], [0x2A4, 0], [0x51, 0], [0x730, 1], [0x12a, 1], [0x160, 1],
- [0x1e0, 1], [0x1a0, 1], [0x1ea, 1], [0x200, 1], [0x345, 1], [0x1da, 1]]
-
- RELAY_MALFUNCTION_ADDRS = {0: (0x50, 0x2a4), 1: (0x1a0,)} # LKAS, CAM_0x2A4, SCC_CONTROL
-
- DISABLED_ECU_UDS_MSG = (0x730, 1)
- DISABLED_ECU_ACTUATION_MSG = (0x1a0, 1)
-
- STEER_MSG = "LFA"
- GAS_MSG = ("ACCELERATOR", "ACCELERATOR_PEDAL")
- STEER_BUS = 1
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_canfd_generated")
- self.safety = libsafety_py.libsafety
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, HyundaiSafetyFlags.CANFD_LKA_STEERING |
- HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.EV_GAS)
- self.safety.init_tests()
-
- def _accel_msg(self, accel, aeb_req=False, aeb_decel=0):
- values = {
- "aReqRaw": accel,
- "aReqValue": accel,
- }
- return self.packer.make_can_msg_safety("SCC_CONTROL", self.PT_BUS, values)
-
- def _tx_acc_state_msg(self, enable):
- values = {"MainMode_ACC": enable}
- return self.packer.make_can_msg_safety("SCC_CONTROL", self.PT_BUS, values)
-
-
-# Tests longitudinal for ICE, hybrid, EV cars with LFA steering
-class TestHyundaiCanfdLFASteeringLongBase(HyundaiLongitudinalBase, TestHyundaiCanfdLFASteeringBase):
-
- FWD_BLACKLISTED_ADDRS = {2: [0x12a, 0x1e0, 0x1a0, 0x160]}
-
- RELAY_MALFUNCTION_ADDRS = {0: (0x12A, 0x1E0, 0x1a0, 0x160)} # LFA, LFAHDA_CLUSTER, SCC_CONTROL, ADRV_0x160
-
- DISABLED_ECU_UDS_MSG = (0x7D0, 0)
- DISABLED_ECU_ACTUATION_MSG = (0x1a0, 0)
-
- @classmethod
- def setUpClass(cls):
- if cls.__name__ == "TestHyundaiCanfdLFASteeringLongBase":
- cls.safety = None
- raise unittest.SkipTest
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_canfd_generated")
- self.safety = libsafety_py.libsafety
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, HyundaiSafetyFlags.LONG | self.SAFETY_PARAM)
- self.safety.init_tests()
-
- def _accel_msg(self, accel, aeb_req=False, aeb_decel=0):
- values = {
- "aReqRaw": accel,
- "aReqValue": accel,
- }
- return self.packer.make_can_msg_safety("SCC_CONTROL", self.PT_BUS, values)
-
- def _tx_acc_state_msg(self, enable):
- values = {"MainMode_ACC": enable}
- return self.packer.make_can_msg_safety("SCC_CONTROL", self.PT_BUS, values)
-
- # no knockout
- def test_tester_present_allowed(self):
- pass
-
-
-@parameterized_class(ALL_GAS_EV_HYBRID_COMBOS)
-class TestHyundaiCanfdLFASteeringLong(TestHyundaiCanfdLFASteeringLongBase):
- @classmethod
- def setUpClass(cls):
- if cls.__name__ == "TestHyundaiCanfdLFASteeringLong":
- cls.safety = None
- raise unittest.SkipTest
-
-
-@parameterized_class(ALL_GAS_EV_HYBRID_COMBOS)
-class TestHyundaiCanfdLFASteeringLongAltButtons(TestHyundaiCanfdLFASteeringLongBase, TestHyundaiCanfdLFASteeringAltButtonsBase):
- @classmethod
- def setUpClass(cls):
- if cls.__name__ == "TestHyundaiCanfdLFASteeringLongAltButtons":
- cls.safety = None
- raise unittest.SkipTest
-
- def setUp(self):
- self.packer = CANPackerSafety("hyundai_canfd_generated")
- self.safety = libsafety_py.libsafety
- self.safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.CANFD_ALT_BUTTONS | self.SAFETY_PARAM)
- self.safety.init_tests()
-
- def test_acc_cancel(self):
- # Alt buttons does not use SCC_CONTROL to cancel if longitudinal
- pass
-
-
-if __name__ == "__main__":
- unittest.main()
+@pytest.fixture
+def safety():
+ return libsafety_py.libsafety
+
+
+@pytest.mark.parametrize("param", (
+ 0,
+ HyundaiSafetyFlags.EV_GAS,
+ HyundaiSafetyFlags.HYBRID_GAS,
+ HyundaiSafetyFlags.LONG,
+ HyundaiSafetyFlags.CAMERA_SCC,
+ HyundaiSafetyFlags.CANFD_LKA_STEERING,
+ HyundaiSafetyFlags.CANFD_ALT_BUTTONS,
+ HyundaiSafetyFlags.CANFD_LKA_STEERING | HyundaiSafetyFlags.CANFD_LKA_STEERING_ALT,
+ HyundaiSafetyFlags.CANFD_LKA_STEERING | HyundaiSafetyFlags.LONG,
+ HyundaiSafetyFlags.CANFD_LKA_STEERING | HyundaiSafetyFlags.LONG | HyundaiSafetyFlags.CANFD_ALT_BUTTONS,
+))
+def test_canfd_safety_configurations_initialize(safety, param):
+ assert safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, param) == 0
+ safety.init_tests()
+ assert safety.get_current_safety_param() == param
+
+
+@pytest.mark.parametrize(("param", "addr", "length"), (
+ (0, 0x12A, 16),
+ (HyundaiSafetyFlags.CANFD_LKA_STEERING, 0x50, 16),
+ (HyundaiSafetyFlags.CANFD_LKA_STEERING | HyundaiSafetyFlags.CANFD_LKA_STEERING_ALT, 0x110, 32),
+ (HyundaiSafetyFlags.CANFD_LKA_STEERING | HyundaiSafetyFlags.LONG, 0x12A, 16),
+))
+def test_canfd_steering_limits(safety, param, addr, length):
+ safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, param)
+ safety.init_tests()
+
+ safety.set_controls_allowed(False)
+ assert safety.safety_tx_hook(canfd_steer(addr, length, 0, False))
+ assert not safety.safety_tx_hook(canfd_steer(addr, length, 1))
+
+ safety.set_controls_allowed(True)
+ assert safety.safety_tx_hook(canfd_steer(addr, length, 10))
+ safety.set_desired_torque_last(512)
+ safety.set_rt_torque_last(512)
+ assert safety.safety_tx_hook(canfd_steer(addr, length, 512))
+ assert not safety.safety_tx_hook(canfd_steer(addr, length, 513))
+ assert not safety.safety_tx_hook(canfd_steer(addr, length, -513))
+
+
+def test_canfd_tx_whitelist_and_buttons(safety):
+ safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, 0)
+ safety.init_tests()
+ assert not safety.safety_tx_hook(packet(0x123, 0, 8))
+ assert not safety.safety_tx_hook(packet(0x12A, 1, 16))
+
+ safety.set_controls_allowed(False)
+ assert not safety.safety_tx_hook(packet(0x1CF, 0, 8, {2: 1}))
+ assert not safety.safety_tx_hook(packet(0x1CF, 0, 8, {2: 2}))
+ assert not safety.safety_tx_hook(packet(0x1CF, 0, 8, {2: 4}))
+
+ safety.set_controls_allowed(True)
+ assert safety.safety_tx_hook(packet(0x1CF, 0, 8, {2: 1}))
+ assert not safety.safety_tx_hook(packet(0x1CF, 0, 8, {2: 2}))
+ assert safety.safety_tx_hook(packet(0x1CF, 0, 8, {2: 4}))
+
+ safety.set_controls_allowed(False)
+ safety.set_cruise_engaged_prev(True)
+ assert safety.safety_tx_hook(packet(0x1CF, 0, 8, {2: 4}))
+
+
+def test_canfd_stock_longitudinal_only_allows_cancel(safety):
+ safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, 0)
+ safety.init_tests()
+ assert safety.safety_tx_hook(canfd_accel(0, acc_mode=4))
+ assert not safety.safety_tx_hook(canfd_accel(1, acc_mode=4))
+ assert not safety.safety_tx_hook(canfd_accel(0, acc_mode=0))
+
+
+def test_canfd_longitudinal_accel_limits(safety):
+ safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, HyundaiSafetyFlags.LONG)
+ safety.init_tests()
+
+ safety.set_controls_allowed(False)
+ assert safety.safety_tx_hook(canfd_accel(0))
+ assert not safety.safety_tx_hook(canfd_accel(1))
+
+ safety.set_controls_allowed(True)
+ for accel in (-400, 0, 250):
+ assert safety.safety_tx_hook(canfd_accel(accel))
+ for accel in (-401, 251):
+ assert not safety.safety_tx_hook(canfd_accel(accel))
+
+
+def test_canfd_hda2_diagnostic_payload_is_restricted(safety):
+ param = HyundaiSafetyFlags.CANFD_LKA_STEERING | HyundaiSafetyFlags.LONG
+ safety.set_safety_hooks(CarParams.SafetyModel.hyundaiCanfd, param)
+ safety.init_tests()
+ assert safety.safety_tx_hook(packet(0x730, 1, 8, dict(enumerate(TESTER_PRESENT))))
+ assert not safety.safety_tx_hook(packet(0x730, 1, 8, {0: 3, 1: 0x22}))
diff --git a/iqdbc_repo/iqdbc/safety/tests/test_hyundai_controller.py b/iqdbc_repo/iqdbc/safety/tests/test_hyundai_controller.py
new file mode 100644
index 0000000..71c14b5
--- /dev/null
+++ b/iqdbc_repo/iqdbc/safety/tests/test_hyundai_controller.py
@@ -0,0 +1,39 @@
+import pytest
+
+from iqdbc.car import gen_empty_fingerprint, structs
+from iqdbc.car.hyundai.interface import CarInterface
+from iqdbc.car.hyundai.values import CAR
+from iqdbc.safety.tests.libsafety import libsafety_py
+
+
+@pytest.mark.parametrize("candidate", list(CAR), ids=lambda candidate: candidate.value)
+@pytest.mark.parametrize("alpha_long", (False, True), ids=("stock_long", "openpilot_long"))
+def test_controller_frames_match_configured_safety(candidate, alpha_long, monkeypatch, tmp_path):
+ """Run real controller output through the safety configuration selected for every HKG platform."""
+ monkeypatch.setenv("PARAMS_ROOT", str(tmp_path / candidate.value))
+ fingerprint = gen_empty_fingerprint()
+ cp = CarInterface.get_params(candidate, fingerprint, [], alpha_long, False, False)
+ cp_iq = CarInterface.get_params_iq(cp, candidate, fingerprint, [], alpha_long, False, False)
+ interface = CarInterface(cp, cp_iq)
+ interface.update([])
+
+ safety_config = cp.safetyConfigs[-1]
+ safety = libsafety_py.libsafety
+ assert safety.set_safety_hooks(safety_config.safetyModel.raw, safety_config.safetyParam) == 0
+ safety.init_tests()
+ safety.set_controls_allowed(True)
+
+ control = structs.CarControl.new_message()
+ control.enabled = True
+ control.latActive = True
+ control.longActive = alpha_long
+ control.actuators.torque = 0.01
+ control.actuators.accel = 0.0
+
+ for frame in range(20):
+ _, can_sends = interface.apply(control.as_reader(), structs.IQCarControl())
+ assert isinstance(can_sends, list)
+ for address, data, bus in can_sends:
+ packet = libsafety_py.make_CANPacket(address, bus, data)
+ rejection = f"{candidate.value} frame {frame}: safety rejected address={address:#x} bus={bus} data={data.hex()}"
+ assert safety.safety_tx_hook(packet), rejection
diff --git a/iqdbc_repo/iqdbc/safety/tests/test_nissan.py b/iqdbc_repo/iqdbc/safety/tests/test_nissan.py
index 30b2047..fe09fa0 100755
--- a/iqdbc_repo/iqdbc/safety/tests/test_nissan.py
+++ b/iqdbc_repo/iqdbc/safety/tests/test_nissan.py
@@ -2,8 +2,10 @@
import unittest
from iqdbc.car.nissan.values import NissanSafetyFlags
-from iqdbc.lvbs.car.nissan.values import NissanSafetyFlagsIQ
from iqdbc.car.structs import CarParams
+
+# NISSAN_PARAM_IQ_LEAF in safety/modes/nissan.h (IQ safety framework flag)
+NISSAN_PARAM_IQ_LEAF = 1
from iqdbc.safety.tests.libsafety import libsafety_py
import iqdbc.safety.tests.common as common
from iqdbc.safety.tests.common import CANPackerSafety
@@ -105,7 +107,7 @@ class TestNissanLeafSafety(TestNissanSafety):
def setUp(self):
self.packer = CANPackerSafety("nissan_leaf_2018_generated")
self.safety = libsafety_py.libsafety
- self.safety.set_current_safety_param_iq(NissanSafetyFlagsIQ.LEAF)
+ self.safety.set_current_safety_param_iq(NISSAN_PARAM_IQ_LEAF)
self.safety.set_safety_hooks(CarParams.SafetyModel.nissan, 0)
self.safety.init_tests()
diff --git a/iqdbc_repo/iqdbc/safety/tests/test_tesla.py b/iqdbc_repo/iqdbc/safety/tests/test_tesla.py
index 49432aa..cde2451 100755
--- a/iqdbc_repo/iqdbc/safety/tests/test_tesla.py
+++ b/iqdbc_repo/iqdbc/safety/tests/test_tesla.py
@@ -11,8 +11,7 @@ except ImportError:
pytest.skip("requires openpilot dependencies", allow_module_level=True)
from iqdbc.car.lateral import get_max_angle_delta_vm, get_max_angle_vm
-from iqdbc.car.tesla.teslacan import get_steer_ctrl_type
-from iqdbc.car.tesla.values import CarControllerParams, TeslaSafetyFlags, TeslaFlags, CANBUS
+from iqdbc.car.tesla.values import CarControllerParams, TeslaSafetyFlags, CANBUS
from iqdbc.car.structs import CarParams
from iqdbc.car.vehicle_model import VehicleModel
from iqdbc.can import CANDefine
@@ -23,6 +22,7 @@ from iqdbc.safety.tests.common import CANPackerSafety, MAX_SPEED_DELTA, MAX_WRON
MSG_DAS_steeringControl = 0x488
MSG_APS_eacMonitor = 0x27d
MSG_DAS_Control = 0x2b9
+MSG_DAS_bodyControls = 0x3E9
def round_angle(apply_angle, can_offset=0):
@@ -34,6 +34,7 @@ def round_angle(apply_angle, can_offset=0):
class TestTeslaSafetyBase(common.CarSafetyTest, common.AngleSteeringSafetyTest, common.LongitudinalAccelSafetyTest):
SAFETY_PARAM = 0
+ STEER_TYPE_SHIFT = 0 # legacy firmware uses a 2-bit field, one bit up from the 3-bit signal
RELAY_MALFUNCTION_ADDRS = {0: (MSG_DAS_steeringControl, MSG_APS_eacMonitor)}
FWD_BLACKLISTED_ADDRS = {2: [MSG_DAS_steeringControl, MSG_APS_eacMonitor]}
@@ -83,11 +84,7 @@ class TestTeslaSafetyBase(common.CarSafetyTest, common.AngleSteeringSafetyTest,
self.safety.init_tests()
def _angle_cmd_msg(self, angle: float, state: bool | int, increment_timer: bool = True, bus: int = 0):
- # If FSD 14, translate steer control type to new flipped definition
- if self.safety.get_current_safety_param() & TeslaSafetyFlags.FSD_14:
- state = get_steer_ctrl_type(TeslaFlags.FSD_14, int(state))
-
- values = {"DAS_steeringAngleRequest": angle, "DAS_steeringControlType": state}
+ values = {"DAS_steeringAngleRequest": angle, "DAS_steeringControlType": int(state) << self.STEER_TYPE_SHIFT}
if increment_timer:
self.safety.set_timer(self.cnt_angle_cmd * int(1e6 / self.LATERAL_FREQUENCY))
self.__class__.cnt_angle_cmd += 1
@@ -407,8 +404,9 @@ class TestTeslaStockSafety(TestTeslaSafetyBase):
self.assertFalse(self._tx(no_aeb_msg))
-class TestTeslaFSD14StockSafety(TestTeslaStockSafety):
- SAFETY_PARAM = TeslaSafetyFlags.FSD_14
+class TestTeslaLegacyDasSteeringStockSafety(TestTeslaStockSafety):
+ SAFETY_PARAM = TeslaSafetyFlags.LEGACY_DAS_STEERING
+ STEER_TYPE_SHIFT = 1
class TestTeslaLongitudinalSafety(TestTeslaSafetyBase):
@@ -459,14 +457,18 @@ class TestTeslaLongitudinalSafety(TestTeslaSafetyBase):
self.assertFalse(self._tx(self._long_control_msg(set_speed=0, accel_limits=(-0.1, -0.1))))
-class TestTeslaFSD14LongitudinalSafety(TestTeslaLongitudinalSafety):
- SAFETY_PARAM = TeslaSafetyFlags.LONG_CONTROL | TeslaSafetyFlags.FSD_14
+class TestTeslaLegacyDasSteeringLongitudinalSafety(TestTeslaLongitudinalSafety):
+ SAFETY_PARAM = TeslaSafetyFlags.LONG_CONTROL | TeslaSafetyFlags.LEGACY_DAS_STEERING
+ STEER_TYPE_SHIFT = 1
class TestTeslaVehicleBusSafety(TestTeslaSafetyBase):
LONGITUDINAL = False
+ # With the vehicle bus harness, DAS_bodyControls is also TX'd on bus 1 (blinker MITM)
+ TX_MSGS = [*TestTeslaSafetyBase.TX_MSGS, [MSG_DAS_bodyControls, 1]]
+
def setUp(self):
super().setUp()
self.safety = libsafety_py.libsafety
diff --git a/iqdbc_repo/iqdbc/safety/tests/test_volkswagen_pq.py b/iqdbc_repo/iqdbc/safety/tests/test_volkswagen_pq.py
index 85f6564..c6ca4b8 100755
--- a/iqdbc_repo/iqdbc/safety/tests/test_volkswagen_pq.py
+++ b/iqdbc_repo/iqdbc/safety/tests/test_volkswagen_pq.py
@@ -20,6 +20,7 @@ MSG_ACC_GRA_ANZEIGE = 0x56A # TX by OP, ACC HUD
MSG_LDW_1 = 0x5BE # TX by OP, Lane line recognition and text alerts
MSG_BLINKMODI_02 = 0x0AA # TX by OP, turn signal control
MSG_APD_1 = 0x3D6 # TX by OP, CarParams
+MSG_IQ = 0x6A1 # TX by OP
class TestVolkswagenPqSafetyBase(common.CarSafetyTest):
@@ -43,7 +44,7 @@ class TestVolkswagenPqSafetyBase(common.CarSafetyTest):
# Ego speed (Bremse_1)
def _speed_msg(self, speed):
values = {"BR1_Rad_kmh": speed}
- return self.packer.make_can_msg_safety("Bremse_1", 0, values)
+ return self.packer.make_can_msg_safety("Bremse_1", 1, values)
# Brake light switch (shared message Motor_2)
def _user_brake_msg(self, brake):
@@ -63,7 +64,7 @@ class TestVolkswagenPqSafetyBase(common.CarSafetyTest):
# Driver steering input torque
def _torque_driver_msg(self, torque):
values = {"LH3_LM": abs(torque), "LH3_LMSign": torque < 0}
- return self.packer.make_can_msg_safety("Lenkhilfe_3", 0, values)
+ return self.packer.make_can_msg_safety("Lenkhilfe_3", 1, values)
# openpilot steering output torque
def _torque_cmd_msg(self, torque, steer_req=1, hca_status=7):
@@ -76,17 +77,17 @@ class TestVolkswagenPqSafetyBase(common.CarSafetyTest):
values = {"MO2_BLS": brake_pressed,
"MO2_Sta_GRA": cruise_engaged,
"MO2_Status_TSK": tsk_status}
- return self.packer.make_can_msg_safety("Motor_2", 0, values)
+ return self.packer.make_can_msg_safety("Motor_2", 1, values)
# ACC main switch status
def _motor_5_msg(self, main_switch=False):
values = {"MO5_GRA_Hauptsch": main_switch}
- return self.packer.make_can_msg_safety("Motor_5", 0, values)
+ return self.packer.make_can_msg_safety("Motor_5", 1, values)
# Driver throttle input (Motor_3)
def _user_gas_msg(self, gas):
values = {"MO3_Pedalwert": gas}
- return self.packer.make_can_msg_safety("Motor_3", 0, values)
+ return self.packer.make_can_msg_safety("Motor_3", 1, values)
# Cruise control buttons (GRA_Neu)
def _button_msg(self, _set=False, resume=False, cancel=False, bus=2):
@@ -116,7 +117,7 @@ class TestVolkswagenPqSafetyBase(common.CarSafetyTest):
class TestVolkswagenPqStockSafety(TestVolkswagenPqSafetyBase):
# Transmit of GRA_Neu is allowed on bus 0/1/2 to keep compatibility with gateway and camera integration
- TX_MSGS = [[MSG_HCA_1, 0], [MSG_GRA_NEU, 0], [MSG_GRA_NEU, 1], [MSG_GRA_NEU, 2], [MSG_LDW_1, 0], [MSG_BLINKMODI_02, 0], [MSG_APD_1, 1]]
+ TX_MSGS = [[MSG_HCA_1, 0], [MSG_GRA_NEU, 0], [MSG_GRA_NEU, 1], [MSG_GRA_NEU, 2], [MSG_LDW_1, 0], [MSG_BLINKMODI_02, 0], [MSG_APD_1, 1], [MSG_IQ, 1]]
FWD_BLACKLISTED_ADDRS = {2: [MSG_HCA_1, MSG_LDW_1]}
def setUp(self):
@@ -139,11 +140,11 @@ class TestVolkswagenPqLongSafety(TestVolkswagenPqSafetyBase, common.Longitudinal
tsk_status = True
TX_MSGS = [[MSG_HCA_1, 0], [MSG_LDW_1, 0], [MSG_ACC_SYSTEM, 0], [MSG_ACC_GRA_ANZEIGE, 0],
- [MSG_GRA_NEU, 1], [MSG_GRA_NEU, 2], [MSG_BLINKMODI_02, 0], [MSG_MOTOR_2, 2], [MSG_APD_1, 1]]
- FWD_BLACKLISTED_ADDRS = {0: [MSG_MOTOR_2, MSG_GRA_NEU],
+ [MSG_GRA_NEU, 1], [MSG_GRA_NEU, 2], [MSG_BLINKMODI_02, 0], [MSG_MOTOR_2, 2], [MSG_MOTOR_5, 2], [MSG_APD_1, 1], [MSG_IQ, 1]]
+ FWD_BLACKLISTED_ADDRS = {0: [MSG_MOTOR_2, MSG_MOTOR_5, MSG_GRA_NEU],
2: [MSG_HCA_1, MSG_LDW_1, MSG_ACC_SYSTEM, MSG_ACC_GRA_ANZEIGE]}
RELAY_MALFUNCTION_ADDRS = {0: (MSG_HCA_1, MSG_LDW_1, MSG_ACC_SYSTEM, MSG_ACC_GRA_ANZEIGE),
- 2: (MSG_MOTOR_2, MSG_GRA_NEU)}
+ 2: (MSG_MOTOR_2, MSG_GRA_NEU, MSG_MOTOR_5)}
INACTIVE_ACCEL = 3.01
def setUp(self):
@@ -168,20 +169,20 @@ class TestVolkswagenPqLongSafety(TestVolkswagenPqSafetyBase, common.Longitudinal
# ACC main switch must be on, engage on falling edge
self.safety.set_controls_allowed(0)
self._rx(self._motor_5_msg(main_switch=False))
- self._rx(self._button_msg(_set=(button == "set"), resume=(button == "resume"), bus=0))
- self._rx(self._button_msg(bus=0))
+ self._rx(self._button_msg(_set=(button == "set"), resume=(button == "resume"), bus=1))
+ self._rx(self._button_msg(bus=1))
self.assertFalse(self.safety.get_controls_allowed(), f"controls allowed on {button} with main switch off")
self._rx(self._motor_5_msg(main_switch=True))
- self._rx(self._button_msg(_set=(button == "set"), resume=(button == "resume"), bus=0))
+ self._rx(self._button_msg(_set=(button == "set"), resume=(button == "resume"), bus=1))
self.assertFalse(self.safety.get_controls_allowed(), f"controls allowed on {button} rising edge")
- self._rx(self._button_msg(bus=0))
+ self._rx(self._button_msg(bus=1))
self.assertTrue(self.safety.get_controls_allowed(), f"controls not allowed on {button} falling edge")
def test_cancel_button(self):
# Disable on rising edge of cancel button
self._rx(self._motor_5_msg(main_switch=True))
self.safety.set_controls_allowed(1)
- self._rx(self._button_msg(cancel=True, bus=0))
+ self._rx(self._button_msg(cancel=True, bus=1))
self.assertFalse(self.safety.get_controls_allowed(), "controls allowed after cancel")
def test_main_switch(self):
@@ -223,8 +224,8 @@ class TestVolkswagenPqLongSafety(TestVolkswagenPqSafetyBase, common.Longitudinal
self.safety.set_controls_allowed(0)
self._rx(self._motor_5_msg(main_switch=False))
self._rx(self._motor_2_msg(tsk_status=True))
- self._rx(self._button_msg(_set=(button == "set"), resume=(button == "resume"), bus=0))
- self._rx(self._button_msg(bus=0))
+ self._rx(self._button_msg(_set=(button == "set"), resume=(button == "resume"), bus=1))
+ self._rx(self._button_msg(bus=1))
self.assertTrue(self.safety.get_controls_allowed(), f"controls not allowed on {button} falling edge with TSK ready")
def test_torque_cmd_enable_variants(self):
@@ -250,5 +251,42 @@ class TestVolkswagenPqLongSafety(TestVolkswagenPqSafetyBase, common.Longitudinal
self.safety.set_controls_allowed(True)
self.assertTrue(self._tx(self._accel_msg(0.5)))
+
+class TestVolkswagenPqLowlineSafety(TestVolkswagenPqSafetyBase):
+ """Non-ECAN lateral-only PQ cars: bus 0 dead, TX on bus 1 (ptCAN) directly to EPS."""
+ TX_MSGS = [[MSG_HCA_1, 1], [MSG_GRA_NEU, 1], [MSG_GRA_NEU, 2], [MSG_LDW_1, 1], [MSG_BLINKMODI_02, 1], [MSG_APD_1, 1], [MSG_IQ, 1]]
+ FWD_BUS_LOOKUP = {2: 0}
+ FWD_BLACKLISTED_ADDRS = {}
+ RELAY_MALFUNCTION_ADDRS = {1: (MSG_HCA_1, MSG_LDW_1)}
+
+ def setUp(self):
+ self.packer = CANPackerSafety("vw_pq")
+ self.safety = libsafety_py.libsafety
+ self.safety.set_safety_hooks(CarParams.SafetyModel.volkswagenPq, VolkswagenSafetyFlags.PQ_LOWLINE | VolkswagenSafetyFlags.PQ_NO_CAM_BUS)
+ self.safety.init_tests()
+
+ def _torque_cmd_msg(self, torque, steer_req=1, hca_status=7):
+ values = {"LM_Offset": abs(torque), "LM_OffSign": torque < 0, "HCA_Status": hca_status if steer_req else 3}
+ return self.packer.make_can_msg_safety("HCA_1", 1, values)
+
+ def test_spam_cancel_safety_check(self):
+ self.safety.set_controls_allowed(0)
+ self.assertTrue(self._tx(self._button_msg(cancel=True)))
+ self.assertFalse(self._tx(self._button_msg(resume=True)))
+ self.assertFalse(self._tx(self._button_msg(_set=True)))
+ self.safety.set_controls_allowed(1)
+ self.assertTrue(self._tx(self._button_msg(resume=True)))
+
+
+class TestVolkswagenPqNoCamSafety(TestVolkswagenPqStockSafety):
+ FWD_BUS_LOOKUP = {2: 0}
+
+ def setUp(self):
+ self.packer = CANPackerSafety("vw_pq")
+ self.safety = libsafety_py.libsafety
+ self.safety.set_safety_hooks(CarParams.SafetyModel.volkswagenPq, VolkswagenSafetyFlags.PQ_NO_CAM_BUS)
+ self.safety.init_tests()
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/iqdbc_repo/lefthook.yml b/iqdbc_repo/lefthook.yml
deleted file mode 100644
index 079b1f4..0000000
--- a/iqdbc_repo/lefthook.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-output:
- - meta # Print lefthook version
- - summary # Print summary block (successful and failed steps)
- - empty_summary # Print summary heading when there are no steps to run
- - success # Print successful steps
- - failure # Print failed steps printing
- - execution # Print any execution logs
- #- execution_out # Print execution output
- #- execution_info # Print `EXECUTE > ...` logging
- - skips # Print "skip" (i.e. no files matched)
-
-test:
- parallel: true
- commands:
- # *** static analysis
- ruff:
- run: ruff check .
- ty:
- run: ty check
- codespell:
- run: codespell {files} -L tge,stdio -S *.dbc --ignore-words=.codespellignore
- files: git ls-tree -r HEAD --name-only
- cpplint:
- run: cpplint --exclude=iqdbc/safety/tests/misra/cppcheck/ --exclude=iqdbc/can/*_pyx.cpp --recursive --quiet --counting=detailed --linelength=240 --filter=-build,-legal,-readability,-runtime,-whitespace,+build/include_subdir,+build/forward_decl,+build/include_what_you_use,+build/deprecated,+whitespace/comma,+whitespace/line_length,+whitespace/empty_if_body,+whitespace/empty_loop_body,+whitespace/empty_conditional_body,+whitespace/forcolon,+whitespace/parens,+whitespace/semicolon,+whitespace/tab,+readability/braces iqdbc/
- misra:
- run: iqdbc/safety/tests/misra/test_misra.sh
-
- # *** tests ***
- pytest:
- run: pytest -n8
diff --git a/iqdbc_repo/pyproject.toml b/iqdbc_repo/pyproject.toml
index e1fd92f..1806468 100644
--- a/iqdbc_repo/pyproject.toml
+++ b/iqdbc_repo/pyproject.toml
@@ -3,11 +3,11 @@ name = "iqdbc"
version = "0.2.1"
description = "CAN bus databases and tools"
license = "MIT"
-authors = [{ name = "Vehicle Researcher", email = "user@comma.ai" }]
+authors = [{ name = "IQ.Lvbs", email = "team@iqlvbs.com" }]
readme = "README.md"
requires-python = ">=3.11,<3.13" # pycapnp doesn't work with 3.13
-urls = { "homepage" = "https://gitlvb.teallvbs.xyz/teal/iqdbc" }
+urls = { "homepage" = "https://git.konn3kt.com/teal/iqdbc" }
dependencies = [
"scons",
diff --git a/panda/SConscript b/panda/SConscript
index 164b7fd..56d73d9 100644
--- a/panda/SConscript
+++ b/panda/SConscript
@@ -20,9 +20,6 @@ else:
if os.getenv("DEBUG"):
common_flags += ["-DDEBUG"]
-def objcopy(source, target, env, for_signature):
- return '$OBJCOPY -O binary %s %s' % (source[0], target[0])
-
def get_version(builder, build_type):
try:
git = subprocess.check_output(["git", "rev-parse", "--short=8", "HEAD"], encoding='utf8').strip()
@@ -92,12 +89,20 @@ def build_project(project_name, project, main, extra_flags):
LINKFLAGS=flags,
CPPPATH=[Dir("./"), "./board/stm32f4/inc", "./board/stm32h7/inc", iqdbc.INCLUDE_PATH],
ASCOM="$AS $ASFLAGS -o $TARGET -c $SOURCES",
- BUILDERS={
- 'Objcopy': Builder(generator=objcopy, suffix='.bin', src_suffix='.elf')
- },
tools=["default", "compilation_db"],
)
+ # short colored build output shared with the top-level build (if present)
+ _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')
+ env.Append(BUILDERS={
+ 'Objcopy': Builder(action=env.PrettyAction('$OBJCOPY -O binary $SOURCE $TARGET', 'OBJCOPY'),
+ suffix='.bin', src_suffix='.elf')
+ })
+
startup = env.Object(project["STARTUP_FILE"])
# Build bootstub
@@ -118,7 +123,8 @@ def build_project(project_name, project, main, extra_flags):
], LINKFLAGS=[f"-Wl,--section-start,.isr_vector={project['APP_START_ADDRESS']}"] + flags)
main_bin = env.Objcopy(f"{project_dir}/main.bin", main_elf)
sign_py = File(f"./crypto/sign.py").srcnode().relpath
- env.Command(f"./board/obj/{project_name}.bin.signed", main_bin, f"SETLEN=1 {sign_py} $SOURCE $TARGET {cert_fn}")
+ env.Command(f"./board/obj/{project_name}.bin.signed", main_bin,
+ env.PrettyAction(f"SETLEN=1 {sign_py} $SOURCE $TARGET {cert_fn}", 'SIGN', logfile='/dev/null'))
diff --git a/panda/board/drivers/can_common.h b/panda/board/drivers/can_common.h
index af1f510..12de85a 100644
--- a/panda/board/drivers/can_common.h
+++ b/panda/board/drivers/can_common.h
@@ -138,9 +138,11 @@ bus_config_t bus_config[PANDA_CAN_CNT] = {
void can_init_all(void) {
for (uint8_t i=0U; i < PANDA_CAN_CNT; i++) {
bus_config[i].canfd_enabled = false;
- // Preserve can_data_speed (default 20000U = 2Mbps) through safety model changes.
- // Auto-detection in can_rx() sets canfd_enabled=true when the first FD frame arrives;
- // keeping data speed nonzero lets the FDCAN peripheral handle FD frames immediately.
+ // NOTE: do NOT reset can_data_speed here. Matching stock panda, can_init_all() only clears
+ // canfd_enabled (re-discovered on RX via canfd_auto). The old "#ifndef CANFD: can_data_speed = 0U"
+ // fired on every board because CANFD is never defined, zeroing the FD data-phase bitrate on every
+ // set_safety_model() -> CAN-FD frames then failed with form/stuff errors and never re-enabled,
+ // breaking all CAN-FD cars (e.g. Kia EV6) after fingerprinting. can_data_speed is only used by fdcan.
can_clear(can_queues[i]);
(void)can_init(i);
}
@@ -169,6 +171,7 @@ void ignition_can_hook(CANPacket_t *msg) {
static int tesla_gear = TESLA_DI_GEAR_P;
static int toyota_gear = TOYOTA_GEAR_P;
static int toyota_hybrid_gear = TOYOTA_HYBRID_GEAR_P;
+ static bool toyota_hybrid_gear_seen = false;
// GM exception
if ((msg->addr == 0x1F1U) && (len == 8)) {
@@ -218,8 +221,10 @@ void ignition_can_hook(CANPacket_t *msg) {
ignition_can_cnt = 0U;
}
- // Toyota/Lexus exception
- if ((msg->addr == 0x3BCU) && (len == 8)) {
+ // Toyota/Lexus exception. SecOC hybrids (e.g. Sienna 4th gen) report gear on
+ // GEAR_PACKET_HYBRID (0x127); their GEAR_PACKET (0x3BC) does not read Park, so once
+ // the hybrid gear packet is seen, don't let 0x3BC override it (Park -> ignition off).
+ if ((msg->addr == 0x3BCU) && (len == 8) && !toyota_hybrid_gear_seen) {
int gear = msg->data[1] & 0x3FU;
if ((gear == 0) || (gear == 1) || (gear == 8) || (gear == 16) || (gear == 32)) {
toyota_gear = gear;
@@ -231,24 +236,14 @@ void ignition_can_hook(CANPacket_t *msg) {
if ((msg->addr == 0x127U) && (len == 8)) {
int gear = (msg->data[5] >> 4U) & 0xFU;
if (gear <= 4) {
+ toyota_hybrid_gear_seen = true;
toyota_hybrid_gear = gear;
ignition_can = toyota_hybrid_gear != TOYOTA_HYBRID_GEAR_P;
ignition_can_cnt = 0U;
}
}
- // Volkswagen MEB exception
- if ((msg->addr == 0x3C0U) && (len == 4)) {
- int counter = msg->data[1] & 0xFU;
- static int prev_counter_vw_meb = -1;
- if ((counter == ((prev_counter_vw_meb + 1) % 16)) && (prev_counter_vw_meb != -1)) {
- // Klemmen_Status_01->ZAS_Kl_15
- ignition_can = ((msg->data[2] >> 1) & 1U) != 0U;
- ignition_can_cnt = 0U;
- }
- prev_counter_vw_meb = counter;
- }
}
}
diff --git a/panda/board/drivers/harness.h b/panda/board/drivers/harness.h
index 3ebf109..883cb32 100644
--- a/panda/board/drivers/harness.h
+++ b/panda/board/drivers/harness.h
@@ -14,8 +14,10 @@ void set_intercept_relay(bool intercept, bool ignition_relay) {
harness.relay_driven = true;
}
- // wait until we're not reading the analog voltages anymore
- while (harness.sbu_adc_lock) {}
+ // The relay pins are separate from the SBU sense pins, so no need to wait for
+ // orientation sampling: it runs in thread context, sees relay_driven set, and
+ // discards its result. Spinning on sbu_adc_lock here would deadlock when called
+ // from interrupt context while thread-context sampling holds the lock.
if (harness.status == HARNESS_STATUS_NORMAL) {
set_gpio_output(current_board->harness_config->GPIO_relay_SBU1, current_board->harness_config->pin_relay_SBU1, !ignition_relay);
@@ -31,20 +33,25 @@ void set_intercept_relay(bool intercept, bool ignition_relay) {
}
bool harness_check_ignition(void) {
- bool ret = false;
+ // The SBU pins are in analog mode while orientation sampling is in flight
+ // (thread context), so a digital read would return 0. Return the last good
+ // value instead of spinning: this is called from interrupt context, where
+ // waiting for preempted thread-context sampling to finish would deadlock.
+ bool ret = harness.ignition_line;
- // wait until we're not reading the analog voltages anymore
- while (harness.sbu_adc_lock) {}
-
- switch(harness.status){
- case HARNESS_STATUS_NORMAL:
- ret = !get_gpio_input(current_board->harness_config->GPIO_SBU1, current_board->harness_config->pin_SBU1);
- break;
- case HARNESS_STATUS_FLIPPED:
- ret = !get_gpio_input(current_board->harness_config->GPIO_SBU2, current_board->harness_config->pin_SBU2);
- break;
- default:
- break;
+ if (!harness.sbu_adc_lock) {
+ switch(harness.status){
+ case HARNESS_STATUS_NORMAL:
+ ret = !get_gpio_input(current_board->harness_config->GPIO_SBU1, current_board->harness_config->pin_SBU1);
+ break;
+ case HARNESS_STATUS_FLIPPED:
+ ret = !get_gpio_input(current_board->harness_config->GPIO_SBU2, current_board->harness_config->pin_SBU2);
+ break;
+ default:
+ ret = false;
+ break;
+ }
+ harness.ignition_line = ret;
}
return ret;
}
@@ -81,6 +88,12 @@ static uint8_t harness_detect_orientation(void) {
set_gpio_mode(current_board->harness_config->GPIO_SBU1, current_board->harness_config->pin_SBU1, MODE_INPUT);
set_gpio_mode(current_board->harness_config->GPIO_SBU2, current_board->harness_config->pin_SBU2, MODE_INPUT);
harness.sbu_adc_lock = false;
+
+ // This runs in thread context and can be preempted by an interrupt driving
+ // the relay mid-sample, which changes the SBU line voltages; discard
+ if (harness.relay_driven) {
+ ret = harness.status;
+ }
}
#endif
diff --git a/panda/board/drivers/harness_declarations.h b/panda/board/drivers/harness_declarations.h
index 6f4327a..6f7af28 100644
--- a/panda/board/drivers/harness_declarations.h
+++ b/panda/board/drivers/harness_declarations.h
@@ -4,12 +4,15 @@
#define HARNESS_STATUS_NORMAL 1U
#define HARNESS_STATUS_FLIPPED 2U
+// orientation sampling runs in thread context and shares this state with
+// interrupt handlers, so the fields are volatile
struct harness_t {
- uint8_t status;
- uint16_t sbu1_voltage_mV;
- uint16_t sbu2_voltage_mV;
- bool relay_driven;
- bool sbu_adc_lock;
+ volatile uint8_t status;
+ volatile uint16_t sbu1_voltage_mV;
+ volatile uint16_t sbu2_voltage_mV;
+ volatile bool ignition_line;
+ volatile bool relay_driven;
+ volatile bool sbu_adc_lock;
};
extern struct harness_t harness;
diff --git a/panda/board/main.c b/panda/board/main.c
index 0cfd708..8033ad6 100644
--- a/panda/board/main.c
+++ b/panda/board/main.c
@@ -117,6 +117,22 @@ static void __attribute__ ((noinline)) enable_fpu(void) {
#define HEARTBEAT_IGNITION_CNT_OFF 2U
// called at 8Hz
+static volatile bool tick_sample_pending = false;
+
+// All runtime ADC sampling runs here, in thread context. ADC conversions
+// busy-wait for tens to hundreds of microseconds, and all interrupts share one
+// NVIC priority: sampling in the 8Hz tick interrupt delayed the SPI slave's
+// RX DMA re-arm long enough for the host to clock into an unarmed peripheral
+// (checksum failures -> NACK retry storms -> multi-second CAN blackouts).
+static void tick_sample_poll(void) {
+ if (tick_sample_pending) {
+ tick_sample_pending = false;
+ harness_tick();
+ voltage_mV = current_board->read_voltage_mV();
+ current_mA = current_board->read_current_mA();
+ }
+}
+
static void tick_handler(void) {
static uint32_t siren_countdown = 0; // siren plays while countdown > 0
static uint32_t controls_allowed_countdown = 0;
@@ -131,7 +147,7 @@ static void tick_handler(void) {
// tick drivers at 8Hz
fan_tick();
- harness_tick();
+ tick_sample_pending = true; // ADC sampling deferred to thread context (see tick_sample_poll)
simple_watchdog_kick();
sound_tick();
@@ -304,6 +320,10 @@ int main(void) {
current_board->set_can_mode(CAN_MODE_NORMAL);
harness_init();
+ // seed the ADC caches before interrupts are live
+ voltage_mV = current_board->read_voltage_mV();
+ current_mA = current_board->read_current_mA();
+
// panda has an FPU, let's use it!
enable_fpu();
@@ -347,6 +367,7 @@ int main(void) {
// LED should keep on blinking all the time
while (true) {
+ tick_sample_poll();
if (power_save_status == POWER_SAVE_STATUS_DISABLED) {
#ifdef DEBUG_FAULTS
if (fault_status == FAULT_STATUS_NONE) {
@@ -357,6 +378,7 @@ int main(void) {
delay(fade >> 4);
led_set(LED_RED, false);
delay((MAX_LED_FADE - fade) >> 4);
+ tick_sample_poll();
}
for (uint32_t fade = MAX_LED_FADE; fade > 0U; fade -= 1U) {
@@ -364,6 +386,7 @@ int main(void) {
delay(fade >> 4);
led_set(LED_RED, false);
delay((MAX_LED_FADE - fade) >> 4);
+ tick_sample_poll();
}
#ifdef DEBUG_FAULTS
diff --git a/panda/board/main_comms.h b/panda/board/main_comms.h
index 6450c0f..c43b208 100644
--- a/panda/board/main_comms.h
+++ b/panda/board/main_comms.h
@@ -9,8 +9,10 @@ static int get_health_pkt(void *dat) {
struct health_t * health = (struct health_t*)dat;
health->uptime_pkt = uptime_cnt;
- health->voltage_pkt = current_board->read_voltage_mV();
- health->current_pkt = current_board->read_current_mA();
+ // cached values sampled in thread context (see tick_sample_poll in main.c);
+ // reading the ADC here would busy-wait in interrupt context
+ health->voltage_pkt = voltage_mV;
+ health->current_pkt = current_mA;
health->ignition_line_pkt = (uint8_t)(harness_check_ignition());
health->ignition_can_pkt = ignition_can;
diff --git a/panda/board/main_declarations.h b/panda/board/main_declarations.h
index 52aaa6c..e6737bb 100644
--- a/panda/board/main_declarations.h
+++ b/panda/board/main_declarations.h
@@ -13,6 +13,10 @@ extern uint8_t hw_type;
extern board *current_board;
extern uint32_t uptime_cnt;
+// ADC results, sampled in thread context (see tick_sample_poll in main.c)
+extern uint32_t voltage_mV;
+extern uint32_t current_mA;
+
// heartbeat state
extern uint32_t heartbeat_counter;
extern bool heartbeat_lost;
diff --git a/panda/board/main_definitions.h b/panda/board/main_definitions.h
index 83c9109..27d5eb3 100644
--- a/panda/board/main_definitions.h
+++ b/panda/board/main_definitions.h
@@ -5,6 +5,10 @@ uint8_t hw_type = 0;
board *current_board;
uint32_t uptime_cnt = 0;
+// ADC results, sampled in thread context (see tick_sample_poll in main.c)
+uint32_t voltage_mV = 0;
+uint32_t current_mA = 0;
+
// heartbeat state
uint32_t heartbeat_counter = 0;
bool heartbeat_lost = false;
diff --git a/panda/pyproject.toml b/panda/pyproject.toml
index bd07fd6..9eb79a8 100644
--- a/panda/pyproject.toml
+++ b/panda/pyproject.toml
@@ -13,7 +13,7 @@ classifiers = [
]
dependencies = [
"libusb1",
- "iqdbc @ git+https://gitlvb.teallvbs.xyz/teal/iqdbc.git@master#egg=iqdbc",
+ "iqdbc @ git+https://git.konn3kt.com/teal/iqdbc.git@master#egg=iqdbc",
]
[project.optional-dependencies]
diff --git a/panda/tests/libpanda/SConscript b/panda/tests/libpanda/SConscript
index 4f5d193..0f423ac 100644
--- a/panda/tests/libpanda/SConscript
+++ b/panda/tests/libpanda/SConscript
@@ -26,6 +26,11 @@ env = Environment(
if system == "Darwin":
env.PrependENVPath('PATH', '/opt/homebrew/bin')
+# 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 GetOption('ubsan'):
flags = [
"-fsanitize=undefined",
diff --git a/selfdrive/controls/lib/longcontrol.py b/selfdrive/controls/lib/longcontrol.py
index c304425..4be1953 100644
--- a/selfdrive/controls/lib/longcontrol.py
+++ b/selfdrive/controls/lib/longcontrol.py
@@ -47,6 +47,7 @@ class LongControl:
(CP.longitudinalTuning.kiBP, CP.longitudinalTuning.kiV),
rate=1 / DT_CTRL)
self.last_output_accel = 0.0
+ self.stopping_decel_rate = CP_IQ.stoppingDecelRateOverride or 1.0
self.smooth = SmoothStopController()
def reset(self):
@@ -75,7 +76,7 @@ class LongControl:
if output_accel > self.CP.stopAccel:
output_accel = min(output_accel, 0.0)
# TODO: can we just go straight to stopAccel?
- output_accel -= 1.0 * DT_CTRL # m/s^2/s while trying to stop
+ output_accel -= self.stopping_decel_rate * DT_CTRL # m/s^2/s while trying to stop
self.reset()
self.smooth.reset()
diff --git a/selfdrive/selfdrived/selfdrived.py b/selfdrive/selfdrived/selfdrived.py
index 39f655d..5c13610 100755
--- a/selfdrive/selfdrived/selfdrived.py
+++ b/selfdrive/selfdrived/selfdrived.py
@@ -745,7 +745,16 @@ class SelfdriveD(GapButtonActions):
self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled")
self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator")
self.experimental_mode = self.params.get_bool("ExperimentalMode") and self.CP.openpilotLongitudinalControl
- self.personality = self.params.get("LongitudinalPersonality", return_default=True)
+ # Params can be changed while selfdrived is running. Keep the live value in
+ # the same valid enum range enforced during startup; otherwise a stale value
+ # (for example 3) makes the alert callback lookup raise KeyError and kills
+ # selfdrived.
+ self.personality = get_sanitize_int_param(
+ "LongitudinalPersonality",
+ min(log.LongitudinalPersonality.schema.enumerants.values()),
+ max(log.LongitudinalPersonality.schema.enumerants.values()),
+ self.params,
+ )
self.nav_exit_lane_change = self._read_nav_exit_lane_change()
self.model_download_pending = self.params.get("ModelManager_DownloadIndex") is not None
diff --git a/selfdrive/selfdrived/tests/test_longitudinal_pref_persistence.py b/selfdrive/selfdrived/tests/test_longitudinal_pref_persistence.py
index b8e1c58..ba128f7 100644
--- a/selfdrive/selfdrived/tests/test_longitudinal_pref_persistence.py
+++ b/selfdrive/selfdrived/tests/test_longitudinal_pref_persistence.py
@@ -1,6 +1,6 @@
from cereal import car
-from openpilot.selfdrive.selfdrived.selfdrived import _cleanup_startup_params
+from openpilot.selfdrive.selfdrived.selfdrived import _cleanup_startup_params, get_sanitize_int_param
class DummyParams:
@@ -21,3 +21,20 @@ class TestLongitudinalPrefPersistence:
_cleanup_startup_params(cp, params)
assert params.removed == []
+
+ def test_invalid_personality_is_clamped_before_use(self):
+ class ParamsWithInvalidPersonality:
+ def __init__(self):
+ self.value = 3
+
+ def get(self, key: str, return_default: bool = False) -> int:
+ assert key == "LongitudinalPersonality"
+ return self.value
+
+ def put(self, key: str, value: int) -> None:
+ assert key == "LongitudinalPersonality"
+ self.value = value
+
+ params = ParamsWithInvalidPersonality()
+ assert get_sanitize_int_param("LongitudinalPersonality", 0, 2, params) == 2
+ assert params.value == 2
diff --git a/selfdrive/ui/layouts/settings/developer.py b/selfdrive/ui/layouts/settings/developer.py
index 7a45da0..c19e086 100644
--- a/selfdrive/ui/layouts/settings/developer.py
+++ b/selfdrive/ui/layouts/settings/developer.py
@@ -24,6 +24,14 @@ DESCRIPTIONS = {
"Exposes a snapshot of recent dashcam clips and logs as a USB drive when connected to a computer. " +
"IQ.Pilot keeps running while this is enabled."
),
+ 'long_maneuver': tr_noop(
+ "Commands a scripted sequence of acceleration steps to measure longitudinal actuator response. " +
+ "Requires IQ.Pilot longitudinal control. Only use on a clear, closed road."
+ ),
+ 'lat_maneuver': tr_noop(
+ "Commands a scripted sequence of lateral acceleration steps to measure steering actuator response. " +
+ "Only use on a straight, flat, clear road."
+ ),
}
@@ -59,6 +67,20 @@ class DeveloperLayout(Widget):
)
self._ssh_keys = ssh_key_item(lambda: tr("SSH Keys"), description=lambda: tr(DESCRIPTIONS["ssh_key"]))
+ self._long_maneuver_toggle = toggle_item(
+ lambda: tr("Longitudinal Maneuver Mode"),
+ description=lambda: tr(DESCRIPTIONS["long_maneuver"]),
+ initial_state=self._params.get_bool("LongitudinalManeuverMode"),
+ callback=self._on_long_maneuver_mode,
+ )
+
+ self._lat_maneuver_toggle = toggle_item(
+ lambda: tr("Lateral Maneuver Mode"),
+ description=lambda: tr(DESCRIPTIONS["lat_maneuver"]),
+ initial_state=self._params.get_bool("LateralManeuverMode"),
+ callback=self._on_lat_maneuver_mode,
+ )
+
self._on_enable_ui_debug(self._params.get_bool("ShowDebugInfo"))
self._scroller = Scroller([
@@ -66,6 +88,8 @@ class DeveloperLayout(Widget):
self._usb_storage_toggle,
self._ssh_toggle,
self._ssh_keys,
+ self._long_maneuver_toggle,
+ self._lat_maneuver_toggle,
], line_separator=True, spacing=0)
# Toggles should be not available to change in onroad state
@@ -81,12 +105,24 @@ class DeveloperLayout(Widget):
def _update_toggles(self):
ui_state.update_params()
+ for item in (self._long_maneuver_toggle, self._lat_maneuver_toggle):
+ item.set_visible(not self._is_release)
+
+ if ui_state.CP is not None:
+ self._long_maneuver_toggle.action_item.set_enabled(ui_state.has_longitudinal_control and ui_state.is_offroad())
+ self._lat_maneuver_toggle.action_item.set_enabled(ui_state.is_offroad())
+ else:
+ self._long_maneuver_toggle.action_item.set_enabled(False)
+ self._lat_maneuver_toggle.action_item.set_enabled(False)
+
# TODO: make a param control list item so we don't need to manage internal state as much here
# refresh toggles from params to mirror external changes
for key, item in (
("AdbEnabled", self._adb_toggle),
("UsbStorageEnabled", self._usb_storage_toggle),
("SshEnabled", self._ssh_toggle),
+ ("LongitudinalManeuverMode", self._long_maneuver_toggle),
+ ("LateralManeuverMode", self._lat_maneuver_toggle),
):
item.action_item.set_state(self._params.get_bool(key))
@@ -108,7 +144,12 @@ class DeveloperLayout(Widget):
def _on_long_maneuver_mode(self, state: bool):
self._params.put_bool("LongitudinalManeuverMode", state)
self._params.put_bool("JoystickDebugMode", False)
+ self._params.put_bool("LateralManeuverMode", False)
+ self._lat_maneuver_toggle.action_item.set_state(False)
def _on_lat_maneuver_mode(self, state: bool):
self._params.put_bool("LateralManeuverMode", state)
self._params.put_bool("JoystickDebugMode", False)
+ self._params.put_bool("ExperimentalMode", False)
+ self._params.put_bool("LongitudinalManeuverMode", False)
+ self._long_maneuver_toggle.action_item.set_state(False)
diff --git a/system/loggerd/loggerd.h b/system/loggerd/loggerd.h
index e8c8c04..0b440db 100644
--- a/system/loggerd/loggerd.h
+++ b/system/loggerd/loggerd.h
@@ -28,12 +28,17 @@ const int SEGMENT_LENGTH = LOGGERD_TEST ? atoi(getenv("LOGGERD_SEGMENT_LENGTH"))
constexpr char PRESERVE_ATTR_NAME[] = "user.preserve";
constexpr char PRESERVE_ATTR_VALUE = '1';
-// 2.5x the stock 526x330 qcamera, rounded up to even. The msm_vidc encoder rejects
-// VIDIOC_S_FMT with ENOTSUPP (524) on an odd width or height, which throws out of
-// encoder_thread and SIGABRTs all of encoderd -- taking fcamera/dcamera/ecamera with it.
constexpr int QCAM_WIDTH = 1316;
constexpr int QCAM_HEIGHT = 826;
-static_assert(QCAM_WIDTH % 2 == 0 && QCAM_HEIGHT % 2 == 0, "qcamera dimensions must be even");
+constexpr int MICI_QCAM_WIDTH = 1210;
+constexpr int MICI_QCAM_HEIGHT = 760;
+static_assert(QCAM_WIDTH % 2 == 0 && QCAM_HEIGHT % 2 == 0 &&
+ MICI_QCAM_WIDTH % 2 == 0 && MICI_QCAM_HEIGHT % 2 == 0,
+ "qcamera dimensions must be even");
+
+inline bool is_mici() {
+ return Hardware::get_device_type() == cereal::InitData::DeviceType::MICI;
+}
struct EncoderSettings {
cereal::EncodeIndex::Type encode_type;
@@ -147,8 +152,8 @@ const EncoderInfo qcam_encoder_info = {
.filename = "qcamera.ts",
.cbr = true, // enforce the bitrate so upload size stays predictable (no VBR overshoot)
.get_settings = [](int){return EncoderSettings::QcamEncoderSettings();},
- .frame_width = QCAM_WIDTH,
- .frame_height = QCAM_HEIGHT,
+ .frame_width = is_mici() ? MICI_QCAM_WIDTH : QCAM_WIDTH,
+ .frame_height = is_mici() ? MICI_QCAM_HEIGHT : QCAM_HEIGHT,
.include_audio = Params().getBool("RecordAudio"),
INIT_ENCODE_FUNCTIONS(QRoadEncode),
};
diff --git a/tools/lateral_maneuvers/README.md b/tools/lateral_maneuvers/README.md
index 78e7b36..2802b74 100644
--- a/tools/lateral_maneuvers/README.md
+++ b/tools/lateral_maneuvers/README.md
@@ -7,7 +7,7 @@ Test your vehicle's lateral control tuning with this tool. The tool will test th
## Instructions
-1. Check out a development branch such as `master-mici` on your comma device.
+1. Check out a development branch such as `master-mici` on your device. The toggle is hidden on release branches.
2. The full maneuver suite runs at 20 and 30 mph.
3. Enable "Lateral Maneuver Mode" in Settings > Developer on the device while offroad. Alternatively, set the parameter manually:
@@ -17,7 +17,7 @@ Test your vehicle's lateral control tuning with this tool. The tool will test th
4. Turn your vehicle back on. You will see "Lateral Maneuver Mode".
-5. Ensure the area ahead is clear, as iqpilot will command lateral acceleration steps in this mode. Once you are ready, set ACC manually to the target speed shown on screen and let iqpilot stabilize lateral. After 2 seconds of steady straight driving, the maneuver will begin automatically. iqpilot lateral control stays engaged between maneuvers normally while waiting for the next maneuver's readiness conditions. The maneuver will be aborted and repeated if speed is out of range, steering is touched or iqpilot disengages.
+5. Ensure the area ahead is clear, as IQ.Pilot will command lateral acceleration steps in this mode. Once you are ready, set ACC manually to the target speed shown on screen and let IQ.Pilot stabilize lateral. After 2 seconds of steady straight driving on a road under 250 m radius and under 6.8° of roll, the maneuver will begin automatically. IQ.Pilot lateral control stays engaged between maneuvers normally while waiting for the next maneuver's readiness conditions. The maneuver will be aborted and repeated if speed is out of range, the steering wheel or gas is touched, or IQ.Pilot disengages.
6. When the testing is complete, you'll see an alert that says "Maneuvers Finished." Complete the route by pulling over and turning off the vehicle.
@@ -37,4 +37,18 @@ Test your vehicle's lateral control tuning with this tool. The tool will test th
Opening report: tools/lateral_maneuvers/lateral_reports/KIA_EV6_98395b7c5b27882e_000001cc--5a73bde686.html
```
- The iqpilot `generate_report.py` also supports auto-detection of lateral sweeps in any route without `alertDebug` markers (pass `--auto`), and ranks the top-N highest-peak sweeps by speed/peak filters. See `generate_report.py --help`.
+ The IQ.Pilot `generate_report.py` also takes a path to a local `rlog.zst` or a directory of them, supports
+ auto-detection of lateral sweeps in any route without `alertDebug` markers (pass `--auto`), and ranks the
+ top-N highest-peak sweeps by speed/peak filters. See `generate_report.py --help`.
+
+## Testing the tooling without a car
+
+`sim_maneuvers.py` runs `lateral_maneuversd` as a real process against a synthetic steering rack and writes an
+rlog that `generate_report.py` reads. Use it to verify the daemon and the report generator after changing either:
+
+```sh
+$ python tools/lateral_maneuvers/sim_maneuvers.py --out /tmp/lat/rlog.zst
+$ python tools/lateral_maneuvers/generate_report.py /tmp/lat/rlog.zst
+```
+
+The full suite takes about 5 minutes of wall clock; `--max-maneuvers N` stops early.
diff --git a/tools/lateral_maneuvers/generate_report.py b/tools/lateral_maneuvers/generate_report.py
index fbfb43f..c122203 100644
--- a/tools/lateral_maneuvers/generate_report.py
+++ b/tools/lateral_maneuvers/generate_report.py
@@ -1,376 +1,261 @@
#!/usr/bin/env python3
-"""Lateral maneuver compliance report — analog of tools/longitudinal_maneuvers/generate_report.py.
-
-Produces the "sine 0.5 Hz 30 mph" / "50% peak crossed in X.XXXs" style HTML report comma posts
-on social media for steering-rack compliance comparisons. Reads any iqpilot/openpilot rlog
-route, slices it into lateral maneuver windows (either by `alertDebug` markers from a scripted
-maneuversd run, or by auto-detection of contiguous lat-active sweeps), and emits a 4-panel
-plot per run:
-
- 1. Lateral accel (desired + actual, m/s²) on left axis and steering-wheel angle (deg) on
- right axis. Black circle marks the time the actual lat-accel first crosses 50 % of the
- desired peak in the same direction.
- 2. Vehicle speed (mph)
- 3. Lateral jerk (m/s³), numerically differentiated from actual lat-accel
- 4. Roll (deg) from liveParameters
-
-Usage:
- python tools/lateral_maneuvers/generate_report.py [description]
-
-Examples:
- python tools/lateral_maneuvers/generate_report.py 1ce1b50dd82993a1\\|0000003b--a389fbdf35
- python tools/lateral_maneuvers/generate_report.py /path/to/local/rlog.zst "sine 0.5Hz 30mph"
-"""
import argparse
import base64
import io
import math
+import numpy as np
import os
-import pprint
import webbrowser
from collections import defaultdict
from pathlib import Path
-
import matplotlib.pyplot as plt
-import numpy as np
-from tabulate import tabulate
+from openpilot.common.utils import tabulate
+from cereal import car
+from openpilot.common.filter_simple import FirstOrderFilter
+from openpilot.selfdrive.controls.lib.latcontrol_torque import LP_FILTER_CUTOFF_HZ
from openpilot.tools.lib.logreader import LogReader
from openpilot.system.hardware.hw import Paths
+from openpilot.common.constants import CV
+from openpilot.tools.longitudinal_maneuvers.generate_report import format_car_params
+
+ANGLE_CONTROL = (car.CarParams.SteerControlType.angle, car.CarParams.SteerControlType.curvatureDEPRECATED)
-MPS_TO_MPH = 2.23693629
-AUTO_DESIRED_LAT_ACCEL_THRESHOLD = 0.5
-AUTO_MIN_V_EGO = 5.0
-AUTO_MIN_DURATION_S = 1.5
-AUTO_GAP_S = 0.5
+def lat_accel(curvature, v):
+ return curvature * max(v, 1.0) ** 2
-def format_car_params(CP):
- return pprint.pformat({k: v for k, v in CP.to_dict().items() if not k.endswith("DEPRECATED")}, indent=2)
-
-
-def _series(msgs, which):
- rows = [(m.logMonoTime, getattr(m, which)) for m in msgs if m.which() == which]
- if not rows:
- return [], []
- t, v = zip(*rows, strict=True)
- return list(t), list(v)
-
-
-def _to_relative_seconds(t_ns, t0):
- return [(t - t0) / 1e9 for t in t_ns]
-
-
-def _resample(t_src, v_src, t_dst):
- if not t_src or not t_dst:
- return np.zeros(len(t_dst))
- return np.interp(t_dst, t_src, v_src)
-
-
-def _peak_crossing_time(t, desired, actual, fraction=0.5):
- if len(desired) == 0:
- return None, 0.0
- desired = np.asarray(desired)
- actual = np.asarray(actual)
- peak_idx = int(np.argmax(np.abs(desired)))
- peak = desired[peak_idx]
- if abs(peak) < 1e-3:
- return None, peak
- target = fraction * peak
- prev = False
- for i in range(peak_idx + 1):
- crossed = (target > 0 and actual[i] >= target) or (target < 0 and actual[i] <= target)
- if crossed and prev:
- return t[i], peak
- prev = crossed
- return None, peak
-
-
-def _slice_by_alert_debug(msgs):
- out = []
- active_prev = False
- description_prev = None
- for msg in msgs:
- if msg.which() == "alertDebug":
- # Match both the longitudinal daemon ("Maneuver Active: …") and the lateral daemon
- # ("Active sine …", "Active +0.5m/s² …", "Complete").
- text1 = msg.alertDebug.alertText1
- active = "Maneuver Active" in text1 or text1.startswith("Active") or text1 == "Complete"
- if active and not active_prev:
- if msg.alertDebug.alertText2 == description_prev:
- out[-1][1].append([])
- else:
- out.append((msg.alertDebug.alertText2, [[]]))
- description_prev = out[-1][0]
- active_prev = active
- if active_prev:
- out[-1][1][-1].append(msg)
- return out
-
-
-def _slice_auto(msgs):
- t_cc, cc_vals = _series(msgs, "carControl")
- t_cs, cs_vals = _series(msgs, "carState")
- if not t_cc or not t_cs:
- return []
-
- v_ego = np.asarray([m.vEgo for m in cs_vals])
- curvature = np.asarray([m.actuators.curvature for m in cc_vals])
- lat_active = np.asarray([1.0 if m.latActive else 0.0 for m in cc_vals])
-
- t_cc_s = np.asarray([(t - t_cc[0]) / 1e9 for t in t_cc])
- t_cs_s = np.asarray([(t - t_cc[0]) / 1e9 for t in t_cs])
- v_at_cc = np.interp(t_cc_s, t_cs_s, v_ego)
- desired_lat_accel = curvature * v_at_cc ** 2
- signal = np.abs(desired_lat_accel) * lat_active * (v_at_cc > AUTO_MIN_V_EGO).astype(float)
-
- cycle_dt = float(np.median(np.diff(t_cc_s))) if len(t_cc_s) > 1 else 0.01
- min_frames = max(1, int(AUTO_MIN_DURATION_S / cycle_dt))
-
- windows = []
- start = None
- for i, s in enumerate(signal):
- if s > AUTO_DESIRED_LAT_ACCEL_THRESHOLD and start is None:
- start = i
- elif s <= AUTO_DESIRED_LAT_ACCEL_THRESHOLD and start is not None:
- if i - start > min_frames:
- windows.append((t_cc[start], t_cc[i]))
- start = None
- if start is not None and len(signal) - start > min_frames:
- windows.append((t_cc[start], t_cc[-1]))
-
- merged = []
- for a, b in windows:
- if merged and (a - merged[-1][1]) / 1e9 < AUTO_GAP_S:
- merged[-1] = (merged[-1][0], b)
- else:
- merged.append((a, b))
-
- runs = []
- for a, b in merged:
- runs.append([m for m in msgs if a <= m.logMonoTime <= b])
- if not runs:
- return []
- return [("auto-detected lateral sweep", runs)]
-
-
-def _plot_run(description, run_idx, msgs, builder, target_cross_times):
- t_cc, carControl = _series(msgs, "carControl")
- t_cs, carState = _series(msgs, "carState")
- t_lp, livePose = _series(msgs, "livePose")
-
- if not (t_cc and t_cs and t_lp):
- builder.append(f"Run #{run_idx + 1}: missing required data, skipping.
\n")
- return
-
- t0 = min(t_cc[0], t_cs[0], t_lp[0])
- t_cc_s = _to_relative_seconds(t_cc, t0)
- t_cs_s = _to_relative_seconds(t_cs, t0)
- t_lp_s = _to_relative_seconds(t_lp, t0)
-
- v_ego = np.asarray([m.vEgo for m in carState])
- steer = np.asarray([m.steeringAngleDeg for m in carState])
-
- curvature = np.asarray([m.actuators.curvature for m in carControl])
- v_at_cc = _resample(t_cs_s, v_ego, t_cc_s)
- desired_lat_accel = curvature * v_at_cc ** 2
-
- actual_lat_accel = np.asarray([m.accelerationDevice.y for m in livePose])
- jerk = np.gradient(actual_lat_accel, t_lp_s)
-
- t_lpar, liveParameters = _series(msgs, "liveParameters")
- if liveParameters:
- t_lpar_s = _to_relative_seconds(t_lpar, t0)
- roll_deg = np.asarray([math.degrees(m.roll) for m in liveParameters])
- else:
- t_lpar_s = []
- roll_deg = np.asarray([])
-
- desired_lat_accel_on_lp = _resample(t_cc_s, desired_lat_accel, t_lp_s)
- cross_time, peak = _peak_crossing_time(t_lp_s, desired_lat_accel_on_lp, actual_lat_accel, fraction=0.5)
-
- title = f"Run #{run_idx + 1}"
- builder.append(f"{title}
\n")
- if cross_time is not None:
- builder.append(f"50% peak, crossed in {cross_time:.3f}s
\n")
- target_cross_times[description].append(cross_time)
- else:
- builder.append("50% peak, not crossed
\n")
- builder.append(f"Peak desired lat accel: {peak:+.2f} m/s², "
- f"avg speed: {np.mean(v_ego) * MPS_TO_MPH:.1f} mph
\n")
-
- plt.rcParams["font.size"] = 32
- fig = plt.figure(figsize=(28, 22))
- ax = fig.subplots(4, 1, sharex=True, gridspec_kw={"height_ratios": [5, 2, 2, 2]})
-
- ax_la = ax[0]
- ax_la.grid(linewidth=2)
- ax_la.plot(t_cc_s, desired_lat_accel, label="desired lat accel", linewidth=4)
- ax_la.plot(t_lp_s, actual_lat_accel, label="actual lat accel", linewidth=4)
- ax_la.set_ylabel("Lateral Accel (m/s²)")
-
- ax_st = ax_la.twinx()
- ax_st.plot(t_cs_s, steer, color="tab:green", label="steer angle", linewidth=4)
- ax_st.set_ylabel("Steering Angle (deg)")
-
- lines_l, labels_l = ax_la.get_legend_handles_labels()
- lines_r, labels_r = ax_st.get_legend_handles_labels()
- ax_la.legend(lines_l + lines_r, labels_l + labels_r, loc="upper right", prop={"size": 22})
-
- if cross_time is not None:
- cross_val = float(np.interp(cross_time, t_lp_s, actual_lat_accel))
- ax_la.plot(cross_time, cross_val, marker="o", markersize=30, markeredgewidth=4,
- markeredgecolor="black", markerfacecolor="None")
-
- ax[1].grid(linewidth=2)
- ax[1].plot(t_cs_s, v_ego * MPS_TO_MPH, color="tab:blue", label="vEgo", linewidth=4)
- ax[1].set_ylabel("Velocity (mph)")
- ax[1].legend(loc="upper right", prop={"size": 22})
-
- ax[2].grid(linewidth=2)
- ax[2].plot(t_lp_s, jerk, color="tab:blue", label="actual jerk", linewidth=4)
- ax[2].set_ylabel("Jerk (m/s³)")
- ax[2].legend(loc="upper left", prop={"size": 22})
-
- ax[3].grid(linewidth=2)
- if len(roll_deg):
- ax[3].plot(t_lpar_s, roll_deg, color="tab:blue", label="roll", linewidth=4)
- ax[3].set_ylabel("Roll (deg)")
- ax[3].legend(loc="upper right", prop={"size": 22})
-
- ax[-1].set_xlabel("Time (s)")
- fig.tight_layout()
-
- buffer = io.BytesIO()
- fig.savefig(buffer, format="webp")
- plt.close(fig)
- buffer.seek(0)
- builder.append(f"
\n")
- builder.append(" \n")
-
-
-def report(platform, route, description, CP, ID, maneuvers):
+def report(platform, route, _description, CP, ID, maneuvers):
output_path = Path(__file__).resolve().parent / "lateral_reports"
+ output_fn = output_path / f"{platform}_{route.replace('/', '_').replace('|', '_')}.html"
output_path.mkdir(exist_ok=True)
- safe_route = route.replace("/", "_").replace("|", "_")
- output_fn = output_path / f"{platform}_{safe_route}.html"
-
target_cross_times = defaultdict(list)
builder = [
- "\n",
+ "\n",
"Lateral maneuver report
\n",
f"{platform}
\n",
f"{route}
\n",
f"{ID.gitCommit}, {ID.gitBranch}, {ID.gitRemote}
\n",
]
- if description is not None:
- builder.append(f"Description: {description}
\n")
- builder.append(f"CarParams
{format_car_params(CP)} \n")
- builder.append("{ summary }")
+ if _description is not None:
+ builder.append(f"Description: {_description}
\n")
+ builder.append(f"CarParams
{format_car_params(CP)} \n")
+ builder.append('{ summary }') # to be replaced below
+ for description, runs in maneuvers:
+ # filter incomplete runs
+ completed_runs = [msgs for msgs in runs
+ if any(m.alertDebug.alertText1 == 'Complete' for m in msgs if m.which() == 'alertDebug')]
+ print(f'plotting maneuver: {description}, runs: {len(completed_runs)}')
+ if not completed_runs:
+ continue
+ builder.append("\n")
+ builder.append(f"{description}
\n")
+ for run, msgs in enumerate(completed_runs):
+ last_active = max(m.logMonoTime for m in msgs if m.which() == 'lateralManeuverPlan' and m.valid)
+ msgs = [m for m in msgs if m.logMonoTime <= last_active]
+ t_carControl, carControl = zip(*[(m.logMonoTime, m.carControl) for m in msgs if m.which() == 'carControl'], strict=True)
+ t_carState, carState = zip(*[(m.logMonoTime, m.carState) for m in msgs if m.which() == 'carState'], strict=True)
+ t_controlsState, controlsState = zip(*[(m.logMonoTime, m.controlsState) for m in msgs if m.which() == 'controlsState'], strict=True)
+ t_lateralPlan, lateralPlan = zip(*[(m.logMonoTime, m.lateralManeuverPlan) for m in msgs if m.which() == 'lateralManeuverPlan' and m.valid], strict=True)
+ t_carOutput, carOutput = zip(*[(m.logMonoTime, m.carOutput) for m in msgs if m.which() == 'carOutput'], strict=True)
- for maneuver_description, runs in maneuvers:
- print(f"plotting maneuver: {maneuver_description}, runs: {len(runs)}")
- builder.append("\n")
- builder.append(f"{maneuver_description}
\n")
- for run_idx, msgs in enumerate(runs):
- _plot_run(maneuver_description, run_idx, msgs, builder, target_cross_times)
+ # make time relative seconds
+ t_carControl = [(t - t_carControl[0]) / 1e9 for t in t_carControl]
+ t_carState = [(t - t_carState[0]) / 1e9 for t in t_carState]
+ t_controlsState = [(t - t_controlsState[0]) / 1e9 for t in t_controlsState]
+ t_lateralPlan = [(t - t_lateralPlan[0]) / 1e9 for t in t_lateralPlan]
+ t_carOutput = [(t - t_carOutput[0]) / 1e9 for t in t_carOutput]
+
+ # maneuver validity
+ latActive = [m.latActive for m in carControl]
+ maneuver_valid = all(latActive) and not any(cs.steeringPressed for cs in carState)
+
+ _open = 'open' if maneuver_valid else ''
+ title = f'Run #{int(run)+1}' + (' (invalid maneuver!)' if not maneuver_valid else '')
+
+ builder.append(f"{title}
\n")
+
+ baseline_accel = lat_accel(controlsState[0].curvature, carState[0].vEgo)
+ v_ego = [m.vEgo for m in carState]
+ cross_markers = []
+
+ if description.startswith(('sine', 'jitter')):
+ amplitude = max(abs(lat_accel(lp.desiredCurvature, v) - baseline_accel)
+ for lp, v in zip(lateralPlan, v_ego, strict=False))
+ threshold = amplitude * 0.5
+ builder.append('50% peak')
+ for t, cs, v in zip(t_controlsState, controlsState, v_ego, strict=False):
+ actual = lat_accel(cs.curvature, v) - baseline_accel
+ if abs(actual) > threshold:
+ builder.append(f', crossed in {t:.3f}s')
+ cross_markers.append((t, actual + baseline_accel))
+ if maneuver_valid:
+ target_cross_times[description].append(t)
+ break
+ else:
+ builder.append(', not crossed')
+ builder.append('
')
+ if maneuver_valid:
+ target_cross_times.setdefault(description, [])
+ else:
+ action_targets = [(0, lat_accel(lateralPlan[0].desiredCurvature, v_ego[0]) - baseline_accel)]
+ for i in range(1, min(len(lateralPlan), len(v_ego))):
+ if abs(lateralPlan[i].desiredCurvature - lateralPlan[i - 1].desiredCurvature) > 0.001:
+ desired = lat_accel(lateralPlan[i].desiredCurvature, v_ego[i]) - baseline_accel
+ action_targets.append((i, desired))
+
+ for j, (start_i, act_target) in enumerate(action_targets):
+ start_time = t_lateralPlan[start_i]
+ end_time = t_lateralPlan[action_targets[j + 1][0]] if j + 1 < len(action_targets) else t_controlsState[-1]
+
+ builder.append(f'aTarget: {round(act_target, 1)} m/s^2')
+ prev_crossed = False
+ for t, cs, v in zip(t_controlsState, controlsState, v_ego, strict=False):
+ if not (start_time <= t <= end_time):
+ continue
+ actual_accel = lat_accel(cs.curvature, v) - baseline_accel
+ crossed = (0 < act_target < actual_accel) or (0 > act_target > actual_accel)
+ if crossed and prev_crossed:
+ cross_time = t - start_time
+ builder.append(f', crossed in {cross_time:.3f}s')
+ cross_markers.append((t, act_target + baseline_accel))
+ if maneuver_valid:
+ target_cross_times[description].append(cross_time)
+ break
+ prev_crossed = crossed
+ else:
+ builder.append(', not crossed')
+ builder.append('
')
+ if maneuver_valid:
+ target_cross_times.setdefault(description, [])
+
+ plt.rcParams['font.size'] = 40
+ fig = plt.figure(figsize=(30, 40))
+ ax = fig.subplots(5, 1, sharex=True, gridspec_kw={'height_ratios': [5, 5, 3, 3, 3]})
+
+ ax[0].grid(linewidth=4)
+ desired_label = 'lateralManeuverPlan.desiredCurvature * vEgo^2'
+ desired_lat_accel = [lat_accel(m.desiredCurvature, v) for m, v in zip(lateralPlan, v_ego, strict=False)]
+ if description.startswith(('sine', 'jitter')):
+ ax[0].plot(t_lateralPlan[:len(desired_lat_accel)], desired_lat_accel, 'C1', label=desired_label, linewidth=6)
+ else:
+ t_desired = [t_lateralPlan[0]] + t_lateralPlan[:len(desired_lat_accel)]
+ desired_lat_accel = [baseline_accel] + desired_lat_accel
+ ax[0].step(t_desired, desired_lat_accel, 'C1', label=desired_label, linewidth=6, where='post')
+ actual_lat_accel = [lat_accel(cs.curvature, v) for cs, v in zip(controlsState, v_ego, strict=False)]
+ ax[0].plot(t_controlsState[:len(actual_lat_accel)], actual_lat_accel, 'g', label='controlsState.curvature * vEgo^2', linewidth=6)
+ ax[0].set_ylabel('Lateral Accel (m/s^2)')
+ for ct, cv in cross_markers:
+ ax[0].plot(ct, cv, marker='o', markersize=50, markeredgewidth=7, markeredgecolor='black', markerfacecolor='None')
+ ax[0].legend(prop={'size': 30})
+
+ ax[1].grid(linewidth=4)
+ if CP.steerControlType in ANGLE_CONTROL:
+ steer_field, steer_ylabel = 'steeringAngleDeg', 'Steer angle (deg)'
+ else:
+ steer_field, steer_ylabel = 'torque', 'Steer torque'
+ ax[1].plot(t_carControl, [getattr(m.actuators, steer_field) for m in carControl], 'C1', label=f'carControl.actuators.{steer_field}', linewidth=6)
+ ax[1].plot(t_carOutput, [getattr(m.actuatorsOutput, steer_field) for m in carOutput], 'g', label=f'carOutput.actuatorsOutput.{steer_field}', linewidth=6)
+ ax[1].set_ylabel(steer_ylabel)
+ ax[1].legend(prop={'size': 30})
+
+ ax[2].grid(linewidth=4)
+ ax[2].plot(t_carState, [v * CV.MS_TO_MPH for v in v_ego], label='carState.vEgo', linewidth=6)
+ ax[2].set_ylabel('Velocity (mph)')
+ ax[2].yaxis.set_major_formatter(plt.FormatStrFormatter('%.1f'))
+ ax[2].legend()
+
+ t_accel = np.array(t_controlsState[:len(actual_lat_accel)])
+ raw_jerk = np.gradient(actual_lat_accel, t_accel)
+ dt_avg = np.mean(np.diff(t_accel))
+ jerk_filter = FirstOrderFilter(0.0, 1 / (2 * np.pi * LP_FILTER_CUTOFF_HZ), dt_avg)
+ filtered_jerk = [jerk_filter.update(j) for j in raw_jerk]
+ ax[3].grid(linewidth=4)
+ ax[3].plot(t_accel, filtered_jerk, label='d/dt(controlsState.curvature * vEgo^2)', linewidth=6)
+ ax[3].set_ylabel('Jerk (m/s^3)')
+ ax[3].legend()
+
+ ax[4].grid(linewidth=4)
+ ax[4].plot(t_carControl, [math.degrees(m.orientationNED[0]) if len(m.orientationNED) == 3 else 0.0 for m in carControl],
+ label='carControl.orientationNED[0]', linewidth=6)
+ ax[4].set_ylabel('Roll (deg)')
+ ax[4].legend()
+
+ ax[-1].set_xlabel("Time (s)")
+ fig.tight_layout()
+
+ buffer = io.BytesIO()
+ fig.savefig(buffer, format='webp')
+ plt.close(fig)
+ buffer.seek(0)
+ builder.append(f"
\n")
+ builder.append(" \n")
summary = ["Summary
\n"]
- cols = ["maneuver", "crossed", "runs", "mean (s)", "min (s)", "max (s)"]
+ cols = ['maneuver', 'crossed', 'mean', 'min', 'max']
table = []
- for maneuver_description, runs in maneuvers:
- times = target_cross_times[maneuver_description]
- row = [maneuver_description, len(times), len(runs)]
- if times:
- row.extend([round(np.mean(times), 3), round(np.min(times), 3), round(np.max(times), 3)])
- table.append(row)
- summary.append(tabulate(table, headers=cols, tablefmt="html", numalign="left") + "\n")
+ for description, times in target_cross_times.items():
+ l = [description, len(times)]
+ if len(times):
+ l.extend([round(sum(times) / len(times), 2), round(min(times), 2), round(max(times), 2)])
+ table.append(l)
+ summary.append(tabulate(table, headers=cols, tablefmt='html', numalign='left') + '\n')
- sum_idx = builder.index("{ summary }")
+ sum_idx = builder.index('{ summary }')
builder[sum_idx:sum_idx + 1] = summary
with open(output_fn, "w") as f:
- f.write("".join(builder))
+ f.write(''.join(builder))
+
print(f"\nOpening report: {output_fn}\n")
webbrowser.open_new_tab(str(output_fn))
-def _rank_runs(runs, top_n, min_vego_mph, min_peak):
- scored = []
- for r in runs:
- t_cc, cc = _series(r, "carControl")
- t_cs, cs = _series(r, "carState")
- if not (t_cc and t_cs):
- continue
- v_ego = np.mean([m.vEgo for m in cs]) * MPS_TO_MPH
- curv = np.asarray([m.actuators.curvature for m in cc])
- v_at_cc = np.interp([(t - t_cc[0]) / 1e9 for t in t_cc],
- [(t - t_cc[0]) / 1e9 for t in t_cs],
- [m.vEgo for m in cs])
- peak = float(np.max(np.abs(curv * v_at_cc ** 2)))
- if v_ego < min_vego_mph or peak < min_peak:
- continue
- scored.append((peak, r))
- scored.sort(key=lambda x: -x[0])
- return [r for _, r in scored[:top_n]] if top_n > 0 else [r for _, r in scored]
+def open_route(route: str) -> LogReader:
+ if os.path.isdir(route):
+ rlogs = sorted(str(p) for p in Path(route).glob("*rlog.zst"))
+ if not rlogs:
+ raise SystemExit(f"no *rlog.zst files in {route}")
+ print(f"loading {len(rlogs)} rlogs from {route}")
+ return LogReader(rlogs, only_union_types=True)
+ if os.path.exists(route) or '/' in route or '|' in route:
+ return LogReader(route, only_union_types=True)
+ segs = [seg for seg in os.listdir(Paths.log_root()) if route in seg]
+ return LogReader([os.path.join(Paths.log_root(), seg, 'rlog.zst') for seg in segs], only_union_types=True)
-def main():
- parser = argparse.ArgumentParser(description="Generate lateral maneuver compliance report from a route")
- parser.add_argument("route", type=str, help="Route name, segment range, local rlog path, or directory of rlogs")
- parser.add_argument("description", type=str, nargs="?")
- parser.add_argument("--auto", action="store_true",
- help="Auto-detect lateral sweeps instead of relying on alertDebug 'Maneuver Active' markers")
- parser.add_argument("--top-n", type=int, default=10,
- help="Plot only the N largest-peak sweeps (0 = all). Default 10.")
- parser.add_argument("--min-vego-mph", type=float, default=15.0,
- help="Drop sweeps below this average speed. Default 15 mph.")
- parser.add_argument("--min-peak", type=float, default=0.5,
- help="Drop sweeps with peak desired lat accel below this (m/s²). Default 0.5.")
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description='Generate lateral maneuver report from route')
+ parser.add_argument('route', type=str, help='Route name, local rlog path, or directory of rlogs')
+ parser.add_argument('description', type=str, nargs='?')
+
args = parser.parse_args()
- if os.path.isdir(args.route):
- rlogs = sorted(p for p in Path(args.route).glob("*rlog.zst"))
- if not rlogs:
- raise SystemExit(f"no *rlog.zst files in {args.route}")
- print(f"loading {len(rlogs)} rlogs from {args.route}")
- lr = LogReader([str(p) for p in rlogs])
- elif os.path.exists(args.route):
- lr = LogReader(args.route)
- elif "/" in args.route or "|" in args.route:
- lr = LogReader(args.route)
- else:
- segs = [seg for seg in os.listdir(Paths.log_root()) if args.route in seg]
- lr = LogReader([os.path.join(Paths.log_root(), seg, "rlog.zst") for seg in segs])
+ lr = open_route(args.route)
- msgs = list(lr)
- CP = next(m.carParams for m in msgs if m.which() == "carParams")
- ID = next(m.initData for m in msgs if m.which() == "initData")
+ CP = lr.first('carParams')
+ ID = lr.first('initData')
platform = CP.carFingerprint
- print("processing report for", platform)
+ print('processing report for', platform)
- maneuvers = [] if args.auto else _slice_by_alert_debug(msgs)
- if not maneuvers:
- print("no alertDebug 'Maneuver Active' windows found; auto-detecting lateral sweeps")
- maneuvers = _slice_auto(msgs)
+ maneuvers: list[tuple[str, list[list]]] = []
+ active_prev = False
+ description_prev = None
- if not maneuvers:
- print("no lateral maneuvers detected — treating the whole route as one run")
- maneuvers = [("full route", [msgs])]
- else:
- filtered = []
- for description, runs in maneuvers:
- kept = _rank_runs(runs, args.top_n, args.min_vego_mph, args.min_peak)
- print(f" {description}: {len(runs)} candidate sweeps → {len(kept)} after rank/filter")
- if kept:
- filtered.append((description, kept))
- maneuvers = filtered or [("filtered out", [])]
+ for msg in lr:
+ if msg.which() == 'alertDebug':
+ active = 'Active' in msg.alertDebug.alertText1 or msg.alertDebug.alertText1 == 'Complete'
+ if active and not active_prev:
+ if msg.alertDebug.alertText2 == description_prev:
+ maneuvers[-1][1].append([])
+ else:
+ maneuvers.append((msg.alertDebug.alertText2, [[]]))
+ description_prev = maneuvers[-1][0]
+ active_prev = active
+
+ if active_prev:
+ maneuvers[-1][1][-1].append(msg)
report(platform, args.route, args.description, CP, ID, maneuvers)
-
-
-if __name__ == "__main__":
- main()
diff --git a/tools/lateral_maneuvers/lateral_maneuversd.py b/tools/lateral_maneuvers/lateral_maneuversd.py
index ad398a9..cce125a 100644
--- a/tools/lateral_maneuvers/lateral_maneuversd.py
+++ b/tools/lateral_maneuvers/lateral_maneuversd.py
@@ -12,7 +12,7 @@ from openpilot.tools.longitudinal_maneuvers.maneuversd import Action, Maneuver a
# thresholds for starting maneuvers
MAX_SPEED_DEV = 0.7 # deviation in m/s
-MAX_CURV = 0.002 # 500 m radius
+MAX_CURV = 0.004 # 250 m radius
MAX_ROLL = 0.12 # 6.8°
TIMER = 2.0 # sec stable conditions before starting maneuver
@@ -67,6 +67,12 @@ MANEUVERS = [
repeat=2,
initial_speed=20. * CV.MPH_TO_MS,
),
+ Maneuver(
+ "jitter 20mph",
+ [Action([-0.5 if i % 2 == 0 else 0.5], [0.1]) for i in range(10)],
+ repeat=2,
+ initial_speed=20. * CV.MPH_TO_MS,
+ ),
Maneuver(
"step right 30mph",
[Action([0.5], [1.0]), Action([-0.5], [1.5])],
@@ -85,6 +91,12 @@ MANEUVERS = [
repeat=2,
initial_speed=30. * CV.MPH_TO_MS,
),
+ Maneuver(
+ "jitter 30mph",
+ [Action([-0.5 if i % 2 == 0 else 0.5], [0.1]) for i in range(10)],
+ repeat=2,
+ initial_speed=30. * CV.MPH_TO_MS,
+ ),
]
@@ -106,6 +118,8 @@ def main():
maneuvers = iter(MANEUVERS)
maneuver = None
complete_cnt = 0
+ aborted_cnt = 0
+ abort_reason = ''
display_holdoff = 0
prev_text = ''
@@ -129,8 +143,14 @@ def main():
alert_msg.alertDebug.alertText1 = 'Completed'
alert_msg.alertDebug.alertText2 = maneuver.description
elif maneuver is not None:
- # reset maneuver on steering override or out of range speed
- if sm['carState'].steeringPressed or (maneuver.active and abs(v_ego - maneuver.initial_speed) > MAX_SPEED_DEV):
+ # any driver input aborts the maneuver
+ CS = sm['carState']
+ if CS.steeringPressed or CS.gasPressed:
+ aborted_cnt = int(1.0 / DT_MDL)
+ abort_reason = ('steering pressed' if CS.steeringPressed else 'gas pressed').ljust(20)
+ aborted = aborted_cnt > 0
+ speed_out_of_range = maneuver.active and abs(v_ego - maneuver.initial_speed) > MAX_SPEED_DEV
+ if aborted or speed_out_of_range:
maneuver.reset()
roll = sm['carControl'].orientationNED[0] if len(sm['carControl'].orientationNED) == 3 else 0.0
@@ -148,6 +168,9 @@ def main():
else:
alert_msg.alertDebug.alertText1 = f'Active {accel:+.1f}m/s² {max(action_remaining, 0):.1f}s'
alert_msg.alertDebug.alertText2 = maneuver.description
+ elif aborted_cnt > 0:
+ aborted_cnt -= 1
+ alert_msg.alertDebug.alertText1 = abort_reason
elif not (abs(v_ego - maneuver.initial_speed) < MAX_SPEED_DEV and sm['carControl'].latActive):
alert_msg.alertDebug.alertText1 = f'Set speed to {maneuver.initial_speed * CV.MS_TO_MPH:0.0f} mph'
elif maneuver._ready_cnt > 0:
diff --git a/tools/lateral_maneuvers/sim_maneuvers.py b/tools/lateral_maneuvers/sim_maneuvers.py
new file mode 100755
index 0000000..22ad54f
--- /dev/null
+++ b/tools/lateral_maneuvers/sim_maneuvers.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python3
+"""Run lateral_maneuversd against a synthetic lateral plant and write an rlog.
+
+ ./tools/lateral_maneuvers/sim_maneuvers.py --out /tmp/lat_rlog.zst
+ ./tools/lateral_maneuvers/generate_report.py /tmp/lat_rlog.zst
+"""
+import argparse
+import re
+from pathlib import Path
+
+from openpilot.common.constants import CV
+from openpilot.tools.lateral_maneuvers.lateral_maneuversd import MANEUVERS
+from openpilot.tools.longitudinal_maneuvers.sim_harness import ManeuverSim, Plant
+
+CURV_TAU = 0.05 # controlsd curvature command tracking
+RACK_WN = 8.0 # steering rack + tire natural frequency (rad/s)
+RACK_ZETA = 0.7 # underdamped, so achieved curvature overshoots like a real rack
+CRUISE_ACCEL = 1.2
+
+SET_SPEED_RE = re.compile(r"Set speed to (\d+) mph")
+
+
+class LateralPlant(Plant):
+ PLAN = 'lateralManeuverPlan'
+
+ def __init__(self):
+ super().__init__(v_ego=MANEUVERS[0].initial_speed)
+ self.sim = None
+ self._rack_rate = 0.0
+ self.target_speed = MANEUVERS[0].initial_speed
+ self._by_description = {m.description: m.initial_speed for m in MANEUVERS}
+
+ def _update_target(self):
+ if self.sim is None:
+ return
+ speed = self._by_description.get(self.sim.alert2)
+ if speed is None:
+ match = SET_SPEED_RE.search(self.sim.alert1)
+ speed = float(match.group(1)) * CV.MPH_TO_MS if match else None
+ if speed is not None:
+ self.target_speed = speed
+
+ def step(self, dt, plan):
+ self._update_target()
+
+ err = self.target_speed - self.v_ego
+ self.a_ego = max(min(err / 1.0, CRUISE_ACCEL), -CRUISE_ACCEL)
+ self.v_ego = max(self.v_ego + self.a_ego * dt, 0.0)
+
+ desired_curvature = float(plan.desiredCurvature) if plan is not None else 0.0
+ self.curvature += (dt / (CURV_TAU + dt)) * (desired_curvature - self.curvature)
+
+ self._rack_rate += dt * (RACK_WN ** 2 * (self.curvature - self.achieved_curvature) - 2 * RACK_ZETA * RACK_WN * self._rack_rate)
+ self.achieved_curvature += dt * self._rack_rate
+ self.lat_accel = self.achieved_curvature * max(self.v_ego, 1.0) ** 2
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument("--out", type=Path, default=Path("/tmp/lateral_maneuvers_sim/rlog.zst"))
+ parser.add_argument("--max-maneuvers", type=int, default=0, help="stop after N maneuvers (0 = all)")
+ parser.add_argument("--timeout", type=float, default=900.0)
+ args = parser.parse_args()
+
+ sim = ManeuverSim("openpilot.tools.lateral_maneuvers.lateral_maneuversd", LateralPlant(),
+ max_maneuvers=args.max_maneuvers, timeout=args.timeout)
+ out = sim.run(args.out)
+ print(f"\nmaneuvers seen: {sim.seen_maneuvers}")
+ print(f"rlog: {out} ({out.stat().st_size / 1e6:.1f} MB)")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tools/longitudinal_maneuvers/README.md b/tools/longitudinal_maneuvers/README.md
index 643af7f..28e4231 100644
--- a/tools/longitudinal_maneuvers/README.md
+++ b/tools/longitudinal_maneuvers/README.md
@@ -6,9 +6,9 @@ Test your vehicle's longitudinal control tuning with this tool. The tool will te
## Instructions
-1. Check out a development branch such as `master` on your comma device.
-2. Locate either a large empty parking lot or road devoid of any car or foot traffic. Flat, straight road is preferred. The full maneuver suite can take 1 mile or more if left running, however it is recommended to disengage openpilot between maneuvers and turn around if there is not enough space.
-3. Turn off the vehicle and set this parameter which will signal to openpilot to start the longitudinal maneuver daemon:
+1. Check out a development branch such as `master-mici` on your device. The toggle is hidden on release branches.
+2. Locate either a large empty parking lot or road devoid of any car or foot traffic. Flat, straight road is preferred. The full maneuver suite can take 1 mile or more if left running, however it is recommended to disengage IQ.Pilot between maneuvers and turn around if there is not enough space.
+3. Turn off the vehicle and enable "Longitudinal Maneuver Mode" in Settings > Developer. The toggle requires IQ.Pilot longitudinal control and only enables while offroad. Alternatively, set the parameter manually:
```sh
echo -n 1 > /data/params/d/LongitudinalManeuverMode
@@ -42,7 +42,19 @@ Test your vehicle's longitudinal control tuning with this tool. The tool will te
plotting maneuver: creep: alternate between +1m/s^2 and -1m/s^2, runs: 2
plotting maneuver: gas step response: +1m/s^2 from 20mph, runs: 2
- Report written to /home/batman/openpilot/tools/longitudinal_maneuvers/longitudinal_reports/LEXUS_ES_TSS2_57048cfce01d9625_0000010e--5b26bc3be7.html
+ Report written to tools/longitudinal_maneuvers/longitudinal_reports/LEXUS_ES_TSS2_57048cfce01d9625_0000010e--5b26bc3be7.html
```
-You can reach out on [Discord](https://discord.comma.ai) if you have any questions about these instructions or the tool itself.
+ `generate_report.py` also takes a path to a local `rlog.zst` or a directory of them.
+
+## Testing the tooling without a car
+
+`sim_maneuvers.py` runs `maneuversd` as a real process against a synthetic powertrain and writes an rlog
+that `generate_report.py` reads. Use it to verify the daemon and the report generator after changing either:
+
+```sh
+$ python tools/longitudinal_maneuvers/sim_maneuvers.py --out /tmp/long/rlog.zst
+$ python tools/longitudinal_maneuvers/generate_report.py /tmp/long/rlog.zst
+```
+
+The full suite takes about 4 minutes of wall clock; `--max-maneuvers N` stops early.
diff --git a/tools/longitudinal_maneuvers/generate_report.py b/tools/longitudinal_maneuvers/generate_report.py
index 8c16e30..32bdb5b 100755
--- a/tools/longitudinal_maneuvers/generate_report.py
+++ b/tools/longitudinal_maneuvers/generate_report.py
@@ -9,7 +9,7 @@ import webbrowser
from collections import defaultdict
from pathlib import Path
import matplotlib.pyplot as plt
-from tabulate import tabulate
+from openpilot.common.utils import tabulate
from openpilot.tools.lib.logreader import LogReader
from openpilot.system.hardware.hw import Paths
diff --git a/tools/longitudinal_maneuvers/sim_harness.py b/tools/longitudinal_maneuvers/sim_harness.py
new file mode 100644
index 0000000..d77079f
--- /dev/null
+++ b/tools/longitudinal_maneuvers/sim_harness.py
@@ -0,0 +1,240 @@
+#!/usr/bin/env python3
+"""Closed-loop offline harness for the maneuver daemons.
+
+Runs maneuversd / lateral_maneuversd as real subprocesses over msgq, drives them with a
+synthetic vehicle, and records every message to an rlog that generate_report.py can read.
+Used to validate the maneuver tooling without a car.
+"""
+import math
+import os
+import signal
+import subprocess
+import sys
+import time
+from pathlib import Path
+from typing import NamedTuple
+
+import numpy as np
+import zstandard as zstd
+
+from cereal import car, messaging
+from openpilot.common.params import Params
+from openpilot.common.realtime import DT_CTRL, Ratekeeper
+from openpilot.common.basedir import BASEDIR
+
+PUB_100HZ = ('carState', 'carControl', 'carOutput', 'controlsState', 'selfdriveState')
+PUB_20HZ = ('modelV2', 'livePose', 'liveParameters')
+SUB = ('alertDebug', 'longitudinalPlan', 'lateralManeuverPlan')
+
+STEER_RATIO = 15.0
+WHEELBASE = 2.78
+
+
+class LongPlan(NamedTuple):
+ aTarget: float
+ shouldStop: bool
+
+
+class LatPlan(NamedTuple):
+ desiredCurvature: float
+
+
+class Plant:
+ """Vehicle model. Subclasses consume the daemon's plan and fill the published messages."""
+
+ sim = None
+ PLAN = 'longitudinalPlan'
+
+ def __init__(self, v_ego: float = 0.0):
+ self.v_ego = v_ego
+ self.a_ego = 0.0
+ self.curvature = 0.0 # commanded, controlsState.desiredCurvature
+ self.achieved_curvature = 0.0 # measured, controlsState.curvature
+ self.lat_accel = 0.0
+ self.long_active = True
+ self.lat_active = True
+
+ def step(self, dt: float, plan) -> None:
+ raise NotImplementedError
+
+ def _angle(self, curvature: float) -> float:
+ return math.degrees(curvature * WHEELBASE * STEER_RATIO)
+
+ def _torque(self, curvature: float) -> float:
+ return float(np.clip(curvature * max(self.v_ego, 1.0) ** 2 / 3.0, -1.0, 1.0))
+
+ def fill_car_state(self, cs) -> None:
+ cs.vEgo = float(self.v_ego)
+ cs.vEgoRaw = float(self.v_ego)
+ cs.vEgoCluster = float(self.v_ego)
+ cs.aEgo = float(self.a_ego)
+ cs.standstill = self.v_ego < 0.01
+ cs.steeringAngleDeg = self._angle(self.achieved_curvature)
+ cs.cruiseState.enabled = True
+ cs.cruiseState.available = True
+ cs.cruiseState.speed = float(max(self.v_ego, 1.0))
+
+ def fill_car_control(self, cc) -> None:
+ cc.enabled = True
+ cc.latActive = self.lat_active
+ cc.longActive = self.long_active
+ cc.orientationNED = [0.0, 0.0, 0.0]
+ cc.actuators.curvature = float(self.curvature)
+ cc.actuators.accel = float(self.a_ego)
+ cc.actuators.steeringAngleDeg = self._angle(self.curvature)
+ cc.actuators.torque = self._torque(self.curvature)
+
+
+class ManeuverSim:
+ def __init__(self, module: str, plant: Plant, fingerprint: str = "TOYOTA_SIENNA",
+ max_maneuvers: int = 0, timeout: float = 600.0, verbose: bool = True):
+ self.module = module
+ self.plant = plant
+ plant.sim = self
+ self.fingerprint = fingerprint
+ self.max_maneuvers = max_maneuvers
+ self.timeout = timeout
+ self.verbose = verbose
+
+ self.events: list[bytes] = []
+ self.alert1 = ''
+ self.alert2 = ''
+ self.seen_maneuvers: list[str] = []
+ self.finished = False
+
+ def _write_car_params(self):
+ CP = car.CarParams.new_message()
+ CP.carFingerprint = self.fingerprint
+ CP.brand = "toyota"
+ CP.openpilotLongitudinalControl = True
+ CP.autoResumeSng = True
+ CP.steerRatio = STEER_RATIO
+ CP.wheelbase = WHEELBASE
+ Params().put("CarParams", CP.to_bytes())
+ return CP
+
+ def _head_events(self, CP):
+ init = messaging.new_message('initData')
+ init.valid = True
+ init.initData.gitCommit = "simulated"
+ init.initData.gitBranch = "sim"
+ init.initData.gitRemote = "iqpilot-sim"
+ self.events.append(init.to_bytes())
+
+ cpm = messaging.new_message('carParams')
+ cpm.valid = True
+ cpm.carParams = CP
+ self.events.append(cpm.to_bytes())
+
+ def _launch(self):
+ env = dict(os.environ)
+ env["PYTHONPATH"] = str(BASEDIR) + os.pathsep + env.get("PYTHONPATH", "")
+ return subprocess.Popen([sys.executable, "-c", f"from {self.module} import main; main()"],
+ cwd=str(BASEDIR), env=env, start_new_session=True)
+
+ def _on_alert(self, ad):
+ text1, text2 = ad.alertText1, ad.alertText2
+ if (text1, text2) != (self.alert1, self.alert2):
+ if self.verbose:
+ print(f" [{time.monotonic() - self.t_start:6.1f}s] {text1!r} | {text2!r}")
+ if text2 and text2 not in self.seen_maneuvers:
+ self.seen_maneuvers.append(text2)
+ if text1 == 'Maneuvers Finished':
+ self.finished = True
+ self.alert1, self.alert2 = text1, text2
+
+ def run(self, out: Path) -> Path:
+ self._head_events(self._write_car_params())
+
+ pm = messaging.PubMaster(list(PUB_100HZ) + list(PUB_20HZ))
+ socks = {s: messaging.sub_sock(s, conflate=False, timeout=0) for s in SUB}
+
+ proc = self._launch()
+ self.t_start = time.monotonic()
+ rk = Ratekeeper(int(1.0 / DT_CTRL), print_delay_threshold=None)
+
+ plans: dict[str, object | None] = {'longitudinalPlan': None, 'lateralManeuverPlan': None}
+ frame = 0
+ try:
+ while True:
+ for s, sock in socks.items():
+ while True:
+ raw = sock.receive(non_blocking=True)
+ if raw is None:
+ break
+ self.events.append(raw)
+ evt = messaging.log_from_bytes(raw)
+ if s == 'alertDebug':
+ self._on_alert(evt.alertDebug)
+ elif s == 'longitudinalPlan':
+ plans[s] = LongPlan(evt.longitudinalPlan.aTarget, evt.longitudinalPlan.shouldStop)
+ elif s == 'lateralManeuverPlan':
+ plans[s] = LatPlan(evt.lateralManeuverPlan.desiredCurvature) if evt.valid else None
+
+ self.plant.step(DT_CTRL, plans[self.plant.PLAN])
+
+ for s in PUB_100HZ:
+ raw = self._build(s).to_bytes()
+ self.events.append(raw)
+ pm.send(s, raw)
+
+ if frame % 5 == 0:
+ for s in PUB_20HZ:
+ raw = self._build(s).to_bytes()
+ self.events.append(raw)
+ pm.send(s, raw)
+
+ frame += 1
+ if self.finished:
+ break
+ if self.max_maneuvers and len(self.seen_maneuvers) > self.max_maneuvers:
+ break
+ if time.monotonic() - self.t_start > self.timeout:
+ print(" timed out")
+ break
+ rk.keep_time()
+ finally:
+ if proc.poll() is None:
+ os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
+ proc.wait(timeout=5)
+ for sock in socks.values():
+ del sock
+
+ out.parent.mkdir(parents=True, exist_ok=True)
+ out.write_bytes(zstd.compress(b"".join(self.events), 10))
+ return out
+
+ def _build(self, s: str):
+ msg = messaging.new_message(s)
+ msg.valid = True
+ if s == 'carState':
+ self.plant.fill_car_state(msg.carState)
+ elif s == 'carControl':
+ self.plant.fill_car_control(msg.carControl)
+ elif s == 'carOutput':
+ msg.carOutput.actuatorsOutput.accel = float(self.plant.a_ego)
+ msg.carOutput.actuatorsOutput.curvature = float(self.plant.curvature)
+ msg.carOutput.actuatorsOutput.steeringAngleDeg = self.plant._angle(self.plant.achieved_curvature)
+ msg.carOutput.actuatorsOutput.torque = self.plant._torque(self.plant.achieved_curvature)
+ elif s == 'controlsState':
+ msg.controlsState.curvature = float(self.plant.achieved_curvature)
+ msg.controlsState.desiredCurvature = float(self.plant.curvature)
+ elif s == 'selfdriveState':
+ msg.selfdriveState.enabled = True
+ msg.selfdriveState.active = True
+ msg.selfdriveState.state = 'enabled'
+ elif s == 'modelV2':
+ msg.modelV2.frameId = 0
+ msg.modelV2.action.desiredCurvature = 0.0
+ elif s == 'livePose':
+ msg.livePose.accelerationDevice.x = float(self.plant.a_ego)
+ msg.livePose.accelerationDevice.y = float(self.plant.lat_accel)
+ msg.livePose.velocityDevice.x = float(self.plant.v_ego)
+ msg.livePose.inputsOK = True
+ msg.livePose.posenetOK = True
+ msg.livePose.sensorsOK = True
+ elif s == 'liveParameters':
+ msg.liveParameters.valid = True
+ msg.liveParameters.roll = 0.0
+ msg.liveParameters.steerRatio = STEER_RATIO
+ return msg
diff --git a/tools/longitudinal_maneuvers/sim_maneuvers.py b/tools/longitudinal_maneuvers/sim_maneuvers.py
new file mode 100755
index 0000000..34e0eae
--- /dev/null
+++ b/tools/longitudinal_maneuvers/sim_maneuvers.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+"""Run maneuversd against a synthetic longitudinal plant and write an rlog.
+
+ ./tools/longitudinal_maneuvers/sim_maneuvers.py --out /tmp/long_rlog.zst
+ ./tools/longitudinal_maneuvers/generate_report.py /tmp/long_rlog.zst
+"""
+import argparse
+from pathlib import Path
+
+from openpilot.tools.longitudinal_maneuvers.sim_harness import ManeuverSim, Plant
+
+WN = 6.0 # powertrain natural frequency (rad/s)
+ZETA = 0.6 # underdamped, so actual accel overshoots the target like a real car
+
+
+class LongitudinalPlant(Plant):
+ def __init__(self):
+ super().__init__()
+ self.jerk = 0.0
+
+ def step(self, dt, plan):
+ a_target = float(plan.aTarget) if plan is not None else 0.0
+ if plan is not None and plan.shouldStop:
+ a_target = min(a_target, -0.5)
+
+ self.jerk += dt * (WN ** 2 * (a_target - self.a_ego) - 2 * ZETA * WN * self.jerk)
+ self.a_ego += dt * self.jerk
+
+ self.v_ego = max(self.v_ego + self.a_ego * dt, 0.0)
+ if self.v_ego <= 0.0:
+ self.a_ego = min(self.a_ego, 0.0)
+ self.jerk = min(self.jerk, 0.0)
+ self.lat_accel = 0.0
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument("--out", type=Path, default=Path("/tmp/longitudinal_maneuvers_sim/rlog.zst"))
+ parser.add_argument("--max-maneuvers", type=int, default=0, help="stop after N maneuvers (0 = all)")
+ parser.add_argument("--timeout", type=float, default=900.0)
+ args = parser.parse_args()
+
+ sim = ManeuverSim("openpilot.tools.longitudinal_maneuvers.maneuversd", LongitudinalPlant(),
+ max_maneuvers=args.max_maneuvers, timeout=args.timeout)
+ out = sim.run(args.out)
+ print(f"\nmaneuvers seen: {sim.seen_maneuvers}")
+ print(f"rlog: {out} ({out.stat().st_size / 1e6:.1f} MB)")
+
+
+if __name__ == "__main__":
+ main()