IQ.Pilot Release Commit @ 6d177d4

This commit is contained in:
IQ.Lvbs CI [bot]
2026-07-22 23:21:13 -05:00
parent ff4dfcb728
commit 401cac1028
93 changed files with 9223 additions and 4600 deletions
+6 -6
View File
@@ -8,11 +8,11 @@
* A modern comma, or clone device to run this software (Comma 3, 3x, 4, Konik A1/M, Mr.One C3, C3 Lite)
* One of [the supported cars](https://gitlvb.teallvbs.xyz/IQ.Lvbs/IQ.Pilot/src/branch/release/iqdbc_repo/docs/CARS.md).
* A [car harness](https://comma.ai/shop/products/car-harness) to connect to your car
#### Side Note: Volkswagen Group, and Tesla vehicles are currently the most compatible for use with IQ.Pilot, other manufacturers are supported at a minimum to the same level as stock openpilot, but are not a top priority while we are in beta.
#### Wondering if IQ.Pilot supports your car? IQ.Pilot supports every car [stock openpilot](https://gitlvb.teallvbs.xyz/IQ.Lvbs/IQ.Pilot/src/branch/release/iqdbc_repo/docs/CARS.md) supports!
## Installation
#### Installing Via Installer URL:
#### Enter the following into your device custom URL box to install IQ.Pilot:
`iqinc/release`
`installer.iqlvbs.com/release`
#### Having Trouble? If your device is currently running AGNOS 13.1 or older, you should install latest stock openpilot, then install IQ.Pilot, or try one of the alternative methods listed below!
@@ -27,11 +27,11 @@
#### Installing Via SSH:
#### Once you are connected to your device via SSH, you can paste the following command below to install IQ.Pilot:
`cd .. && rm -rf openpilot && git clone https://github.com/iqinc/openpilot.git -b release && cd openpilot && sudo reboot`
`cd .. && rm -rf openpilot && git clone https://git.konn3kt.com/IQ.Lvbs/IQ.Pilot openpilot -b release && cd openpilot && sudo reboot`
#### If you'd like to backup your previous installation as well, paste the following command below to install IQ.Pilot:
`cd .. && mv openpilot openpilot_backup_X && git clone https://github.com/iqinc/openpilot.git -b release && cd openpilot && sudo reboot`
#### Alternatively, you can use your existing fork's built in tools to switch your branch as well:
`git remote add iqpilot https://github.com/iqinc/openpilot.git && op switch iqpilot release`
`cd .. && mv openpilot openpilot_backup_X && git clone https://git.konn3kt.com/IQ.Lvbs/IQ.Pilot -b release && cd openpilot && sudo reboot`
#### Alternatively, you can use your existing fork's built in tools to switch your branch as well:
`git remote add iqpilot https://git.konn3kt.com/IQ.Lvbs/IQ.Pilot && op switch iqpilot release`
---
@@ -16,27 +16,27 @@
},
"python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "70cbd719ded42c8fd7c841864ab88c334a2155be4a57c36df240233022a5e8d1",
"sha256": "2e02a71cab9b9609ba13dc1ec0d8e804802411f1796036d2316829fdf3781804",
"size": 135536
},
"python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "b6a02ca7f2adb8788c960e931b97f9b9f40164944ad9d2a7824689beaabc53b9",
"sha256": "38d13fa715f5d04b8f4b3bb00dd1179bd0acfba6bccb8ed0ef188744be6ee48a",
"size": 67664
},
"python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "95187b8c5f81707a7fabbd9d1d8e281405ff382260ed43bef510c0089af95d13",
"sha256": "aeb2de2e8ec70238b4a5958d191eb9c674bcbdba68d5224f00339e0f6398834f",
"size": 204624
},
"python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "cd215251153edb32ff7a2d417ccc3e2921f3e669e98fa508cecb169b21e0bf4a",
"sha256": "28f5cb9010ef726b44cb3c386bdb892c1b6ad245dca5a14a530dfcb2f8975cb1",
"size": 69752
},
"python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "49736fa1e12f39114a40814f142750312ac5544416bbccc6014f1337c19dc606",
"sha256": "0f8d80604c2c124c59f7fbc62797d7ec19ab6f3ea7a239382ffa84a7ef67895f",
"size": 203072
},
"python/iqpilot_private/konn3kt/hephaestus/__init__.py": {
@@ -46,67 +46,67 @@
},
"python/iqpilot_private/konn3kt/hephaestus/_vendor/localapi_runtime.zip": {
"mode": 420,
"sha256": "8c1a71f4be436f09054bda32748c4eb094bf0e26832147d7e28ca19ce91e805f",
"sha256": "37c257acb58ab4eceb7908cd0694aeb228e5434a4110300fa8c9f38adb9bce8f",
"size": 2100238
},
"python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "0109732b5e45e846531048a649e4cd188d394aa5e64df3b36b6f4f26542dc155",
"sha256": "1e84c409cbbc2cb10d4ee120ef7a29e642add973d7fb1c788e90cf0e2c64bede",
"size": 268064
},
"python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "237166f1c645447f1467f7081bc71dedb7d090076ad135f83dc189cd3a904802",
"sha256": "d3706d25e240417da3e9e6736afd4c237bff9885f1af58dc7f58232639acab21",
"size": 340584
},
"python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "4f493569b38e1e50e2fa6d752a30d495cb3fdf572daa94452e72db067674bc0f",
"sha256": "9dcc0237069538c4848291b42c15f53c6c574b0be15b943caec86ae419f15b1d",
"size": 68048
},
"python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "bf42ea50717c7bac73bec9fd48874f43d963459f1a91cf9c92596018fbe4cd62",
"sha256": "65104577577030a91052822478be8e2ebfade9c148d01fe6dc1bb90aca269668",
"size": 335728
},
"python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "11cc3a7a1c21f40a0b6719ec1b97776ab786a5c75f31b43af173bc4452697ca7",
"sha256": "5b8c42a4b552225da64a2ee7415c4128f7b01c1949d37ada07d2f763ba35116e",
"size": 271680
},
"python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "5098e97f036dffb92eca2fce847fcbe9bc13f9277a2ae39b42300cfe56e133df",
"sha256": "d561920e30cbc493c3b6e43778f6149285d9131103dfc1b41c965aa3ecb6f5af",
"size": 134408
},
"python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "17605aaedb7b4324a4c2ea64c15c6a6f305f8d455060c7a280e2db228307a9e7",
"size": 3513840
"sha256": "e7cbdb07e7fbf760313d430a1aa635ff20566fe4c974690b1e3c37dbbf83ceb3",
"size": 3514416
},
"python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "45022394525e297bff8af3f17710bfe31f63c3526985211e4eb8924490f54600",
"sha256": "deca6bd519f1e9ffa21654eec9efd078ffeb0164b5a7920418da03015daef58b",
"size": 136448
},
"python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "f35fe3724a5a8f823b2ad42efc3a7bbeeba6d7f7fd61eda76596a296df51ca5a",
"sha256": "b6fa57cdd14e5be2afe62f7670a33bd857240aa326e0861783ac5c04fc279eea",
"size": 68136
},
"python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "af53a0e6fef1bbb63cbdae857aeb7b2b4c93cfc290b3e27211a5df60af462a9d",
"sha256": "edc1708324a5822298dbf3d65436e5887c8b72da4ef6fab98dd237dccad6a94b",
"size": 67840
},
"python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "83f5129c7a2337e63ac79e4fd4cd430e96f9570bca6b5e6e3bc5224815030913",
"sha256": "57a1f5528041a28ccc77bb491b39af7e3013aece38aa8d1fbe19fa529cecc7b2",
"size": 135648
},
"python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "afb1b9cd772fe31c6845af195f6c62ef89aeef028cebc9ea7e25187ac108f90f",
"sha256": "3ea49eb20d190b9fd858c6c5bf102d474ddefb8b9e98e6e80fc7968c738b5bc2",
"size": 269568
},
"python/iqpilot_private/konn3kt/uploaderd/__init__.py": {
@@ -116,7 +116,7 @@
},
"python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so": {
"mode": 493,
"sha256": "4c4589a6419e9501ec5a86385a6991a54a72b290e9de855e5aa303c2fac59cb0",
"sha256": "07579fac8cc95845e8bd2125b898f8d28a6f65c73556671b56f5cdffece7ac09",
"size": 204184
},
"runtime": {
@@ -148,23 +148,23 @@
}
},
"signatures": {
"python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so": "fHETfdkKuvKTn8rv9E8G6c7xzCNGE2z4BV9YqbGN4Al5F+knIeiSh2EzKkjr8TVLMHmF1BpbYqO/Hk0Le9eqBw==",
"python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so": "oXxKlxWYX8r6eFPfFWTUgUgykuIv4Fbn4LGdLzRQcO8gBNm6ZvF1+z5vlZ3A1eX/vdutp3nilP6PVz83kE+XDg==",
"python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so": "A2qyZYHlLEheJ7MKAWJ/t435DBRud3DDWXZZIAnS0KQthX2hSjxeYPPToQAaBOVso2yGj+02Jr6d5XjAjfGlDQ==",
"python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so": "yq0n30lKaAYI3uwYthCUY5w+DU52v80vQQdzdJ3HU/H4Yx//us+qoulgO4y5Lh6wIkcGyVxZM8qALf6tv/uICw==",
"python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so": "dc9Uj1Mtzs/JqAhXrRypKVXcOeDz+LhQkoC9i480cm9xTD4CwHi0uMb0R0ug3Zy/a/T6kEb1dfeLaRu8bifsAQ==",
"python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so": "f8rBsEG6oV0FWBwF1UN/wNZstXb+I1RHgznD+IuFXdsSKD1ucPSIfu+BYzxDi9/DpPfxRXVoHS4cOgN1CadmBw==",
"python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so": "YFxsXCJUOlnws+cDf5MO8mkKSiOo27xUqo29lwZBP8y2+BPiiknCShaI4hC+ejzWd4+59smPaKUuUsXcdmPABQ==",
"python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so": "aC/O3UeBljXJ6QGSvJBULyPhSUmMOp6Y7pGtfXA1Nf5tw8qEAb/7kjiU6my5+f9w48fNAe1voSF1mO5eLCsLCg==",
"python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so": "lubN92tDcIPYnpq7LLPsgqxq5qj715kBljkie2yURge7SGluI6bWyO616OIVHjdG0Wvq58/EsmvH2qKH6EbKAg==",
"python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so": "51hAcDuyXxQcnPQUQV58KcRnIggvBJSVyRA/EzO22WgX1kLXCkhGsYbJ9lMHZH3IVUXzOpP16qEoxcdykyK/Bw==",
"python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so": "ExuQziX7rIwMiZGQjFTnr7Rw+LA4iluxeRPZ7zxnvdKo6qagECqmv5VdqxsevAYmH6KiwYDBH/Bjn4G4sLnQDg==",
"python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so": "T1QHRSyUFUhXl0Mw0CSrG3oIbcCuInWNdX1mMuYHKNf3O+iaAVDB7fgYB6jl9C3jzeiD2LH6jgpgvWEUqF9WAA==",
"python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so": "YlDNaD3dT6JuYRT7P3UEnha+/W13//OtYrkoGa8KwpDFhZy7FAyQkZiENHjIQi+K3K+I7qd2phlwrWcPXvaWAg==",
"python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so": "PxuLDE5We4EsluPRWPZBt2E9nBJTsEX0You50iDdWgjQp8+gJT5ZWfX3wG8cHF8JzOL4xZdg11SjdXpOKsoODg==",
"python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so": "Lsz5pL5pkh5n3aqJ+SQi4vixS2CTIG1Nou3+z8/OgnPq/8nF47NWuOgL2pT2ogeElgOqSHZgEVO4v4V/FQKHBg==",
"python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so": "hbCMagRzeN+JMb4Z/ZkiYo8WvA8ptT8r0NzwBlLRfY1LqkC1ZePGROG3Fq5RC9ylb1UotOmBcIVcOfiG3zDMCw==",
"python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so": "zxtsmguucERIWEZXJiNU16fWzGDcbOWgsDa4oB90G1kAP73CTY9cMjchHsIkNZ+bkQNBFNSMmBsTavo6NeOTCQ==",
"python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so": "mInwiS+voFDcEVMHBmHY4W69OQ+Vhl0N6cdmsetpX2YMS8zKfkDJIWvP7AwwX2ZFGkKJ/V8Wc2NTObJAIUqDBA=="
"python/iqpilot_private/konn3kt/backups/archive_codec.cpython-312-aarch64-linux-gnu.so": "kMbERPxDWFOY9nlRI3TUHRCWmz9HUw+Y+LNT7YoA0m+kovLcUK7+9JKlggNrvEMnxZwxeJQgo1vApe42zEeaDA==",
"python/iqpilot_private/konn3kt/backups/backup_keys.cpython-312-aarch64-linux-gnu.so": "AsrsCTOTeh3yiMJfFc/soDYkWnRUyJ/xwhpIqYfK+RpPe9dNlNWcS7DOMotFNOhqd4FmaLqLK4IkRRzNYPpnCQ==",
"python/iqpilot_private/konn3kt/backups/backup_orchestrator.cpython-312-aarch64-linux-gnu.so": "L6J8e3PaiczBVYPncWdp0w2odCp9kJCZqEPYJkQb4vevXzTc9/5Z8CghPRhRJBdTkqIGhMUtz4ow4278PVhOBw==",
"python/iqpilot_private/konn3kt/backups/cbc_vault.cpython-312-aarch64-linux-gnu.so": "/3LrOQ6xtNfEb9UO5aBIGXKc4CIcn5MFTvDX6yziN0/fpk5UoZcyimG8Fs3lJn3/XFKxEN9iXQCb2IHrE9PyAQ==",
"python/iqpilot_private/konn3kt/backups/imahelper.cpython-312-aarch64-linux-gnu.so": "pjbxXEMGie5nE9RkTi0HZXCSODxluy/NtKNYE2BbFCh45TQHGLnb514BFiUSRzfX8HvlHOVFdyq50NUpQDghBw==",
"python/iqpilot_private/konn3kt/hephaestus/ble_auth.cpython-312-aarch64-linux-gnu.so": "eIgj34UctUOUNppp1SzsYQThvVXLSwco8K5Nj877cawc1G557rqjKtNANful4fRqzFQY25GBLj0kD09Uh1LRAg==",
"python/iqpilot_private/konn3kt/hephaestus/ble_gatt.cpython-312-aarch64-linux-gnu.so": "u2Vl/KgwccBFEZiI60gFG7yfHMpU3GZTrqVEOrc7ak28pvPGY4i5SxMxN0n5j88F+2M3DiVa2PXH0WquaipTCA==",
"python/iqpilot_private/konn3kt/hephaestus/ble_rpc_dispatch.cpython-312-aarch64-linux-gnu.so": "tBfufS3snKVFtpPxgbyMOLQGvqU+m0urlD/FAUe7q2ID0VDWLY7yb1/LIkdwdaMFq9jvhXfZN7VXp8Fg7XbJCw==",
"python/iqpilot_private/konn3kt/hephaestus/ble_transportd.cpython-312-aarch64-linux-gnu.so": "mVG3Ji6AjMyUMbvljZQziNfVi4sdGZer0Z1+V2imca5u+VNAqYeejxuH3qO0jvnJNCMEWy2G4LGmw/+Opl/XBA==",
"python/iqpilot_private/konn3kt/hephaestus/bt_gamepad.cpython-312-aarch64-linux-gnu.so": "E+LW1FntRDSVaQ9OLC927TnsrL7h17yuPg21yAigJKZuPGZdzgNRjBtw/tCeJ31VvaKnx24/oHiGXVBzhMxfCw==",
"python/iqpilot_private/konn3kt/hephaestus/cloud_routes.cpython-312-aarch64-linux-gnu.so": "r1LJu5eBd9HyVlc6ARvuwmstrr9EoOPYMC5Zo4uUX7/9wf1fIx8zeSY/lZVjZ+Xv9+4Jr5FcAUKn+0nO0KPrCA==",
"python/iqpilot_private/konn3kt/hephaestus/hephaestusd.cpython-312-aarch64-linux-gnu.so": "qL0x7nD5tDgZUBLdjzZxOwdaYNWUjE6HiQN9ZSt10KvrS1Yke+vKl+1YhdT0jC8WEbMRBttKAqW8ZDs5iWY6AA==",
"python/iqpilot_private/konn3kt/hephaestus/kwp2000.cpython-312-aarch64-linux-gnu.so": "OhcVaRn2lq3moVXMWL5oEudhVyka9hDjxEJ6WRuMfKf7o1TlbxVJZny8FqABCOCATD+/HmdjAuIMU31QIZOZCQ==",
"python/iqpilot_private/konn3kt/hephaestus/manage_hephaestusd.cpython-312-aarch64-linux-gnu.so": "8GcOxABlpN/fH0EMLA7JAWsnwH6/jaxqQ+BOLo8VZXfi7mXw08RcuP6aQyEJGRd2PMil4JNdesjywNB6fFFxDA==",
"python/iqpilot_private/konn3kt/hephaestus/motd.cpython-312-aarch64-linux-gnu.so": "uno8NAMvkEV0e9FxoyHNtQGjd3rIjcNboTcCrKdIHpoSN20VQBWz//jD7ksFkS/gKfnFDHqVZF/gPDoU11H6DA==",
"python/iqpilot_private/konn3kt/hephaestus/tp20.cpython-312-aarch64-linux-gnu.so": "1dOOCOC63YO+dP/b52CftTU4ZgnBeZd3J8Op3lrVVi4rVdoBtqtV0TlzPNDU1dOxIJM3NwUKYdJNucKNSRJaAg==",
"python/iqpilot_private/konn3kt/hephaestus/vw_pq_flasher.cpython-312-aarch64-linux-gnu.so": "De+rhzupAdghqffQpAPIBwIK2IuMMGTNzrTpLdDzv0DcNpBeL+NYaFBFTa1Q4Pvdt0jLkg+tAT+HO0QO4gDQCg==",
"python/iqpilot_private/konn3kt/uploaderd/iquploaderd.cpython-312-aarch64-linux-gnu.so": "WpnAv/vfP2yAg1IbyK9b9TD4VDMLDlPPkMHVOunJYi7Ua56+8hSgW6yJmYW6XuMUjoUjLiAbjYwt1GqJABj+Ag=="
}
}
+37
View File
@@ -1,3 +1,8 @@
from collections import deque
import numpy as np
class FirstOrderFilter:
def __init__(self, x0, rc, dt, initialized=True):
self.x = x0
@@ -32,3 +37,35 @@ class BounceFilter(FirstOrderFilter):
self.velocity.x = 0.0
self.x += self.velocity.x
return self.x
class MyMovingAverage:
def __init__(self, window_size, value=None):
self.window_size = window_size
if value is not None:
self.values = deque([value] * window_size, maxlen=window_size)
self.sum = value * window_size
self.result = value
else:
self.values = deque(maxlen=window_size)
self.sum = 0
self.result = 0
def set(self, value):
self.values.clear()
self.values.append(value)
self.sum = value
self.result = value
return value
def set_all(self, value):
self.values = deque([value] * self.window_size, maxlen=self.window_size)
self.sum = value * self.window_size
self.result = value
return value
def process(self, value, median=False):
self.values.append(value)
self.sum = sum(self.values)
self.result = float(np.median(self.values)) if median else float(self.sum) / len(self.values)
return self.result
+22
View File
@@ -63,6 +63,14 @@ public:
inline bool getBool(const std::string &key, bool block = false) {
return get(key, block) == "1";
}
inline int getInt(const std::string &key, bool block = false) {
std::string value = get(key, block);
return value.empty() ? 0 : std::stoi(value);
}
inline float getFloat(const std::string &key, bool block = false) {
std::string value = get(key, block);
return value.empty() ? 0.0F : std::stof(value);
}
std::map<std::string, std::string> readAll();
// helpers for writing values
@@ -73,10 +81,24 @@ public:
inline int putBool(const std::string &key, bool val) {
return put(key.c_str(), val ? "1" : "0", 1);
}
inline int putInt(const std::string &key, int val) {
const std::string value = std::to_string(val);
return put(key.c_str(), value.c_str(), value.size());
}
inline int putFloat(const std::string &key, float val) {
const std::string value = std::to_string(val);
return put(key.c_str(), value.c_str(), value.size());
}
void putNonBlocking(const std::string &key, const std::string &val);
inline void putBoolNonBlocking(const std::string &key, bool val) {
putNonBlocking(key, val ? "1" : "0");
}
inline void putIntNonBlocking(const std::string &key, int val) {
putNonBlocking(key, std::to_string(val));
}
inline void putFloatNonBlocking(const std::string &key, float val) {
putNonBlocking(key, std::to_string(val));
}
private:
void asyncWriteThread();
+20
View File
@@ -64,6 +64,14 @@ except ImportError:
except (FileNotFoundError, NotADirectoryError, IsADirectoryError):
return False
def get_int(self, key, block: bool = False) -> int:
value = self.get(key, block=block)
return int(value) if value else 0
def get_float(self, key, block: bool = False) -> float:
value = self.get(key, block=block)
return float(value) if value else 0.0
def put(self, key, dat):
if isinstance(dat, str):
dat = dat.encode("utf-8")
@@ -80,12 +88,24 @@ except ImportError:
def put_bool(self, key, val: bool):
self.put(key, b"1" if val else b"0")
def put_int(self, key, val: int):
self.put(key, str(val))
def put_float(self, key, val: float):
self.put(key, str(val))
def put_nonblocking(self, key, dat):
self.put(key, dat)
def put_bool_nonblocking(self, key, val: bool):
self.put_bool(key, val)
def put_int_nonblocking(self, key, val: int):
self.put_int(key, val)
def put_float_nonblocking(self, key, val: float):
self.put_float(key, val)
def remove(self, key):
try:
os.remove(self._p(key))
+40
View File
@@ -33,11 +33,17 @@ cdef extern from "common/params.h":
c_Params(string) except + nogil
string get(string, bool) nogil
bool getBool(string, bool) nogil
int getInt(string, bool) nogil
float getFloat(string, bool) nogil
int remove(string) nogil
int put(string, string) nogil
void putNonBlocking(string, string) nogil
void putBoolNonBlocking(string, bool) nogil
int putBool(string, bool) nogil
int putInt(string, int) nogil
int putFloat(string, float) nogil
void putIntNonBlocking(string, int) nogil
void putFloatNonBlocking(string, float) nogil
bool checkKey(string) nogil
ParamKeyType getKeyType(string) nogil
optional[string] getKeyDefaultValue(string) nogil
@@ -136,6 +142,20 @@ cdef class Params:
r = self.p.getBool(k, block)
return r
def get_int(self, key, bool block=False):
cdef string k = self.check_key(key)
cdef int r
with nogil:
r = self.p.getInt(k, block)
return r
def get_float(self, key, bool block=False):
cdef string k = self.check_key(key)
cdef float r
with nogil:
r = self.p.getFloat(k, block)
return r
def _put_cast(self, key, dat):
cdef string k = self.check_key(key)
cdef ParamKeyType t = self.p.getKeyType(k)
@@ -158,6 +178,16 @@ cdef class Params:
with nogil:
self.p.putBool(k, val)
def put_int(self, key, int val):
cdef string k = self.check_key(key)
with nogil:
self.p.putInt(k, val)
def put_float(self, key, float val):
cdef string k = self.check_key(key)
with nogil:
self.p.putFloat(k, val)
def put_nonblocking(self, key, dat):
cdef string k = self.check_key(key)
cdef string dat_bytes = self._put_cast(key, dat)
@@ -169,6 +199,16 @@ cdef class Params:
with nogil:
self.p.putBoolNonBlocking(k, val)
def put_int_nonblocking(self, key, int val):
cdef string k = self.check_key(key)
with nogil:
self.p.putIntNonBlocking(k, val)
def put_float_nonblocking(self, key, float val):
cdef string k = self.check_key(key)
with nogil:
self.p.putFloatNonBlocking(k, val)
def remove(self, key):
cdef string k = self.check_key(key)
with nogil:
+5 -50
View File
@@ -6,63 +6,18 @@ It does not replace the repository-wide license files for IQ.Pilot itself or any
## Credits:
### Hyundai / Kia / Genesis (HKG) - Sunnypilot
#### Contributors
Full credit for the Hyundai / Kia / Genesis port, along with the HKG-specific tuning work used in this tree, belongs to:
- Jason Wen
- James Vecellio-Grant
- sunnypilot
#### Attribution
This repository carries HKG-side tuning and port lineage that originated from, and/or is verbatim their work. They are the authors of the Sunnypilot-side HKG port and its tuning, and are accredited as such, IQ.Lvbs claims no copyright, credit, or authorship of the components listed below.
#### Upstream License Notice
The HKG work attributed above is acknowledged here under LICENSE notice:
```text
MIT License
Copyright (c) 2024 Jason Wen, James Vecellio-Grant, Sunnypilot, and a number of other contributors.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
#### Scope
This licensing is limited to `iqdbc_repo/iqdbc/car/hyundai` and `iqdbc_repo/iqdbc/iqpilot/car/hyundai`.
### Hyundai / Kia / Genesis (HKG) - carrotpilot
#### Contributors
Full credit for the carrotpilot-side HKG tuning lineage carried in this tree belongs to:
Full credit for the Hyundai / Kia / Genesis port and its HKG-specific tuning belongs to:
- carrotpilot devs (ajoutam)
- carrotpilot
- ajouatom
#### Attribution
This repository carries HKG-side tuning and port lineage that originated from, and/or is verbatim their work. They are the authors of the carrotpilot-side HKG tuning credited here, and are accredited as such, IQ.Lvbs claims no copyright, credit, or authorship of the components listed below.
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
@@ -80,7 +35,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
#### Scope
This licensing is limited to `iqdbc_repo/iqdbc/car/hyundai` and `iqdbc_repo/iqdbc/iqpilot/car/hyundai`.
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
+4 -4
View File
@@ -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:
+67 -7
View File
@@ -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;
@@ -302,13 +338,16 @@ struct CarState {
setCruise @9;
resumeCruise @10;
gapAdjustCruise @11;
lfaButton @12;
paddleLeft @13;
paddleRight @14;
}
}
# 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;
@@ -346,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 {
@@ -401,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;
@@ -436,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;
@@ -499,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;
@@ -595,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);
}
@@ -768,11 +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
vEgoStartingDEPRECATED @59 :Float32;
startAccelDEPRECATED @32 :Float32;
startingStateDEPRECATED @70 :Bool;
vEgoStarting @59 :Float32;
startAccel @32 :Float32;
startingState @70 :Bool;
vEgoStoppingDEPRECATED @29 :Float32;
stoppingDecelRateDEPRECATED @52 :Float32;
}
+662 -120
View File
@@ -1,31 +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.iqpilot.car.hyundai.escc import EsccCarController
from iqdbc.iqpilot.car.hyundai.longitudinal.controller import LongitudinalController
from iqdbc.iqpilot.car.hyundai.lead_data_ext import LeadDataCarController
from iqdbc.iqpilot.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
def _use_stock_lkas_request_path(CP) -> bool:
return CP.carFingerprint == CAR.HYUNDAI_PALISADE
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))
@@ -50,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])
@@ -68,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 not _use_stock_lkas_request_path(self.CP) and 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 = False if _use_stock_lkas_request_path(self.CP) else (CC.latActive and not apply_steer_req)
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))
@@ -125,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
@@ -166,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)
+614 -122
View File
@@ -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.iqpilot.car.hyundai.carstate_ext import CarStateExt
from iqdbc.iqpilot.car.hyundai.escc import EsccCarStateBase
from iqdbc.iqpilot.car.hyundai.aol import AolCarState
from iqdbc.iqpilot.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),
}
+91 -78
View File
@@ -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.iqpilot.car.fingerprints_ext import merge_fw_versions
from iqdbc.iqpilot.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 = merge_fw_versions(FW_VERSIONS, FW_VERSIONS_EXT)
+253 -129
View File
@@ -1,21 +1,33 @@
import copy
import crcmod
from iqdbc.car.hyundai.values import CAR, HyundaiFlags
from iqdbc.iqpilot.car.hyundai.escc import EnhancedSmartCruiseControl
from iqdbc.iqpilot.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
def _use_stock_scc_surrogates(CP) -> bool:
return CP.carFingerprint == CAR.HYUNDAI_PALISADE
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",
@@ -34,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
@@ -42,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
@@ -59,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
@@ -76,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
@@ -88,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:
@@ -128,152 +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():
values = {
"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 _use_stock_scc_surrogates(CP):
values["ObjValid"] = 1
values["ACC_ObjStatus"] = 1
values["ACC_ObjDist"] = 1
return values
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():
values = {
"ComfortBandUpper": tuning.comfort_band_upper, # stock usually is 0 but sometimes uses higher values
"ComfortBandLower": tuning.comfort_band_lower, # stock usually is 0 but sometimes uses higher values
"JerkUpperLimit": tuning.jerk_upper, # stock usually is 1.0 but sometimes uses higher values
"JerkLowerLimit": tuning.jerk_lower, # stock usually is 0.5 but sometimes uses higher values
"ACCMode": 2 if enabled and long_override else 1 if enabled else 4, # stock will always be 4 instead of 0 after first disengage
"ObjGap": lead_data.object_gap, # 5: >30, m, 4: 25-30 m, 3: 20-25 m, 2: < 20 m, 0: no lead
}
if not _use_stock_scc_surrogates(CP):
values["ObjDistStat"] = lead_data.object_rel_gap
return values
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)
+767 -95
View File
@@ -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.iqpilot.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
+192 -133
View File
@@ -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, CAR, DBC, CANFD_RADAR_SCC_CAR, \
CANFD_UNSUPPORTED_LONGITUDINAL_CAR, \
UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags
UNSUPPORTED_LONGITUDINAL_CAR, HyundaiSafetyFlags, 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.iqpilot.car.hyundai.escc import ESCC_MSG
from iqdbc.iqpilot.car.hyundai.longitudinal.helpers import get_longitudinal_tune
from iqdbc.iqpilot.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,53 +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 = 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:
@@ -152,95 +250,56 @@ 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)
def init(CP, can_recv, can_send):
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
Params().put_int('LongitudinalPersonalityMax', 4)
if ret.flags & HyundaiFlagsIQ.ENHANCED_SCC:
ret.iqSafetyFlags |= HyundaiSafetyFlagsIQ.ESCC
stock_cp.radarUnavailable = False
if stock_cp.flags & HyundaiFlags.HAS_LDA_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)
return ret
@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
+851 -52
View File
@@ -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.iqpilot.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
View File
@@ -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
@@ -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
@@ -1,61 +0,0 @@
from iqdbc.can import CANParser, CANPacker
from iqdbc.car import Bus
from iqdbc.car.hyundai import hyundaican
from iqdbc.car.hyundai.values import CAR, DBC
class DummyHudControl:
leadDistanceBars = 3
leadVisible = True
class DummyLeadData:
lead_visible = False
lead_rel_speed = -7
lead_distance = 42
object_gap = 5
object_rel_gap = 2
class DummyTuning:
comfort_band_upper = 0.2
comfort_band_lower = 0.3
jerk_upper = 1.7
jerk_lower = 1.2
desired_accel = 0.4
actual_accel = 0.3
stopping = False
class DummyCP:
carFingerprint = CAR.HYUNDAI_PALISADE
flags = 0
def _decode(msg_name: str, addr: int, dat: bytes):
cp = CANParser(DBC[CAR.HYUNDAI_PALISADE][Bus.pt], [(msg_name, 0)], 0)
cp.update([(0, [(addr, dat, 0)])])
return cp.vl[msg_name]
def test_palisade_uses_stock_scc_surrogates():
packer = CANPacker(DBC[CAR.HYUNDAI_PALISADE][Bus.pt])
cp = DummyCP()
hud = DummyHudControl()
tuning = DummyTuning()
lead = DummyLeadData()
scc11 = hyundaican.create_acc_commands(
packer, True, 0.5, 3.0, 1, lead, hud, 72, False, False, True, cp, False, tuning
)[0]
scc14 = hyundaican.create_acc_commands(
packer, True, 0.5, 3.0, 1, lead, hud, 72, False, False, True, cp, False, tuning
)[2]
scc11_vals = _decode("SCC11", scc11[0], scc11[1])
assert scc11_vals["ObjValid"] == 1
assert scc11_vals["ACC_ObjStatus"] == 1
assert scc11_vals["ACC_ObjDist"] == 1
scc14_vals = _decode("SCC14", scc14[0], scc14[1])
assert "ObjDistStat" not in scc14_vals or scc14_vals["ObjDistStat"] == 0
@@ -0,0 +1,41 @@
import pytest
from iqdbc.car import gen_empty_fingerprint, structs
from iqdbc.car.hyundai.interface import CarInterface
from iqdbc.car.hyundai.values import CAR
@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
@@ -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
+276 -92
View File
@@ -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.iqpilot.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):
@@ -72,12 +85,7 @@ class HyundaiSafetyFlags(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
@@ -87,7 +95,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
@@ -103,7 +111,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
@@ -122,23 +130,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 <a href=\"https://comma.ai/shop/can-fd-panda-kit\" target=\"_blank\">CAN FD panda kit</a> if not using " +
"comma 3X for this <a href=\"https://en.wikipedia.org/wiki/CAN_FD\" target=\"_blank\">CAN FD car</a>.",
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
@@ -153,20 +179,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
@@ -174,6 +189,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),
@@ -260,9 +279,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]))],
@@ -285,6 +304,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
@@ -300,17 +324,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",
@@ -321,8 +345,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
@@ -362,11 +392,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])),
@@ -386,6 +437,37 @@ 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(
@@ -405,6 +487,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
@@ -421,16 +515,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])),
],
@@ -471,7 +562,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(
@@ -499,6 +590,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(
@@ -528,6 +620,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])),
@@ -537,6 +634,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])),
@@ -605,54 +710,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
@@ -660,6 +827,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]]:
@@ -840,11 +1008,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)
@@ -859,7 +1037,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)
+22
View File
@@ -332,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]:
@@ -348,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"""
+33 -38
View File
@@ -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,30 +38,23 @@ 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]
"SEAT_ALHAMBRA_MK1" = [2.5, 2.5, 0.1]
"HYUNDAI_SANTA_CRUZ_1ST_GEN" = [2.7, 2.7, 0.1]
"KIA_SPORTAGE_5TH_GEN" = [2.6, 2.6, 0.1]
"GENESIS_GV70_1ST_GEN" = [2.42, 2.42, 0.1]
@@ -82,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]
@@ -117,6 +93,25 @@ 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]
+10 -1
View File
@@ -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]
@@ -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,9 +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"
"VOLKSWAGEN_PASSAT_B7" = "VOLKSWAGEN_PASSAT_NMS"
"SUBARU_CROSSTREK_HYBRID" = "SUBARU_IMPREZA_2020"
"SUBARU_FORESTER_HYBRID" = "SUBARU_IMPREZA_2020"
@@ -88,22 +99,3 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"SUBARU_FORESTER_PREGLOBAL" = "SUBARU_IMPREZA"
"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"
"CHEVROLET_BOLT_NON_ACC" = "CHEVROLET_BOLT_EUV"
"CHEVROLET_BOLT_NON_ACC_1ST_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"
@@ -1,2 +1,3 @@
hyundai_kia_mando_front_radar.dbc
hyundai_kia_denso_front_radar.dbc
hyundai_kia_mando_corner_radar.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
File diff suppressed because it is too large Load Diff
@@ -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;
@@ -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)
@@ -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;
@@ -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)
@@ -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;
@@ -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)
File diff suppressed because it is too large Load Diff
@@ -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
""")
@@ -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
""")
@@ -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
+32 -27
View File
@@ -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";
@@ -1,3 +0,0 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
@@ -1,99 +0,0 @@
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.iqpilot.car.hyundai.values import HyundaiFlagsIQ
from iqdbc.iqpilot.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
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
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.MAIN_BTN_LONG_TOGGLE:
if any(be.type == ButtonType.mainCruise and be.pressed for be in ret.buttonEvents):
self.main_cruise_enabled = not self.main_cruise_enabled
else:
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
@@ -1,79 +0,0 @@
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.iqpilot.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
@@ -1,67 +0,0 @@
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}")
@@ -1,51 +0,0 @@
from iqdbc.car import structs
from iqdbc.iqpilot.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):
self.car_state = car_state
def update_scc12(self, values):
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
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
@@ -1,95 +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',
],
},
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.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',
],
},
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',
],
},
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\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\x00CN ESC \t 100!\x05\x01 58910-IB000',
],
(Ecu.transmission, 0x7e1, None): [
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'
],
},
}
@@ -1,111 +0,0 @@
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)
@@ -1,49 +0,0 @@
from dataclasses import dataclass, field
from iqdbc.car.hyundai.values import CAR
@dataclass
class CarTuningConfig:
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(
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(
lookahead_jerk_upper_v=[0.3, 0.7],
lookahead_jerk_lower_v=[0.2, 0.4],
),
"HYBRID": CarTuningConfig(),
"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(
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(
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,
)
}
@@ -1,288 +0,0 @@
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.iqpilot.car.hyundai.longitudinal.helpers import get_car_config, jerk_limited_integrator, ramp_update
from iqdbc.iqpilot.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/
"""
# 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/)
velocity: Current vehicle speed (m/s)
Returns:
Tuple of (upper_jerk, lower_jerk) in m/
"""
# 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/)
velocity: Current vehicle speed (m/s)
Returns:
Dynamic lower jerk limit (m/)
"""
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
@@ -1,52 +0,0 @@
import numpy as np
from iqdbc.car import structs, DT_CTRL, rate_limit
from iqdbc.car.hyundai.values import HyundaiFlags
from iqdbc.iqpilot.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.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
@@ -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.iqpilot.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')
self.pts[ii].vRel = msg['ACC_ObjRelSpd']
self.pts[ii].aRel = float('nan')
self.pts[ii].yvRel = float('nan')
else:
del self.pts[ii]
ret.points = list(self.pts.values())
return ret
@@ -1,25 +0,0 @@
from enum import IntFlag
class HyundaiSafetyFlagsIQ:
DEFAULT = 0
ESCC = 16
MAIN_BTN_LONG_TOGGLE = 32
HAS_LDA_BUTTON = 64
NON_SCC = 128
class HyundaiFlagsIQ(IntFlag):
ENHANCED_SCC = 1
HAS_LFA_BUTTON = 2
MAIN_BTN_LONG_TOGGLE = 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
NON_SCC_NO_FCA = 2 ** 8
SPEED_LIMIT_AVAILABLE = 2 ** 9
HAS_LKAS12 = 2 ** 10
@@ -8,11 +8,7 @@ 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.iqpilot.car.hyundai.enable_radar_tracks import enable_radar_tracks as hyundai_enable_radar_tracks
from iqdbc.iqpilot.car.hyundai.longitudinal.helpers import LongitudinalTuningType
from iqdbc.iqpilot.car.hyundai.values import HyundaiFlagsIQ
from iqdbc.iqpilot.car.subaru.values_ext import SubaruFlagsIQ, SubaruSafetyFlagsIQ
from iqdbc.iqpilot.car.tesla.values import TeslaFlagsIQ
from iqdbc.iqpilot.car.toyota.values import ToyotaFlagsIQ
@@ -81,7 +77,6 @@ def setup_interfaces(CI, CP: structs.CarParams, CP_IQ: structs.IQCarParams,
_initialize_custom_longitudinal_tuning(CI, CP, CP_IQ, params_dict)
_initialize_coop_steering(CP, CP_IQ, params_dict)
_initialize_radar_tracks(CP, CP_IQ, can_recv, can_send)
_initialize_stop_and_go(CP, CP_IQ, params_dict)
_initialize_toyota(CP, CP_IQ, params_dict)
@@ -89,16 +84,6 @@ def setup_interfaces(CI, CP: structs.CarParams, CP_IQ: structs.IQCarParams,
def _initialize_custom_longitudinal_tuning(CI, CP: structs.CarParams, CP_IQ: structs.IQCarParams,
params_dict: dict[str, str]) -> None:
# HKG longitudinal tuning lineage in this port traces to Jason Wen, James
# Vecellio-Grant, and carrotpilot; keep that attribution with this path.
# 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)
@@ -110,14 +95,6 @@ def _initialize_coop_steering(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 _initialize_stop_and_go(CP: structs.CarParams, CP_IQ: structs.IQCarParams, params_dict: dict[str, str]) -> None:
if CP.brand == 'subaru' and not CP.flags & (SubaruFlags.GLOBAL_GEN2 | SubaruFlags.HYBRID):
stop_and_go = int(params_dict.get("SubaruStopAndGo", 0)) == 1
+288 -330
View File
@@ -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,
+589 -228
View File
@@ -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,
+44 -90
View File
@@ -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 = 16,
HYUNDAI_PARAM_IQ_MAIN_BTN_LONG_TOGGLE = 32,
HYUNDAI_PARAM_IQ_HAS_LDA_BUTTON = 64,
HYUNDAI_PARAM_IQ_NON_SCC = 128,
};
// 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_main_btn_long_toggle;
bool hyundai_main_btn_long_toggle = 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_main_btn_long_toggle = GET_FLAG(current_safety_param_iq, HYUNDAI_PARAM_IQ_MAIN_BTN_LONG_TOGGLE);
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_main_btn_long_toggle) {
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;
}
+33 -283
View File
@@ -1,296 +1,46 @@
import unittest
from iqdbc.iqpilot.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.MAIN_BTN_LONG_TOGGLE 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.MAIN_BTN_LONG_TOGGLE
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.MAIN_BTN_LONG_TOGGLE
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.MAIN_BTN_LONG_TOGGLE
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")
+101 -563
View File
@@ -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.iqpilot.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}))
+98 -306
View File
@@ -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}))
@@ -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
+13 -17
View File
@@ -1,11 +1,6 @@
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
"""
# DISCLAIMER: This code is intended principally for development and debugging purposes.
# Although it provides a standalone entry point to the program, users should refer
# to the actual implementations for consumption. Usage outside of development scenarios
# is not advised and could lead to unpredictable results.
import threading
import traceback
@@ -13,26 +8,27 @@ from openpilot.common.realtime import Ratekeeper, config_realtime_process
from openpilot.iqpilot.iq_maps.road_data import debug_road_data
from openpilot.iqpilot.iq_maps.road_data.iq_road_layer import IQRoadLayer
ROAD_LAYER_HZ = 1
ROAD_LAYER_CORES = [0, 1, 2, 3]
def excepthook(args):
debug_road_data(f'IQ maps threading exception:\n{args}')
def _log_thread_exception(args) -> None:
debug_road_data(f"IQ maps threading exception:\n{args}")
traceback.print_exception(args.exc_type, args.exc_value, args.exc_traceback)
def live_map_data_iq_thread():
config_realtime_process([0, 1, 2, 3], 5)
live_map_iq = IQRoadLayer()
rk = Ratekeeper(1, print_delay_threshold=None)
def run() -> None:
config_realtime_process(ROAD_LAYER_CORES, 5)
layer = IQRoadLayer()
rk = Ratekeeper(ROAD_LAYER_HZ, print_delay_threshold=None)
while True:
live_map_iq.step()
layer.step()
rk.keep_time()
def main():
threading.excepthook = excepthook
live_map_data_iq_thread()
def main() -> None:
threading.excepthook = _log_thread_exception
run()
if __name__ == "__main__":
+77 -95
View File
@@ -1,21 +1,25 @@
#!/usr/bin/env python3
import hashlib
"""
Copyright © IQ.Lvbs, apart of Project Teal Lvbs, All Rights Reserved, licensed under https://konn3kt.com/tos
Installs the `mapd` binary by Jacob Pfeifer (github.com/pfeiferj/mapd) the binary is his work.
"""
import hashlib
import logging
import os
import stat
import time
import traceback
import requests
from pathlib import Path
from urllib.request import urlopen
import requests
from cereal import messaging
from openpilot.common.basedir import BASEDIR
from openpilot.common.params import Params
from openpilot.system.hardware.hw import Paths
from openpilot.common.spinner import Spinner
from openpilot.system.hardware.hw import Paths
from openpilot.system.version import is_prebuilt
from openpilot.iqpilot.iq_maps import VENDOR_MAPD_BIN_DIR, VENDOR_MAPD_PATH
import openpilot.system.sentry as sentry
@@ -23,17 +27,28 @@ import openpilot.system.sentry as sentry
VENDOR_RELEASE_TAG = "v2.0.6"
VENDOR_RELEASE_URL = f"https://github.com/pfeiferj/mapd/releases/download/{VENDOR_RELEASE_TAG}/mapd"
_VERSION_PARAM = "MapdVersion"
_HASH_FILE = os.path.join(BASEDIR, "iqpilot", "iq_maps", "tests", "mapd_hash")
_DOWNLOAD_TIMEOUT_S = 60
_MAX_DOWNLOAD_TRIES = 5
def get_file_hash(path: str) -> str:
"""Hex SHA-256 of a file's contents."""
with open(path, "rb") as handle:
return hashlib.file_digest(handle, "sha256").hexdigest()
def stamp_vendor_version(version: str, params: Params | None = None) -> None:
if params is None:
params = Params()
params.put("MapdVersion", version)
(params or Params()).put(_VERSION_PARAM, version)
def _expected_vendor_hash_path() -> str:
from openpilot.common.basedir import BASEDIR
return os.path.join(BASEDIR, "iqpilot", "iq_maps", "tests", "mapd_hash")
def _pinned_hash() -> str:
try:
with open(_HASH_FILE) as f:
return f.read().strip()
except OSError:
return ""
class VendorMapdInstaller:
@@ -41,98 +56,74 @@ class VendorMapdInstaller:
self._spinner = spinner_ref
self._params = Params()
def fetch(self) -> None:
self.ensure_directories_exist()
self._download_file()
stamp_vendor_version(VENDOR_RELEASE_TAG, self._params)
def get_installed_version(self) -> str:
return str(self._params.get(_VERSION_PARAM) or "")
def check_and_download(self) -> None:
if self.download_needed():
self.fetch()
@staticmethod
def ensure_directories_exist() -> None:
for d in (Paths.mapd_root(), VENDOR_MAPD_BIN_DIR):
os.makedirs(d, exist_ok=True)
def download_needed(self) -> bool:
if not os.path.exists(VENDOR_MAPD_PATH):
return True
if self.get_installed_version() != VENDOR_RELEASE_TAG:
return True
return not self._binary_hash_matches()
@staticmethod
def _binary_hash_matches() -> bool:
pinned = _pinned_hash()
if not pinned:
return False
try:
hash_path = _expected_vendor_hash_path()
with open(hash_path) as f:
expected = f.read().strip()
except Exception:
return True
if not expected:
return True
try:
return get_file_hash(VENDOR_MAPD_PATH) == expected
except Exception:
return get_file_hash(VENDOR_MAPD_PATH) != pinned
except OSError:
return True
@staticmethod
def ensure_directories_exist() -> None:
if not os.path.exists(Paths.mapd_root()):
os.makedirs(Paths.mapd_root())
if not os.path.exists(VENDOR_MAPD_BIN_DIR):
os.makedirs(VENDOR_MAPD_BIN_DIR)
def check_and_download(self) -> None:
if self.download_needed():
self.fetch()
@staticmethod
def _safe_write_and_set_executable(file_path: Path, content: bytes) -> None:
with open(file_path, 'wb') as output:
output.write(content)
output.flush()
os.fsync(output.fileno())
current_permissions = stat.S_IMODE(os.lstat(file_path).st_mode)
os.chmod(file_path, current_permissions | stat.S_IEXEC)
def fetch(self) -> None:
self.ensure_directories_exist()
if self._pull_binary():
stamp_vendor_version(VENDOR_RELEASE_TAG, self._params)
def _download_file(self, num_retries=5) -> None:
temp_file = Path(VENDOR_MAPD_PATH + ".tmp")
download_timeout = 60
for cnt in range(num_retries):
def _pull_binary(self) -> bool:
scratch = Path(f"{VENDOR_MAPD_PATH}.tmp")
for attempt in range(1, _MAX_DOWNLOAD_TRIES + 1):
try:
response = requests.get(VENDOR_RELEASE_URL, stream=True, timeout=download_timeout)
response.raise_for_status()
self._safe_write_and_set_executable(temp_file, response.content)
temp_file.replace(VENDOR_MAPD_PATH)
return
except requests.exceptions.ReadTimeout:
self._spinner.update(f"ReadTimeout caught. Timeout is [{download_timeout}]. Retrying download... [{cnt}]")
time.sleep(0.5)
resp = requests.get(VENDOR_RELEASE_URL, stream=True, timeout=_DOWNLOAD_TIMEOUT_S)
resp.raise_for_status()
with open(scratch, "wb") as out:
out.write(resp.content)
out.flush()
os.fsync(out.fileno())
mode = stat.S_IMODE(os.lstat(scratch).st_mode)
os.chmod(scratch, mode | stat.S_IEXEC)
scratch.replace(VENDOR_MAPD_PATH)
return True
except requests.exceptions.RequestException as e:
self._spinner.update(f"RequestException caught: {e}. Retrying download... [{cnt}]")
self._spinner.update(f"mapd download failed ({e}); retry {attempt}/{_MAX_DOWNLOAD_TRIES}")
time.sleep(0.5)
# Delete temp file if the process was not successful.
if temp_file.exists():
temp_file.unlink()
logging.error("Failed to download file after all retries")
def get_installed_version(self) -> str:
return str(self._params.get("MapdVersion") or "")
scratch.unlink(missing_ok=True)
logging.error("mapd binary download failed after %d attempts", _MAX_DOWNLOAD_TRIES)
return False
def wait_for_internet_connection(self, return_on_failure: bool = False) -> bool:
max_retries = 10
for retries in range(max_retries + 1):
self._spinner.update(f"Waiting for internet connection... [{retries}/{max_retries}]")
attempts = 10
for i in range(attempts + 1):
self._spinner.update(f"Waiting for internet connection... [{i}/{attempts}]")
time.sleep(2)
try:
_ = urlopen('https://sentry.io', timeout=10)
urlopen("https://sentry.io", timeout=10)
return True
except Exception as e:
print(f'Wait for internet failed: {e}')
if return_on_failure and retries == max_retries:
except Exception as e: # noqa: BLE001
print(f"Wait for internet failed: {e}")
if return_on_failure and i == attempts:
return False
return False
def non_prebuilt_install(self) -> None:
sm = messaging.SubMaster(['deviceState'])
metered = sm['deviceState'].networkMetered
if metered:
sm = messaging.SubMaster(["deviceState"])
if sm["deviceState"].networkMetered:
self._spinner.update("Can't proceed with mapd install since network is metered!")
time.sleep(5)
return
@@ -149,14 +140,11 @@ class VendorMapdInstaller:
time.sleep(0.1)
self.check_and_download()
self._spinner.close()
except Exception:
except Exception: # noqa: BLE001
for i in range(6):
self._spinner.update("Failed to download OSM maps won't work until properly downloaded!" +
"Try again manually rebooting. " +
f"Boot will continue in {5 - i}s...")
self._spinner.update("Failed to download OSM maps won't work until properly downloaded!"
f"Try again manually rebooting. Boot will continue in {5 - i}s...")
time.sleep(1)
sentry.init(sentry.SentryProject.SELFDRIVE)
traceback.print_exc()
sentry.capture_exception()
@@ -164,18 +152,12 @@ class VendorMapdInstaller:
if __name__ == "__main__":
spinner = Spinner()
install_manager = VendorMapdInstaller(spinner)
install_manager.ensure_directories_exist()
installer = VendorMapdInstaller(spinner)
installer.ensure_directories_exist()
if is_prebuilt():
debug_msg = f"[DEBUG] This is prebuilt, no vendor mapd install required. VERSION: [{VENDOR_RELEASE_TAG}], Param [{install_manager.get_installed_version()}]"
spinner.update(debug_msg)
spinner.update(f"[DEBUG] Prebuilt build; no vendor mapd install required. "
f"VERSION: [{VENDOR_RELEASE_TAG}], Param [{installer.get_installed_version()}]")
stamp_vendor_version(VENDOR_RELEASE_TAG)
else:
spinner.update(f"Checking if vendor mapd is installed and valid. Prebuilt [{is_prebuilt()}]")
install_manager.non_prebuilt_install()
def get_file_hash(path: str) -> str:
"""Hex SHA-256 of a file's contents."""
with open(path, "rb") as handle:
return hashlib.file_digest(handle, "sha256").hexdigest()
installer.non_prebuilt_install()
@@ -1,3 +1,4 @@
# openpilot model I/O constants (comma.ai, MIT — see LICENSE)
import numpy as np
@@ -14,7 +15,7 @@ class SplitModelConstants:
LEAD_T_OFFSETS = [0., 2., 4.]
META_T_IDXS = [2., 4., 6., 8., 10.]
# model inputs constants
# split-model temporal / history run parameters
MODEL_FREQ = 20
HISTORY_FREQ = 5
HISTORY_LEN_SECONDS = 5
+1 -1
View File
@@ -23,7 +23,7 @@ if [ -z "$AGNOS_VERSION" ]; then
case "$DEVICE_MODEL" in
*)
export AGNOS_VERSION="IQ.OS 4.5"
export AGNOS_VERSION="IQ.OS 4.8"
;;
esac
fi
+6 -6
View File
@@ -78,17 +78,17 @@
},
{
"name": "system",
"url": "https://sdn.konn3kt.com/agnos/16-iqlvbs/system-036bb0bcf945115c6488efadcdb56a42192201290a5fe4572ac7b46549146c79.img.xz",
"hash": "a0bf6d22e1134fc6c47158d63901c06324ea3b3808ed2fec35801a888cf3d526",
"hash_raw": "036bb0bcf945115c6488efadcdb56a42192201290a5fe4572ac7b46549146c79",
"url": "https://sdn.konn3kt.com/agnos/16-iqlvbs/system-756453317d208f873d44e14e9429d466c90cdcee70de52fede0bfdd6f6571c7b.img.xz",
"hash": "654de83dd64190701c5a9dc7297fb569ba106cc63217725893920df6b8c9eaa0",
"hash_raw": "756453317d208f873d44e14e9429d466c90cdcee70de52fede0bfdd6f6571c7b",
"size": 6291456000,
"sparse": true,
"full_check": false,
"has_ab": true,
"ondevice_hash": "9a08b97618dceceed48205ec674330bb97c7f76487a6cca2f68288aaa42aaf8e",
"ondevice_hash": "8269bd017b18a1a4fd5e093b96efa181fd803e200fa92364fe9307f25445f596",
"alt": {
"hash": "036bb0bcf945115c6488efadcdb56a42192201290a5fe4572ac7b46549146c79",
"url": "https://sdn.konn3kt.com/agnos/16-iqlvbs/system-036bb0bcf945115c6488efadcdb56a42192201290a5fe4572ac7b46549146c79.img",
"hash": "756453317d208f873d44e14e9429d466c90cdcee70de52fede0bfdd6f6571c7b",
"url": "https://sdn.konn3kt.com/agnos/16-iqlvbs/system-756453317d208f873d44e14e9429d466c90cdcee70de52fede0bfdd6f6571c7b.img",
"size": 6291456000
}
}
+1 -1
View File
@@ -1 +1 @@
Xmaq5VKDz8zpg4uJI4cTwgkgKp+HzFlL+5pzHfWvJXqVSNnlOZ/H5dNzm2MScLgzjnxcRYxferbIXjTyZKrzAw==
6ZRxEduDaLm1coUVvI/0QAZtmbf+tY0TWMZtaEaxV7I2fKFfGPG/6oOizuFsmd/SSQls84kap9MwKDEc8XfIDA==
+6 -6
View File
@@ -67,17 +67,17 @@
},
{
"name": "system",
"url": "https://sdn.konn3kt.com/agnos/16-iqlvbs/system-036bb0bcf945115c6488efadcdb56a42192201290a5fe4572ac7b46549146c79.img.xz",
"hash": "a0bf6d22e1134fc6c47158d63901c06324ea3b3808ed2fec35801a888cf3d526",
"hash_raw": "036bb0bcf945115c6488efadcdb56a42192201290a5fe4572ac7b46549146c79",
"url": "https://sdn.konn3kt.com/agnos/16-iqlvbs/system-756453317d208f873d44e14e9429d466c90cdcee70de52fede0bfdd6f6571c7b.img.xz",
"hash": "654de83dd64190701c5a9dc7297fb569ba106cc63217725893920df6b8c9eaa0",
"hash_raw": "756453317d208f873d44e14e9429d466c90cdcee70de52fede0bfdd6f6571c7b",
"size": 6291456000,
"sparse": true,
"full_check": false,
"has_ab": true,
"ondevice_hash": "9a08b97618dceceed48205ec674330bb97c7f76487a6cca2f68288aaa42aaf8e",
"ondevice_hash": "8269bd017b18a1a4fd5e093b96efa181fd803e200fa92364fe9307f25445f596",
"alt": {
"hash": "036bb0bcf945115c6488efadcdb56a42192201290a5fe4572ac7b46549146c79",
"url": "https://sdn.konn3kt.com/agnos/16-iqlvbs/system-036bb0bcf945115c6488efadcdb56a42192201290a5fe4572ac7b46549146c79.img",
"hash": "756453317d208f873d44e14e9429d466c90cdcee70de52fede0bfdd6f6571c7b",
"url": "https://sdn.konn3kt.com/agnos/16-iqlvbs/system-756453317d208f873d44e14e9429d466c90cdcee70de52fede0bfdd6f6571c7b.img",
"size": 6291456000
}
}
@@ -1 +1 @@
IeObYseNfOAYVt6hNKkFMX+RmBAQBU9iiwbox8y6sUdZZs7ZdrUqWJ1ou6yxxsx2JCkgOCQk8z9yT5frz5CeDg==
+gqhJbKMr9i9lW7WrtKebqKXlM0Asr/i7ZodOzIAHzAgzGEvPCWbfco2jo0/jO7O2UzZwKJUl/WzHlsOtJvnCw==
+17 -5
View File
@@ -33,10 +33,19 @@ EMOJI_REGEX = re.compile(
flags=re.UNICODE
)
_emoji_font_loaded = False
def _load_emoji_font() -> ImageFont.FreeTypeFont | None:
global _emoji_font
if _emoji_font is None:
_emoji_font = ImageFont.truetype(str(FONT_DIR.joinpath("NotoColorEmoji.ttf")), 109)
global _emoji_font, _emoji_font_loaded
if not _emoji_font_loaded:
_emoji_font_loaded = True
try:
# FONT_DIR is an importlib.resources path. Inside the setup zipapp it points into the archive,
# so str() yields a path through the .zip that PIL can't open ("cannot open resource"). Read
# the bytes and hand PIL a file object so it works both on disk and inside the zipapp.
_emoji_font = ImageFont.truetype(io.BytesIO(FONT_DIR.joinpath("NotoColorEmoji.ttf").read_bytes()), 109)
except Exception:
_emoji_font = None # never crash the whole UI over an emoji glyph
return _emoji_font
def find_emoji(text):
@@ -44,12 +53,15 @@ def find_emoji(text):
def emoji_tex(emoji):
if emoji not in _cache:
font = _load_emoji_font()
if font is None:
return None
img = Image.new("RGBA", (128, 128), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
draw.text((0, 0), emoji, font=_load_emoji_font(), embedded_color=True)
draw.text((0, 0), emoji, font=font, embedded_color=True)
with io.BytesIO() as buffer:
img.save(buffer, format="PNG")
l = buffer.tell()
buffer.seek(0)
_cache[emoji] = rl.load_texture_from_image(rl.load_image_from_memory(".png", buffer.getvalue(), l))
return _cache[emoji]
return _cache.get(emoji)
+10 -2
View File
@@ -50,6 +50,8 @@ INSTALLER_URL_PATH = "/tmp/installer_url"
# "<user>/<branch>" maps to a GitHub fork. IQ.OS uses the DRM "magic" compositor, not Wayland,
# so comma's downloaded installers (installer.comma.ai) crash on launch; clone the fork directly.
GITHUB_FORK_URL = "https://github.com/{user}/openpilot.git"
# IQ.Pilot lives on the IQ Lvbs git server; github.com/IQLvbs is DMCA'd and dead.
GIT_URL_OVERRIDES = {"IQLvbs": "https://git.konn3kt.com/IQ.Lvbs/IQ.Pilot.git"}
CONTINUE = """#!/usr/bin/env bash
@@ -756,7 +758,7 @@ class Setup(Widget):
pass
def _fork_install_thread(self, user: str, branch: str):
git_url = GITHUB_FORK_URL.format(user=user)
git_url = GIT_URL_OVERRIDES.get(user) or GITHUB_FORK_URL.format(user=user)
label = f"{user}/{branch}"
try:
subprocess.run(["rm", "-rf", TMP_INSTALL_PATH], check=False)
@@ -774,7 +776,8 @@ class Setup(Widget):
subprocess.run(["git", "-C", TMP_INSTALL_PATH, "submodule", "update", "--init"], check=False)
run_cmd(["rm", "-f", VALID_CACHE_PATH])
run_cmd(["rm", "-rf", INSTALL_PATH])
# sudo: a prior *run* install can leave root-owned .pyc here that a comma-user rm can't delete.
run_cmd(["sudo", "rm", "-rf", INSTALL_PATH])
run_cmd(["mv", TMP_INSTALL_PATH, INSTALL_PATH])
self._ble_progress("installing", 90)
@@ -882,6 +885,11 @@ class Setup(Widget):
# AGNOS might try to execute the installer before this process exits.
# Therefore, important to close the fd before renaming the installer.
os.close(fd)
# comma's ELF installer does `rm -rf /data/openpilot` as the comma user and asserts it
# succeeds; a prior *run* install leaves root-owned __pycache__ .pyc it can't delete, so it
# aborts before continue.sh and bounces back to setup. Clear the old tree first (sudo) so the
# installer's rm succeeds.
subprocess.run(["sudo", "rm", "-rf", INSTALL_PATH], check=False)
os.rename(tmpfile, INSTALLER_DESTINATION_PATH)
with open(INSTALLER_URL_PATH, "w") as f:
+10 -2
View File
@@ -51,6 +51,8 @@ INSTALLER_DESTINATION_PATH = "/tmp/installer"
INSTALLER_URL_PATH = "/tmp/installer_url"
GITHUB_FORK_URL = "https://github.com/{user}/openpilot.git"
# IQ.Pilot lives on the IQ Lvbs git server; github.com/IQLvbs is DMCA'd and dead.
GIT_URL_OVERRIDES = {"IQLvbs": "https://git.konn3kt.com/IQ.Lvbs/IQ.Pilot.git"}
CONTINUE = """#!/usr/bin/env bash
@@ -589,7 +591,7 @@ class Setup(Widget):
pass
def _fork_install_thread(self, user: str, branch: str):
git_url = GITHUB_FORK_URL.format(user=user)
git_url = GIT_URL_OVERRIDES.get(user) or GITHUB_FORK_URL.format(user=user)
label = f"{user}/{branch}"
fail_msg = "Ensure the entered URL is valid, and the device's internet connection is good."
try:
@@ -609,7 +611,8 @@ class Setup(Widget):
subprocess.run(["git", "-C", TMP_INSTALL_PATH, "submodule", "update", "--init"], check=False)
run_cmd(["rm", "-f", VALID_CACHE_PATH])
run_cmd(["rm", "-rf", INSTALL_PATH])
# sudo: a prior *run* install can leave root-owned .pyc here that a comma-user rm can't delete.
run_cmd(["sudo", "rm", "-rf", INSTALL_PATH])
run_cmd(["mv", TMP_INSTALL_PATH, INSTALL_PATH])
self._ble_progress("installing", 90)
@@ -718,6 +721,11 @@ class Setup(Widget):
# AGNOS might try to execute the installer before this process exits.
# Therefore, important to close the fd before renaming the installer.
os.close(fd)
# comma's ELF installer does `rm -rf /data/openpilot` as the comma user and asserts it
# succeeds; a prior *run* install leaves root-owned __pycache__ .pyc it can't delete, so it
# aborts before continue.sh and bounces back to setup. Clear the old tree first (sudo) so the
# installer's rm succeeds.
subprocess.run(["sudo", "rm", "-rf", INSTALL_PATH], check=False)
os.rename(tmpfile, INSTALLER_DESTINATION_PATH)
with open(INSTALLER_URL_PATH, "w") as f:
+5 -3
View File
@@ -406,7 +406,8 @@ class Label(Widget):
line_pos.x += width_before.x
tex = emoji_tex(emoji)
rl.draw_texture_ex(tex, line_pos, 0.0, self._font_size / tex.height * FONT_SCALE, self._text_color)
if tex is not None:
rl.draw_texture_ex(tex, line_pos, 0.0, self._font_size / tex.height * FONT_SCALE, self._text_color)
line_pos.x += self._font_size * FONT_SCALE
prev_index = end
rl.draw_text_ex(self._font, text[prev_index:], line_pos, self._font_size, 0, self._text_color)
@@ -849,8 +850,9 @@ class UnifiedLabel(Widget):
# Draw emoji
tex = emoji_tex(emoji)
emoji_scale = self._font_size / tex.height * FONT_SCALE
rl.draw_texture_ex(tex, line_pos, 0.0, emoji_scale, self._text_color)
if tex is not None:
emoji_scale = self._font_size / tex.height * FONT_SCALE
rl.draw_texture_ex(tex, line_pos, 0.0, emoji_scale, self._text_color)
# Emoji width is font_size * FONT_SCALE (as per measure_text_cached)
line_pos.x += self._font_size * FONT_SCALE
prev_index = end