diff --git a/.gitignore b/.gitignore index 8ed8c2c0ca..6ed87a3f85 100644 --- a/.gitignore +++ b/.gitignore @@ -3,11 +3,14 @@ venv/ .tags .ipynb_checkpoints .idea +.overlay_init +.overlay_consistent .sconsign.dblite .vscode model2.png a.out +*.dylib *.DSYM *.d *.pyc @@ -27,6 +30,7 @@ a.out config.json clcache +persist board/obj/ selfdrive/boardd/boardd selfdrive/logcatd/logcatd @@ -51,4 +55,5 @@ panda_jungle .coverage* htmlcov +pandaextra diff --git a/Dockerfile.openpilot b/Dockerfile.openpilot index b5a140c5a8..9faa5c282b 100644 --- a/Dockerfile.openpilot +++ b/Dockerfile.openpilot @@ -17,12 +17,14 @@ RUN apt-get update && apt-get install -y \ libffi-dev \ libglew-dev \ libgles2-mesa-dev \ + libglfw3-dev \ libglib2.0-0 \ liblzma-dev \ libmysqlclient-dev \ libomp-dev \ libopencv-dev \ libssl-dev \ + libsqlite3-dev \ libtool \ libusb-1.0-0-dev \ libzmq5-dev \ diff --git a/Pipfile b/Pipfile index 4f8bc525e8..4d3e046de0 100644 --- a/Pipfile +++ b/Pipfile @@ -8,71 +8,54 @@ opencv-python= "==3.4.2.17" PyQt5 = "*" ipython = "*" networkx = "==2.3" -azure-common = "==1.1.23" +azure-core = "==1.1.1" +azure-common = "==1.1.24" azure-nspkg = "==3.0.2" azure-storage-blob = "==2.1.0" azure-storage-common = "==2.1.0" azure-storage-nspkg = "==3.1.0" -bincopy = "*" -bleach = "*" boto = "*" "boto3" = "*" -celery = "*" control = "*" datadog = "*" -decorator = "*" dlib = "*" -dominate = "*" elasticsearch = "*" -fasteners = "*" future = "*" futures = "*" -gevent = "*" pycocotools = {git = "https://github.com/cocodataset/cocoapi.git",subdirectory = "PythonAPI"} gunicorn = "*" "h5py" = "*" hexdump = "*" "html5lib" = "*" imageio = "*" -intervaltree = "*" ipykernel = "*" joblib = "*" json-logging-py = "*" jupyter = "*" libarchive = "*" lru-dict = "*" -lxml = "*" "mpld3" = "*" msgpack-python = "*" nbstripout = "*" -nose-parameterized = "*" numpy = "*" osmium = "*" pbr = "*" percache = "*" pprofile = "*" -psutil = "*" pycurl = "*" git-pylint-commit-hook = "*" pymongo = "*" "pynmea2" = "*" pypolyline = "*" -pysendfile = "*" python-logstash = "*" -pyvcd = "*" redis = "*" -redlock = "*" "s2sphere" = "*" scikit-image = "*" "subprocess32" = "*" -supervisor = "*" tenacity = "*" tensorflow-gpu = "" -utm = "*" -"v4l2" = "*" PyJWT = "==1.4.1" PyMySQL = "==0.9.2" -Theano = "*" Werkzeug = "*" "backports.lzma" = "*" Flask-Cors = "*" @@ -84,7 +67,6 @@ PyNaCl = "*" reverse_geocoder = "*" Shapely = "*" SQLAlchemy = "*" -uWSGI = "*" scipy = "*" fastcluster = "*" backports-abc = "*" @@ -92,15 +74,13 @@ pygame = "*" simplejson = "*" python-logstash-async = "*" seaborn = "*" -tensorflow-estimator = "*" pyproj = "*" mock = "*" -blinker = "*" -gast = "==0.2.2" matplotlib = "*" dictdiffer = "*" aenum = "*" coverage = "*" +azure-cli-core = "*" [packages] overpy = {git = "https://github.com/commaai/python-overpy.git",ref = "f86529af402d4642e1faeb146671c40284007323"} @@ -144,6 +124,5 @@ pillow = "*" scons = "*" cysignals = "*" - [requires] python_version = "3.7.3" diff --git a/Pipfile.lock b/Pipfile.lock index b4e69cd059..045857cd1b 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "2b47bb704ca3062d9bc7c03a02ffb17fb82bf1cd9d3263c7d3d66fb160bf6dc2" + "sha256": "bc5d2f0b8b59443cbdf4373de05f7522ff24afa7f6e55d1aae08c3961e970beb" }, "pipfile-spec": 6, "requires": { @@ -34,10 +34,10 @@ }, "certifi": { "hashes": [ - "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50", - "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef" + "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", + "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" ], - "version": "==2019.9.11" + "version": "==2019.11.28" }, "cffi": { "hashes": [ @@ -202,11 +202,11 @@ }, "gunicorn": { "hashes": [ - "sha256:0806b5e8a2eb8ba9ac1be65d7b743ec896fc25f5d6cb16c5e051540157b315bb", - "sha256:ef69dea4814df95e64e3f40b47b7ffedc6911c5009233be9d01cfd0d14aa3f50" + "sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626", + "sha256:cd4a810dd51bf497552cf3f863b575dabd73d6ad6a91075b65936b151cbf4f9c" ], "index": "pypi", - "version": "==20.0.0" + "version": "==20.0.4" }, "hexdump": { "hashes": [ @@ -249,11 +249,11 @@ }, "json-rpc": { "hashes": [ - "sha256:35d22e2179c4c8b20d66b044ef45da3138a87b4730f25f6126444d7b4feca69e", - "sha256:8a72c3b33c851cd39899cd77b4da98cf036be72b609943f59ca1b73ffe70ff28" + "sha256:84b45058e5ba95f49c7b6afcf7e03ab86bee89bf2c01f3ad8dd41fe114fc1f84", + "sha256:def0dbcf5b7084fc31d677f2f5990d988d06497f2f47f13024274cfb2d5d7589" ], "index": "pypi", - "version": "==1.12.2" + "version": "==1.13.0" }, "lazy-object-proxy": { "hashes": [ @@ -352,30 +352,30 @@ }, "numpy": { "hashes": [ - "sha256:0a7a1dd123aecc9f0076934288ceed7fd9a81ba3919f11a855a7887cbe82a02f", - "sha256:0c0763787133dfeec19904c22c7e358b231c87ba3206b211652f8cbe1241deb6", - "sha256:3d52298d0be333583739f1aec9026f3b09fdfe3ddf7c7028cb16d9d2af1cca7e", - "sha256:43bb4b70585f1c2d153e45323a886839f98af8bfa810f7014b20be714c37c447", - "sha256:475963c5b9e116c38ad7347e154e5651d05a2286d86455671f5b1eebba5feb76", - "sha256:64874913367f18eb3013b16123c9fed113962e75d809fca5b78ebfbb73ed93ba", - "sha256:683828e50c339fc9e68720396f2de14253992c495fdddef77a1e17de55f1decc", - "sha256:6ca4000c4a6f95a78c33c7dadbb9495c10880be9c89316aa536eac359ab820ae", - "sha256:75fd817b7061f6378e4659dd792c84c0b60533e867f83e0d1e52d5d8e53df88c", - "sha256:7d81d784bdbed30137aca242ab307f3e65c8d93f4c7b7d8f322110b2e90177f9", - "sha256:8d0af8d3664f142414fd5b15cabfd3b6cc3ef242a3c7a7493257025be5a6955f", - "sha256:9679831005fb16c6df3dd35d17aa31dc0d4d7573d84f0b44cc481490a65c7725", - "sha256:a8f67ebfae9f575d85fa859b54d3bdecaeece74e3274b0b5c5f804d7ca789fe1", - "sha256:acbf5c52db4adb366c064d0b7c7899e3e778d89db585feadd23b06b587d64761", - "sha256:ada4805ed51f5bcaa3a06d3dd94939351869c095e30a2b54264f5a5004b52170", - "sha256:c7354e8f0eca5c110b7e978034cd86ed98a7a5ffcf69ca97535445a595e07b8e", - "sha256:e2e9d8c87120ba2c591f60e32736b82b67f72c37ba88a4c23c81b5b8fa49c018", - "sha256:e467c57121fe1b78a8f68dd9255fbb3bb3f4f7547c6b9e109f31d14569f490c3", - "sha256:ede47b98de79565fcd7f2decb475e2dcc85ee4097743e551fe26cfc7eb3ff143", - "sha256:f58913e9227400f1395c7b800503ebfdb0772f1c33ff8cb4d6451c06cabdf316", - "sha256:fe39f5fd4103ec4ca3cb8600b19216cd1ff316b4990f4c0b6057ad982c0a34d5" - ], - "index": "pypi", - "version": "==1.17.4" + "sha256:1786a08236f2c92ae0e70423c45e1e62788ed33028f94ca99c4df03f5be6b3c6", + "sha256:17aa7a81fe7599a10f2b7d95856dc5cf84a4eefa45bc96123cbbc3ebc568994e", + "sha256:20b26aaa5b3da029942cdcce719b363dbe58696ad182aff0e5dcb1687ec946dc", + "sha256:2d75908ab3ced4223ccba595b48e538afa5ecc37405923d1fea6906d7c3a50bc", + "sha256:39d2c685af15d3ce682c99ce5925cc66efc824652e10990d2462dfe9b8918c6a", + "sha256:56bc8ded6fcd9adea90f65377438f9fea8c05fcf7c5ba766bef258d0da1554aa", + "sha256:590355aeade1a2eaba17617c19edccb7db8d78760175256e3cf94590a1a964f3", + "sha256:70a840a26f4e61defa7bdf811d7498a284ced303dfbc35acb7be12a39b2aa121", + "sha256:77c3bfe65d8560487052ad55c6998a04b654c2fbc36d546aef2b2e511e760971", + "sha256:9537eecf179f566fd1c160a2e912ca0b8e02d773af0a7a1120ad4f7507cd0d26", + "sha256:9acdf933c1fd263c513a2df3dceecea6f3ff4419d80bf238510976bf9bcb26cd", + "sha256:ae0975f42ab1f28364dcda3dde3cf6c1ddab3e1d4b2909da0cb0191fa9ca0480", + "sha256:b3af02ecc999c8003e538e60c89a2b37646b39b688d4e44d7373e11c2debabec", + "sha256:b6ff59cee96b454516e47e7721098e6ceebef435e3e21ac2d6c3b8b02628eb77", + "sha256:b765ed3930b92812aa698a455847141869ef755a87e099fddd4ccf9d81fffb57", + "sha256:c98c5ffd7d41611407a1103ae11c8b634ad6a43606eca3e2a5a269e5d6e8eb07", + "sha256:cf7eb6b1025d3e169989416b1adcd676624c2dbed9e3bcb7137f51bfc8cc2572", + "sha256:d92350c22b150c1cae7ebb0ee8b5670cc84848f6359cf6b5d8f86617098a9b73", + "sha256:e422c3152921cece8b6a2fb6b0b4d73b6579bd20ae075e7d15143e711f3ca2ca", + "sha256:e840f552a509e3380b0f0ec977e8124d0dc34dc0e68289ca28f4d7c1d0d79474", + "sha256:f3d0a94ad151870978fb93538e95411c83899c9dc63e6fb65542f769568ecfa5" + ], + "index": "pypi", + "version": "==1.18.1" }, "overpy": { "git": "https://github.com/commaai/python-overpy.git", @@ -384,56 +384,48 @@ }, "pillow": { "hashes": [ - "sha256:047d9473cf68af50ac85f8ee5d5f21a60f849bc17d348da7fc85711287a75031", - "sha256:0f66dc6c8a3cc319561a633b6aa82c44107f12594643efa37210d8c924fc1c71", - "sha256:12c9169c4e8fe0a7329e8658c7e488001f6b4c8e88740e76292c2b857af2e94c", - "sha256:248cffc168896982f125f5c13e9317c059f74fffdb4152893339f3be62a01340", - "sha256:27faf0552bf8c260a5cee21a76e031acaea68babb64daf7e8f2e2540745082aa", - "sha256:285edafad9bc60d96978ed24d77cdc0b91dace88e5da8c548ba5937c425bca8b", - "sha256:384b12c9aa8ef95558abdcb50aada56d74bc7cc131dd62d28c2d0e4d3aadd573", - "sha256:38950b3a707f6cef09cd3cbb142474357ad1a985ceb44d921bdf7b4647b3e13e", - "sha256:4aad1b88933fd6dc2846552b89ad0c74ddbba2f0884e2c162aa368374bf5abab", - "sha256:4ac6148008c169603070c092e81f88738f1a0c511e07bd2bb0f9ef542d375da9", - "sha256:4deb1d2a45861ae6f0b12ea0a786a03d19d29edcc7e05775b85ec2877cb54c5e", - "sha256:59aa2c124df72cc75ed72c8d6005c442d4685691a30c55321e00ed915ad1a291", - "sha256:5a47d2123a9ec86660fe0e8d0ebf0aa6bc6a17edc63f338b73ea20ba11713f12", - "sha256:5cc901c2ab9409b4b7ac7b5bcc3e86ac14548627062463da0af3b6b7c555a871", - "sha256:6c1db03e8dff7b9f955a0fb9907eb9ca5da75b5ce056c0c93d33100a35050281", - "sha256:7ce80c0a65a6ea90ef9c1f63c8593fcd2929448613fc8da0adf3e6bfad669d08", - "sha256:809c19241c14433c5d6135e1b6c72da4e3b56d5c865ad5736ab99af8896b8f41", - "sha256:83792cb4e0b5af480588601467c0764242b9a483caea71ef12d22a0d0d6bdce2", - "sha256:846fa202bd7ee0f6215c897a1d33238ef071b50766339186687bd9b7a6d26ac5", - "sha256:9f5529fc02009f96ba95bea48870173426879dc19eec49ca8e08cd63ecd82ddb", - "sha256:a423c2ea001c6265ed28700df056f75e26215fd28c001e93ef4380b0f05f9547", - "sha256:ac4428094b42907aba5879c7c000d01c8278d451a3b7cccd2103e21f6397ea75", - "sha256:b1ae48d87f10d1384e5beecd169c77502fcc04a2c00a4c02b85f0a94b419e5f9", - "sha256:bf4e972a88f8841d8fdc6db1a75e0f8d763e66e3754b03006cbc3854d89f1cb1", - "sha256:c6414f6aad598364aaf81068cabb077894eb88fed99c6a65e6e8217bab62ae7a", - "sha256:c710fcb7ee32f67baf25aa9ffede4795fd5d93b163ce95fdc724383e38c9df96", - "sha256:c7be4b8a09852291c3c48d3c25d1b876d2494a0a674980089ac9d5e0d78bd132", - "sha256:c9e5ffb910b14f090ac9c38599063e354887a5f6d7e6d26795e916b4514f2c1a", - "sha256:e0697b826da6c2472bb6488db4c0a7fa8af0d52fa08833ceb3681358914b14e5", - "sha256:e9a3edd5f714229d41057d56ac0f39ad9bdba6767e8c888c951869f0bdd129b0" - ], - "index": "pypi", - "version": "==6.2.1" + "sha256:0a628977ac2e01ca96aaae247ec2bd38e729631ddf2221b4b715446fd45505be", + "sha256:4d9ed9a64095e031435af120d3c910148067087541131e82b3e8db302f4c8946", + "sha256:54ebae163e8412aff0b9df1e88adab65788f5f5b58e625dc5c7f51eaf14a6837", + "sha256:5bfef0b1cdde9f33881c913af14e43db69815c7e8df429ceda4c70a5e529210f", + "sha256:5f3546ceb08089cedb9e8ff7e3f6a7042bb5b37c2a95d392fb027c3e53a2da00", + "sha256:5f7ae9126d16194f114435ebb79cc536b5682002a4fa57fa7bb2cbcde65f2f4d", + "sha256:62a889aeb0a79e50ecf5af272e9e3c164148f4bd9636cc6bcfa182a52c8b0533", + "sha256:7406f5a9b2fd966e79e6abdaf700585a4522e98d6559ce37fc52e5c955fade0a", + "sha256:8453f914f4e5a3d828281a6628cf517832abfa13ff50679a4848926dac7c0358", + "sha256:87269cc6ce1e3dee11f23fa515e4249ae678dbbe2704598a51cee76c52e19cda", + "sha256:875358310ed7abd5320f21dd97351d62de4929b0426cdb1eaa904b64ac36b435", + "sha256:8ac6ce7ff3892e5deaab7abaec763538ffd011f74dc1801d93d3c5fc541feee2", + "sha256:91b710e3353aea6fc758cdb7136d9bbdcb26b53cefe43e2cba953ac3ee1d3313", + "sha256:9d2ba4ed13af381233e2d810ff3bab84ef9f18430a9b336ab69eaf3cd24299ff", + "sha256:a62ec5e13e227399be73303ff301f2865bf68657d15ea50b038d25fc41097317", + "sha256:ab76e5580b0ed647a8d8d2d2daee170e8e9f8aad225ede314f684e297e3643c2", + "sha256:bf4003aa538af3f4205c5fac56eacaa67a6dd81e454ffd9e9f055fff9f1bc614", + "sha256:bf598d2e37cf8edb1a2f26ed3fb255191f5232badea4003c16301cb94ac5bdd0", + "sha256:c18f70dc27cc5d236f10e7834236aff60aadc71346a5bc1f4f83a4b3abee6386", + "sha256:c5ed816632204a2fc9486d784d8e0d0ae754347aba99c811458d69fcdfd2a2f9", + "sha256:dc058b7833184970d1248135b8b0ab702e6daa833be14035179f2acb78ff5636", + "sha256:ff3797f2f16bf9d17d53257612da84dd0758db33935777149b3334c01ff68865" + ], + "index": "pypi", + "version": "==7.0.0" }, "psutil": { "hashes": [ - "sha256:021d361439586a0fd8e64f8392eb7da27135db980f249329f1a347b9de99c695", - "sha256:145e0f3ab9138165f9e156c307100905fd5d9b7227504b8a9d3417351052dc3d", - "sha256:348ad4179938c965a27d29cbda4a81a1b2c778ecd330a221aadc7bd33681afbd", - "sha256:3feea46fbd634a93437b718518d15b5dd49599dfb59a30c739e201cc79bb759d", - "sha256:474e10a92eeb4100c276d4cc67687adeb9d280bbca01031a3e41fb35dfc1d131", - "sha256:47aeb4280e80f27878caae4b572b29f0ec7967554b701ba33cd3720b17ba1b07", - "sha256:73a7e002781bc42fd014dfebb3fc0e45f8d92a4fb9da18baea6fb279fbc1d966", - "sha256:d051532ac944f1be0179e0506f6889833cf96e466262523e57a871de65a15147", - "sha256:dfb8c5c78579c226841908b539c2374da54da648ee5a837a731aa6a105a54c00", - "sha256:e3f5f9278867e95970854e92d0f5fe53af742a7fc4f2eba986943345bcaed05d", - "sha256:e9649bb8fc5cea1f7723af53e4212056a6f984ee31784c10632607f472dec5ee" + "sha256:094f899ac3ef72422b7e00411b4ed174e3c5a2e04c267db6643937ddba67a05b", + "sha256:10b7f75cc8bd676cfc6fa40cd7d5c25b3f45a0e06d43becd7c2d2871cbb5e806", + "sha256:1b1575240ca9a90b437e5a40db662acd87bbf181f6aa02f0204978737b913c6b", + "sha256:21231ef1c1a89728e29b98a885b8e0a8e00d09018f6da5cdc1f43f988471a995", + "sha256:28f771129bfee9fc6b63d83a15d857663bbdcae3828e1cb926e91320a9b5b5cd", + "sha256:70387772f84fa5c3bb6a106915a2445e20ac8f9821c5914d7cbde148f4d7ff73", + "sha256:b560f5cd86cf8df7bcd258a851ca1ad98f0d5b8b98748e877a0aec4e9032b465", + "sha256:b74b43fecce384a57094a83d2778cdfc2e2d9a6afaadd1ebecb2e75e0d34e10d", + "sha256:e85f727ffb21539849e6012f47b12f6dd4c44965e56591d8dec6e8bc9ab96f4a", + "sha256:fd2e09bb593ad9bdd7429e779699d2d47c1268cbde4dda95fcd1bd17544a0217", + "sha256:ffad8eb2ac614518bbe3c0b8eb9dffdb3a8d2e3a7d5da51c5b974fb723a5c5aa" ], "index": "pypi", - "version": "==5.6.5" + "version": "==5.6.7" }, "pycapnp": { "hashes": [ @@ -536,22 +528,20 @@ }, "pyyaml": { "hashes": [ - "sha256:0113bc0ec2ad727182326b61326afa3d1d8280ae1122493553fd6f4397f33df9", - "sha256:01adf0b6c6f61bd11af6e10ca52b7d4057dd0be0343eb9283c878cf3af56aee4", - "sha256:5124373960b0b3f4aa7df1707e63e9f109b5263eca5976c66e08b1c552d4eaf8", - "sha256:5ca4f10adbddae56d824b2c09668e91219bb178a1eee1faa56af6f99f11bf696", - "sha256:7907be34ffa3c5a32b60b95f4d95ea25361c951383a894fec31be7252b2b6f34", - "sha256:7ec9b2a4ed5cad025c2278a1e6a19c011c80a3caaac804fd2d329e9cc2c287c9", - "sha256:87ae4c829bb25b9fe99cf71fbb2140c448f534e24c998cc60f39ae4f94396a73", - "sha256:9de9919becc9cc2ff03637872a440195ac4241c80536632fffeb6a1e25a74299", - "sha256:a5a85b10e450c66b49f98846937e8cfca1db3127a9d5d1e31ca45c3d0bef4c5b", - "sha256:b0997827b4f6a7c286c01c5f60384d218dca4ed7d9efa945c3e1aa623d5709ae", - "sha256:b631ef96d3222e62861443cc89d6563ba3eeb816eeb96b2629345ab795e53681", - "sha256:bf47c0607522fdbca6c9e817a6e81b08491de50f3766a7a0e6a5be7905961b41", - "sha256:f81025eddd0327c7d4cfe9b62cf33190e1e736cc6e97502b3ec425f574b3e7a8" + "sha256:059b2ee3194d718896c0ad077dd8c043e5e909d9180f387ce42012662a4946d6", + "sha256:1cf708e2ac57f3aabc87405f04b86354f66799c8e62c28c5fc5f88b5521b2dbf", + "sha256:24521fa2890642614558b492b473bee0ac1f8057a7263156b02e8b14c88ce6f5", + "sha256:4fee71aa5bc6ed9d5f116327c04273e25ae31a3020386916905767ec4fc5317e", + "sha256:70024e02197337533eef7b85b068212420f950319cc8c580261963aefc75f811", + "sha256:74782fbd4d4f87ff04159e986886931456a1894c61229be9eaf4de6f6e44b99e", + "sha256:940532b111b1952befd7db542c370887a8611660d2b9becff75d39355303d82d", + "sha256:cb1f2f5e426dc9f07a7681419fe39cee823bb74f723f36f70399123f439e9b20", + "sha256:dbbb2379c19ed6042e8f11f2a2c66d39cceb8aeace421bfc29d085d93eda3689", + "sha256:e3a057b7a64f1222b56e47bcff5e4b94c4f61faac04c7c4ecb1985e18caa3994", + "sha256:e9f45bd5b92c7974e59bcd2dcc8631a6b6cc380a904725fce7bc08872e691615" ], "index": "pypi", - "version": "==5.1.2" + "version": "==5.3" }, "pyzmq": { "hashes": [ @@ -605,11 +595,11 @@ }, "scons": { "hashes": [ - "sha256:822b99f82295dfa1270f613d63a9cd43cd007c7e98b48cee28067d9c3c9fd593", - "sha256:fd44f8f2a4562e7e5bc8c63c82b01e469e8115805a3e9c2923ee54cdcd6678b3" + "sha256:0f860678cd96fc943ff2294389b0f33cbe51080801591497bc652e72237f0176", + "sha256:8aaa483c303efeb678e6f7c776c8444a482f8ddc3ad891f8b6cdd35264da9a1f" ], "index": "pypi", - "version": "==3.1.1" + "version": "==3.1.2" }, "setproctitle": { "hashes": [ @@ -636,19 +626,19 @@ }, "sympy": { "hashes": [ - "sha256:71a11e5686ae7ab6cb8feb5bd2651ef4482f8fd43a7c27e645a165e4353b23e1", - "sha256:f9b00ec76151c98470e84f1da2d7d03633180b71fb318428ddccce1c867d3eaa" + "sha256:4880d3a351558063bd89febda302f220dc4b88de393bba81fa6539a3966f03fa", + "sha256:d77901d748287d15281f5ffe5b0fef62dd38f357c2b827c44ff07f35695f4e7e" ], "index": "pypi", - "version": "==1.4" + "version": "==1.5.1" }, "tqdm": { "hashes": [ - "sha256:9de4722323451eb7818deb0161d9d5523465353a6707a9f500d97ee42919b902", - "sha256:c1d677f3a85fa291b34bdf8f770f877119b9754b32673699653556f85e2c2f13" + "sha256:4789ccbb6fc122b5a6a85d512e4e41fc5acad77216533a6f2b8ce51e0f265c23", + "sha256:efab950cf7cc1e4d8ee50b2bb9c8e4a89f8307b49e0b2c9cfef3ec4ca26655eb" ], "index": "pypi", - "version": "==4.38.0" + "version": "==4.41.1" }, "typed-ast": { "hashes": [ @@ -693,11 +683,11 @@ }, "websocket-client": { "hashes": [ - "sha256:1151d5fb3a62dc129164292e1227655e4bbc5dd5340a5165dfae61128ec50aa9", - "sha256:1fd5520878b68b84b5748bb30e592b10d0a91529d5383f74f4964e72b297fd3a" + "sha256:0fc45c961324d79c781bab301359d5a1b00b13ad1b10415a4780229ef71a5549", + "sha256:d735b91d6d1692a6a181f2a8c9e0238e5f6373356f561bb9dc4c7af36f452010" ], "index": "pypi", - "version": "==0.56.0" + "version": "==0.57.0" }, "werkzeug": { "hashes": [ @@ -717,9 +707,16 @@ "develop": { "absl-py": { "hashes": [ - "sha256:d9129186431e150d7fe455f1cb1ecbb92bb5dba9da9bc3ef7b012d98c4db2526" + "sha256:75e737d6ce7723d9ff9b7aa1ba3233c34be62ef18d5859e706b8fdc828989830" ], - "version": "==0.8.1" + "version": "==0.9.0" + }, + "adal": { + "hashes": [ + "sha256:5a7f1e037c6290c6d7609cab33a9e5e988c2fbec5c51d1c4c649ee3faff37eaf", + "sha256:fd17e5661f60634ddf96a569b95d34ccb8a98de60593d729c28bdcfe360eaad1" + ], + "version": "==1.2.2" }, "aenum": { "hashes": [ @@ -730,21 +727,34 @@ "index": "pypi", "version": "==2.2.3" }, - "amqp": { + "antlr4-python3-runtime": { "hashes": [ - "sha256:6e649ca13a7df3faacdc8bbb280aa9a6602d22fd9d545336077e573a1f4ff3b8", - "sha256:77f1aef9410698d20eaeac5b73a87817365f457a507d82edf292e12cbb83b08d" + "sha256:168cdcec8fb9152e84a87ca6fd261b3d54c8f6358f42ab3b813b14a7193bb50b" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.5.2" + "markers": "python_version >= '3.0'", + "version": "==4.7.2" + }, + "applicationinsights": { + "hashes": [ + "sha256:30a11aafacea34f8b160fbdc35254c9029c7e325267874e3c68f6bdbcd6ed2c3", + "sha256:b88bc5a41385d8e516489128d5e63f8c52efe597a3579b1718d1ab2f7cf150a2" + ], + "version": "==0.11.9" + }, + "argcomplete": { + "hashes": [ + "sha256:52a08b426bd0b03b6881182dd84149b2493540d1c3109ccf9f09f78e4459e387", + "sha256:783d6a12c6c84a33653dc5bac4d6c0640ba64d1037c2662acd9dbe410c26056f" + ], + "version": "==1.11.0" }, "astor": { "hashes": [ - "sha256:0e41295809baf43ae8303350e031aff81ae52189b6f881f36d623fa8b2f1960e", - "sha256:37a6eed8b371f1228db08234ed7f6cfdc7817a3ed3824797e20cbb11dc2a7862" + "sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5", + "sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.8.0" + "version": "==0.8.1" }, "astroid": { "hashes": [ @@ -762,13 +772,50 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==19.3.0" }, + "azure-cli-core": { + "hashes": [ + "sha256:979954688c56cb76be7043e4c4ecc8433ce20dfc4d95ea42d6584b061cbafdb3", + "sha256:bcd371210ccc83a29884a9add0fa84702538092926eefa4dfdb5075d71ccb6c2" + ], + "index": "pypi", + "version": "==2.0.79" + }, + "azure-cli-nspkg": { + "hashes": [ + "sha256:1bde56090f548c6435bd3093995cf88e4c445fb040604df8b5b5f70780d79181", + "sha256:9a1e4f3197183470e4afecfdd45c92320f6753555b06a70651f89972332ffaf6" + ], + "version": "==3.0.4" + }, + "azure-cli-telemetry": { + "hashes": [ + "sha256:1f239d544d309c29e827982cc20113eb57037dba16db6cdd2e0283e437e0e577", + "sha256:7b18d7520e35e134136a0f7de38403a7dbce7b1e835065bd9e965579815ddf2f" + ], + "version": "==1.0.4" + }, "azure-common": { "hashes": [ - "sha256:53b1195b8f20943ccc0e71a17849258f7781bc6db1c72edc7d6c055f79bd54e3", - "sha256:99ef36e74b6395329aada288764ce80504da16ecc8206cb9a72f55fb02e8b484" + "sha256:184ad6a05a3089dfdc1ce07c1cbfa489bbc45b5f6f56e848cac0851e6443da21", + "sha256:3d64e9ab995300f42abd5bc0ef02f02bab661321e394d4dbacb4382ea1fb2f72" ], "index": "pypi", - "version": "==1.1.23" + "version": "==1.1.24" + }, + "azure-core": { + "hashes": [ + "sha256:4d047fd4e46a958c9b63f9d5cb52e6bf7dfc5c2a1c2a81b968499335a94bb5cb", + "sha256:b44fe5b46d2bb0260cafb737ab5ee89a16d478fc1885dabe21c426c4df205502" + ], + "index": "pypi", + "version": "==1.1.1" + }, + "azure-mgmt-resource": { + "hashes": [ + "sha256:a557a87fad2a2a5190d03e12cd7cf6307a194604e808773972c34847503b482b", + "sha256:e04e867af9289a237cfe285995025555fcceb90de5deb420c540dca3a4c9c622" + ], + "version": "==6.0.0" }, "azure-nspkg": { "hashes": [ @@ -825,36 +872,38 @@ "index": "pypi", "version": "==0.0.14" }, - "billiard": { - "hashes": [ - "sha256:01afcb4e7c4fd6480940cfbd4d9edc19d7a7509d6ada533984d0d0f49901ec82", - "sha256:b8809c74f648dfe69b973c8e660bcec00603758c9db8ba89d7719f88d5f01f26" + "bcrypt": { + "hashes": [ + "sha256:0258f143f3de96b7c14f762c770f5fc56ccd72f8a1857a451c1cd9a655d9ac89", + "sha256:0b0069c752ec14172c5f78208f1863d7ad6755a6fae6fe76ec2c80d13be41e42", + "sha256:19a4b72a6ae5bb467fea018b825f0a7d917789bcfe893e53f15c92805d187294", + "sha256:5432dd7b34107ae8ed6c10a71b4397f1c853bd39a4d6ffa7e35f40584cffd161", + "sha256:6305557019906466fc42dbc53b46da004e72fd7a551c044a827e572c82191752", + "sha256:69361315039878c0680be456640f8705d76cb4a3a3fe1e057e0f261b74be4b31", + "sha256:6fe49a60b25b584e2f4ef175b29d3a83ba63b3a4df1b4c0605b826668d1b6be5", + "sha256:74a015102e877d0ccd02cdeaa18b32aa7273746914a6c5d0456dd442cb65b99c", + "sha256:763669a367869786bb4c8fcf731f4175775a5b43f070f50f46f0b59da45375d0", + "sha256:8b10acde4e1919d6015e1df86d4c217d3b5b01bb7744c36113ea43d529e1c3de", + "sha256:9fe92406c857409b70a38729dbdf6578caf9228de0aef5bc44f859ffe971a39e", + "sha256:a190f2a5dbbdbff4b74e3103cef44344bc30e61255beb27310e2aec407766052", + "sha256:a595c12c618119255c90deb4b046e1ca3bcfad64667c43d1166f2b04bc72db09", + "sha256:c9457fa5c121e94a58d6505cadca8bed1c64444b83b3204928a866ca2e599105", + "sha256:cb93f6b2ab0f6853550b74e051d297c27a638719753eb9ff66d1e4072be67133", + "sha256:ce4e4f0deb51d38b1611a27f330426154f2980e66582dc5f438aad38b5f24fc1", + "sha256:d7bdc26475679dd073ba0ed2766445bb5b20ca4793ca0db32b399dccc6bc84b7", + "sha256:ff032765bb8716d9387fd5376d987a937254b0619eff0972779515b5c98820bc" ], - "version": "==3.6.1.0" - }, - "bincopy": { - "hashes": [ - "sha256:1b4c7219e01042cd8217fb6c12b66f6b0ff01d1986d27b0cb18fcdcf1ea3dcb7", - "sha256:3ba5fe82fc07cb1be40e5ff668a9869aabb5b264a9223b3ff4ded77273260c8c" - ], - "index": "pypi", - "version": "==16.1.3" + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==3.1.7" }, "bleach": { "hashes": [ "sha256:213336e49e102af26d9cde77dd2d0397afabc5a6bf2fed985dc35b5d1e285a16", "sha256:3fdf7f77adcf649c9911387df51254b813185e32b2c6619f690b593a617e19fa" ], - "index": "pypi", + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==3.1.0" }, - "blinker": { - "hashes": [ - "sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6" - ], - "index": "pypi", - "version": "==1.4" - }, "boto": { "hashes": [ "sha256:147758d41ae7240dc989f0039f27da8ca0d53734be0eb869ef16e3adcfa462e8", @@ -865,40 +914,33 @@ }, "boto3": { "hashes": [ - "sha256:165e967db773b14e7a8d430e0dca6da0306fe12db8aff23e9a36e408704b1b45", - "sha256:f60eb8ff4e782c78f09d5ee9a0398185ff45ea799902e3485c18a3de44c55df8" + "sha256:b3b134d8df25ba2465eb4c39b642aaa7b5342917c7810dc24c0aeb866bc6d816", + "sha256:ff3539243b9d8fde9a1e86f8e79a5ae385ccb583ec2a1083f3a63aed078aa42d" ], "index": "pypi", - "version": "==1.10.23" + "version": "==1.10.47" }, "botocore": { "hashes": [ - "sha256:4389d2e97a453f769b613d66128148ae0179d56c12651d27bcb6aec9e2bf5fea", - "sha256:6c7cf235dcb4ff27eb240fa62fc1cb9e1438578116cd8e9179111dbb4f9b325e" + "sha256:a5187cc5ec9558890ce5522a3c7e73c812cbae31c6d905d13a868e861a771272", + "sha256:b7d1001208a0c514ced7b126606dae360ca5e0141cc9496d37f83a2c89ebd915" ], - "version": "==1.13.23" + "version": "==1.13.47" }, "cachetools": { "hashes": [ - "sha256:428266a1c0d36dc5aca63a2d7c5942e88c2c898d72139fca0e97fdd2380517ae", - "sha256:8ea2d3ce97850f31e4a08b0e2b5e6c34997d7216a9d2c98e0f3978630d4da69a" - ], - "version": "==3.1.1" - }, - "celery": { - "hashes": [ - "sha256:4c4532aa683f170f40bd76f928b70bc06ff171a959e06e71bf35f2f9d6031ef9", - "sha256:528e56767ae7e43a16cfef24ee1062491f5754368d38fcfffa861cdb9ef219be" + "sha256:9a52dd97a85f257f4e4127f15818e71a0c7899f121b34591fcc1173ea79a0198", + "sha256:b304586d357c43221856be51d73387f93e2a961598a9b6b6670664746f3b6c6c" ], - "index": "pypi", - "version": "==4.3.0" + "markers": "python_version ~= '3.5'", + "version": "==4.0.0" }, "certifi": { "hashes": [ - "sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50", - "sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef" + "sha256:017c25db2a153ce562900032d5bc68e9f191e44e9a0f762f373977de9df1fbb3", + "sha256:25b64c7da4cd7479594d035c08c2d809eb4aab3a26e5a990ea98cc450c320f1f" ], - "version": "==2019.9.11" + "version": "==2019.11.28" }, "cffi": { "hashes": [ @@ -955,50 +997,57 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==7.0" }, + "colorama": { + "hashes": [ + "sha256:7d73d2a99753107a36ac6b455ee49046802e59d9d076ef8e47b61499fa29afff", + "sha256:e96da0d330793e2cb9485e9ddfd918d456036c7149416295932478192f4436a1" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==0.4.3" + }, "control": { "hashes": [ - "sha256:726e8c36a253a54c8886df31f860d740d70de4f8b041421d5df078c3bff3aadb" + "sha256:1fcfdcf39f96523cb1f2cf7bf7b8ae68ec3ef8350e5c55e17e02afdb0872edbb" ], "index": "pypi", - "version": "==0.8.2" + "version": "==0.8.3" }, "coverage": { "hashes": [ - "sha256:08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6", - "sha256:0be0f1ed45fc0c185cfd4ecc19a1d6532d72f86a2bac9de7e24541febad72650", - "sha256:141f08ed3c4b1847015e2cd62ec06d35e67a3ac185c26f7635f4406b90afa9c5", - "sha256:19e4df788a0581238e9390c85a7a09af39c7b539b29f25c89209e6c3e371270d", - "sha256:23cc09ed395b03424d1ae30dcc292615c1372bfba7141eb85e11e50efaa6b351", - "sha256:245388cda02af78276b479f299bbf3783ef0a6a6273037d7c60dc73b8d8d7755", - "sha256:331cb5115673a20fb131dadd22f5bcaf7677ef758741312bee4937d71a14b2ef", - "sha256:386e2e4090f0bc5df274e720105c342263423e77ee8826002dcffe0c9533dbca", - "sha256:3a794ce50daee01c74a494919d5ebdc23d58873747fa0e288318728533a3e1ca", - "sha256:60851187677b24c6085248f0a0b9b98d49cba7ecc7ec60ba6b9d2e5574ac1ee9", - "sha256:63a9a5fc43b58735f65ed63d2cf43508f462dc49857da70b8980ad78d41d52fc", - "sha256:6b62544bb68106e3f00b21c8930e83e584fdca005d4fffd29bb39fb3ffa03cb5", - "sha256:6ba744056423ef8d450cf627289166da65903885272055fb4b5e113137cfa14f", - "sha256:7494b0b0274c5072bddbfd5b4a6c6f18fbbe1ab1d22a41e99cd2d00c8f96ecfe", - "sha256:826f32b9547c8091679ff292a82aca9c7b9650f9fda3e2ca6bf2ac905b7ce888", - "sha256:93715dffbcd0678057f947f496484e906bf9509f5c1c38fc9ba3922893cda5f5", - "sha256:9a334d6c83dfeadae576b4d633a71620d40d1c379129d587faa42ee3e2a85cce", - "sha256:af7ed8a8aa6957aac47b4268631fa1df984643f07ef00acd374e456364b373f5", - "sha256:bf0a7aed7f5521c7ca67febd57db473af4762b9622254291fbcbb8cd0ba5e33e", - "sha256:bf1ef9eb901113a9805287e090452c05547578eaab1b62e4ad456fcc049a9b7e", - "sha256:c0afd27bc0e307a1ffc04ca5ec010a290e49e3afbe841c5cafc5c5a80ecd81c9", - "sha256:dd579709a87092c6dbee09d1b7cfa81831040705ffa12a1b248935274aee0437", - "sha256:df6712284b2e44a065097846488f66840445eb987eb81b3cc6e4149e7b6982e1", - "sha256:e07d9f1a23e9e93ab5c62902833bf3e4b1f65502927379148b6622686223125c", - "sha256:e2ede7c1d45e65e209d6093b762e98e8318ddeff95317d07a27a2140b80cfd24", - "sha256:e4ef9c164eb55123c62411f5936b5c2e521b12356037b6e1c2617cef45523d47", - "sha256:eca2b7343524e7ba246cab8ff00cab47a2d6d54ada3b02772e908a45675722e2", - "sha256:eee64c616adeff7db37cc37da4180a3a5b6177f5c46b187894e633f088fb5b28", - "sha256:ef824cad1f980d27f26166f86856efe11eff9912c4fed97d3804820d43fa550c", - "sha256:efc89291bd5a08855829a3c522df16d856455297cf35ae827a37edac45f466a7", - "sha256:fa964bae817babece5aa2e8c1af841bebb6d0b9add8e637548809d040443fee0", - "sha256:ff37757e068ae606659c28c3bd0d923f9d29a85de79bf25b2b34b148473b5025" - ], - "index": "pypi", - "version": "==4.5.4" + "sha256:189aac76d6e0d7af15572c51892e7326ee451c076c5a50a9d266406cd6c49708", + "sha256:1bf7ba2af1d373a1750888724f84cffdfc697738f29a353c98195f98fc011509", + "sha256:1f4ee8e2e4243971618bc16fcc4478317405205f135e95226c2496e2a3b8dbbf", + "sha256:225e79a5d485bc1642cb7ba02281419c633c216cdc6b26c26494ba959f09e69f", + "sha256:23688ff75adfa8bfa2a67254d889f9bdf9302c27241d746e17547c42c732d3f4", + "sha256:28f7f73b34a05e23758e860a89a7f649b85c6749e252eff60ebb05532d180e86", + "sha256:2d0cb9b1fe6ad0d915d45ad3d87f03a38e979093a98597e755930db1f897afae", + "sha256:47874b4711c5aeb295c31b228a758ce3d096be83dc37bd56da48ed99efb8813b", + "sha256:511ec0c00840e12fb4e852e4db58fa6a01ca4da72f36a9766fae344c3d502033", + "sha256:53e7438fef0c97bc248f88ba1edd10268cd94d5609970aaf87abbe493691af87", + "sha256:569f9ee3025682afda6e9b0f5bb14897c0db03f1a1dc088b083dd36e743f92bb", + "sha256:593853aa1ac6dcc6405324d877544c596c9d948ef20d2e9512a0f5d2d3202356", + "sha256:5b0a07158360d22492f9abd02a0f2ee7981b33f0646bf796598b7673f6bbab14", + "sha256:7ca3db38a61f3655a2613ee2c190d63639215a7a736d3c64cc7bbdb002ce6310", + "sha256:7d1cc7acc9ce55179616cf72154f9e648136ea55987edf84addbcd9886ffeba2", + "sha256:88b51153657612aea68fa684a5b88037597925260392b7bb4509d4f9b0bdd889", + "sha256:955ec084f549128fa2702f0b2dc696392001d986b71acd8fd47424f28289a9c3", + "sha256:b251c7092cbb6d789d62dc9c9e7c4fb448c9138b51285c36aeb72462cad3600e", + "sha256:bd82b684bb498c60ef47bb1541a50e6d006dde8579934dcbdbc61d67d1ea70d9", + "sha256:bfe102659e2ec13b86c7f3b1db6c9a4e7beea4255058d006351339e6b342d5d2", + "sha256:c1e4e39e43057396a5e9d069bfbb6ffeee892e40c5d2effbd8cd71f34ee66c4d", + "sha256:cb2b74c123f65e8166f7e1265829a6c8ed755c3cd16d7f50e75a83456a5f3fd7", + "sha256:cca38ded59105f7705ef6ffe1e960b8db6c7d8279c1e71654a4775ab4454ca15", + "sha256:cf908840896f7aa62d0ec693beb53264b154f972eb8226fb864ac38975590c4f", + "sha256:d095a7b473f8a95f7efe821f92058c8a2ecfb18f8db6677ae3819e15dc11aaae", + "sha256:d22b4297e7e4225ccf01f1aa55e7a96412ea0796b532dd614c3fcbafa341128e", + "sha256:d4a2b578a7a70e0c71f662705262f87a456f1e6c1e40ada7ea699abaf070a76d", + "sha256:ddeb42a3d5419434742bf4cc71c9eaa22df3b76808e23a82bd0b0bd360f1a9f1", + "sha256:e65a5aa1670db6263f19fdc03daee1d7dbbadb5cb67fd0a1f16033659db13c1d", + "sha256:eaad65bd20955131bcdb3967a4dea66b4e4d4ca488efed7c00d91ee0173387e8", + "sha256:f45fba420b94165c17896861bb0e8b27fb7abdcedfeb154895d8553df90b7b00" + ], + "index": "pypi", + "version": "==5.0.2" }, "cryptography": { "hashes": [ @@ -1036,18 +1085,17 @@ }, "datadog": { "hashes": [ - "sha256:2746dd41055805e7b41610de887444ccbe5ee38ed7cf118bc6ba34e23c5a2e73", - "sha256:d97d85a8d2b90fe01f00b637a943c8b4a2d31928d7d4248610c8aab2292e8407" + "sha256:22d3c935e83de02b64efed635ac5fb45db26e152ac759105ec6d5a7ed8b9f6a9", + "sha256:bce73f33a4496b004402baa502251150e3b48a48f610ff89d4cd110b366ee0ab" ], "index": "pypi", - "version": "==0.32.0" + "version": "==0.33.0" }, "decorator": { "hashes": [ "sha256:54c38050039232e1db4ad7375cfce6748d7b41c29e95a081c8a6d2c30364a2ce", "sha256:5d19b92a3c8f7f101c8dd86afd86b0f061a8ce4540ab8cd401fa2542756bce6d" ], - "index": "pypi", "version": "==4.4.1" }, "defusedxml": { @@ -1060,18 +1108,18 @@ }, "dictdiffer": { "hashes": [ - "sha256:97cf4ef98ebc1acf737074aed41e379cf48ab5ff528c92109dfb8e2e619e6809", - "sha256:b3ad476fc9cca60302b52c50e1839342d2092aeaba586d69cbf9249f87f52463" + "sha256:1adec0d67cdf6166bda96ae2934ddb5e54433998ceab63c984574d187cc563d2", + "sha256:d79d9a39e459fe33497c858470ca0d2e93cb96621751de06d631856adfd9c390" ], "index": "pypi", - "version": "==0.8.0" + "version": "==0.8.1" }, "dlib": { "hashes": [ - "sha256:8ca127253a0ca82a3d847148515f82ff2c504ed77a6385ec4f38c7f8e5360860" + "sha256:d0eeaca07bc4c75973ad0f739a541d8fa4003af778f0dc1c2c595d470823819a" ], "index": "pypi", - "version": "==19.18.0" + "version": "==19.19.0" }, "docutils": { "hashes": [ @@ -1082,14 +1130,6 @@ "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==0.15.2" }, - "dominate": { - "hashes": [ - "sha256:6e833aea505f0236a9fc692326bac575f8bd38ae0f3a1bdc73d20ca606ac75d5", - "sha256:a92474b4312bd8b4c1789792f3ec8c571cd8afa8e7502a2b1c64dd48cd67e59c" - ], - "index": "pypi", - "version": "==2.4.0" - }, "elasticsearch": { "hashes": [ "sha256:0140787216646e1eb7eb001f8146aff7071d7ca438854249787b6cc221ddd266", @@ -1108,41 +1148,32 @@ }, "fastcluster": { "hashes": [ - "sha256:0024b1304d4618a32900473b809265694bc6d0a10bfbc272407443318644d405", - "sha256:0b33b076ea98939742e0734e944c903c8c67af3eecd5a9f8b4349407c1affdd3", - "sha256:244d400a81d23b48f2b825e50e99e1ff3c7d2be2acc40942e3359b4deef68483", - "sha256:2bb3bf8e1c7af42e47ef24bc2386a1d3e6ec8dc5e6be4123a491a36b89227b49", - "sha256:539d84d43fbe541a38d94c84bf0469c430cb7cda488364941ce57f680a07b091", - "sha256:5e7d81385bbc2148c554c4aaa32e26a00fbadc1190d5bad9c8719f6432629307", - "sha256:642e4d92220c1deede1e89409c5ad366e4a3f3ed55fff0a4e325d4eb2574d65a", - "sha256:66c868fdfc161e5c45cdf399f1274216602ea82c9fc46c632c9602dbaa149840", - "sha256:6952c9d25b3ea60d6a53ee92205e7f16cc6baf7caa4776fb1e55dc6e8e2965f2", - "sha256:8606da6f6f51f81c3b4e000edeb8668711a1769a6ebf3c99ab98f9c6d2fb7534", - "sha256:8d552d29ed054ce20f5bb0445b51bd7b6b8088fdae334625b4a9950189dcc2bf", - "sha256:922735fde2848a6f0478c6968048a16a5d3d6ba6e1d1a9596d578b59dce719d7", - "sha256:9f3cd227a9ebeec090e4186a63e46cd87d121968bd1d45ea8a7c2d483bc082fb", - "sha256:a382cb411610ca06a69e7b131239f0bb02961fec762d5b6804e653a32cd5ab52", - "sha256:a986b3afe823bcaea3dad9de1485b176c6dd5b0e2f154ede71aaf6635e82e159", - "sha256:b1902ab52418c6f4c2f3f7439aea711c6b5aa9bbb4c97b6d4b0c6f5e5c894342", - "sha256:bb56f6c7343bbb68beb1ffd13abdb87ce7a84ab391b3a4e63ed5c02b2d1ce46f", - "sha256:c2e5d11f5f96e6861fd632246f18bc6592ac439f236caffd4d2a75697a6f8969", - "sha256:c61973bb16117ee16b7642ff9da8e0899fb4d5eb5d0cc9c56d3269551ccd6307", - "sha256:d2deec11a6625c5578325f4dd10980e2981d1f1d1e658c7c79f2497377f92bdf", - "sha256:e0f2feb03f67b12f25538aa05b1150c7a2c1cd1c21ad7d0bde94e8169ef46627", - "sha256:e32e7287c47291eca2c83cd5cc6a5007eff2da00c12ac21fd721a16d0c428059", - "sha256:e889ea36c4e469ff3fb2a6a868c8e557fc988a81cd1cf3d09876107e59ee9cbd", - "sha256:e96f3b65e3748f2be06aa0977a00872ddeca4f8959703126f2b103978243bbdd" - ], - "index": "pypi", - "version": "==1.1.25" - }, - "fasteners": { - "hashes": [ - "sha256:007e4d2b2d4a10093f67e932e5166722d2eab83b77724156e92ad013c6226574", - "sha256:3a176da6b70df9bb88498e1a18a9e4a8579ed5b9141207762368a1017bf8f5ef" - ], - "index": "pypi", - "version": "==0.15" + "sha256:18988adb9bc07fcb5970a17ced626092d28806866f7914aa8079f1fe57d1fcdf", + "sha256:3fe5102b58736ff8ed2a7944be98fbd4837b6ba4f3acbf6c06ef3b8ccdda00f1", + "sha256:4c0d310b74bfac6121eec4b704ffe52bdca995d022b7898ce02d3609a141d7a3", + "sha256:5026d6a69819c07a9df578529c7ed6615737e70650c42c55267c6a7c57c1b2be", + "sha256:5045697238bc71e37177f6b6ae9d902c02e8947ee43657476227c92d84885a68", + "sha256:67fe1890ba5f281e145cc17444056670b60e0232650d189345001f658046f46c", + "sha256:69055a8cd51e6acafd4d0973cdeaa03620e93f548527310a2448a6d19731ef29", + "sha256:6e421e7eda88f3140c8786da80656d85c7c73b53665439970acfa7e1f54fc699", + "sha256:71b2f1c455aae6bb13aa1c9c1db1b0ccc0cdc336646005008d47fe5d584a07a9", + "sha256:7cb427be975cdadf969fe62eccd5256dccb623342e80ea0fdda8870e40ac756f", + "sha256:8dd5ef24ea7014ea2d2478627fec509a4366053bcce5b8559b72fc4f62d3990e", + "sha256:94699ce6a452e34e1ac530823dbfb5a8b97942f00abd07231cb17b3c9f4d11fb", + "sha256:9849b86b44d2307f52c85a92ecb8dd2c8365bc41d835fb34c859a3622fa52417", + "sha256:a202f44a3b06f5cf9cdba3c67d6c523288922d6e6a1cdf737292f93759aa82f7", + "sha256:aaaef36300cbf20fabea182369186e6899b122b2667e1408c981e5177a8ebc67", + "sha256:accf6df86ce86905a9a87f10cb241d8d772d11ce77a2e8721ac731a7ad11fe8c", + "sha256:b1d905eb21a40a8b80e678030b985f42bbff4d6eef4c3158cbd0c00c36966de9", + "sha256:b86f22c46e8217dcd70a58a35b6134de7fa45d5986d703a8cd0812087782d900", + "sha256:ba26b92bd991714f6edf787e2ec42f294e30d1d6b79cf0c390199cb2b5dcf952", + "sha256:c17e9d650cefdab2f4632faf0239fe5b77d8f92cde56860a3cbdce33d2963bb9", + "sha256:c29af2b6c2c8c39292fba4db1f988ae2328298d16b9dc2e8aa4b969020332f5b", + "sha256:ca988e233e6aee007616af0fc7fbf5b236a3940f334a0fd176cd165151e8aea2", + "sha256:fd1ada69e745032274632ba0ef5532c8ca631a8b1d2db819689385a5253f3129" + ], + "index": "pypi", + "version": "==1.1.26" }, "flask": { "hashes": [ @@ -1188,7 +1219,6 @@ "hashes": [ "sha256:fe939df4583692f0512161ec1c880e0a10e71e6a232da045ab8edd3756fbadf0" ], - "index": "pypi", "version": "==0.2.2" }, "geoalchemy2": { @@ -1199,35 +1229,6 @@ "index": "pypi", "version": "==0.6.3" }, - "gevent": { - "hashes": [ - "sha256:0774babec518a24d9a7231d4e689931f31b332c4517a771e532002614e270a64", - "sha256:0e1e5b73a445fe82d40907322e1e0eec6a6745ca3cea19291c6f9f50117bb7ea", - "sha256:0ff2b70e8e338cf13bedf146b8c29d475e2a544b5d1fe14045aee827c073842c", - "sha256:107f4232db2172f7e8429ed7779c10f2ed16616d75ffbe77e0e0c3fcdeb51a51", - "sha256:14b4d06d19d39a440e72253f77067d27209c67e7611e352f79fe69e0f618f76e", - "sha256:1b7d3a285978b27b469c0ff5fb5a72bcd69f4306dbbf22d7997d83209a8ba917", - "sha256:1eb7fa3b9bd9174dfe9c3b59b7a09b768ecd496debfc4976a9530a3e15c990d1", - "sha256:2711e69788ddb34c059a30186e05c55a6b611cb9e34ac343e69cf3264d42fe1c", - "sha256:28a0c5417b464562ab9842dd1fb0cc1524e60494641d973206ec24d6ec5f6909", - "sha256:3249011d13d0c63bea72d91cec23a9cf18c25f91d1f115121e5c9113d753fa12", - "sha256:44089ed06a962a3a70e96353c981d628b2d4a2f2a75ea5d90f916a62d22af2e8", - "sha256:4bfa291e3c931ff3c99a349d8857605dca029de61d74c6bb82bd46373959c942", - "sha256:50024a1ee2cf04645535c5ebaeaa0a60c5ef32e262da981f4be0546b26791950", - "sha256:53b72385857e04e7faca13c613c07cab411480822ac658d97fd8a4ddbaf715c8", - "sha256:74b7528f901f39c39cdbb50cdf08f1a2351725d9aebaef212a29abfbb06895ee", - "sha256:7d0809e2991c9784eceeadef01c27ee6a33ca09ebba6154317a257353e3af922", - "sha256:896b2b80931d6b13b5d9feba3d4eebc67d5e6ec54f0cf3339d08487d55d93b0e", - "sha256:8d9ec51cc06580f8c21b41fd3f2b3465197ba5b23c00eb7d422b7ae0380510b0", - "sha256:9f7a1e96fec45f70ad364e46de32ccacab4d80de238bd3c2edd036867ccd48ad", - "sha256:ab4dc33ef0e26dc627559786a4fba0c2227f125db85d970abbf85b77506b3f51", - "sha256:d1e6d1f156e999edab069d79d890859806b555ce4e4da5b6418616322f0a3df1", - "sha256:d752bcf1b98174780e2317ada12013d612f05116456133a6acf3e17d43b71f05", - "sha256:e5bcc4270671936349249d26140c267397b7b4b1381f5ec8b13c53c5b53ab6e1" - ], - "index": "pypi", - "version": "==1.4.0" - }, "git-pylint-commit-hook": { "hashes": [ "sha256:e1d39e7856b3ef0a0269121ca210dc3f5a97da158b322411e8e1185918a91b3c" @@ -1237,11 +1238,11 @@ }, "google-auth": { "hashes": [ - "sha256:84105be98837fb8436e9d0bcb7a279fd85fa1d97bb35a077e70ba2fb95bcc983", - "sha256:baf1b3f8b29a5f96f66753ad848473699322b63f4d68964e510554b12d002443" + "sha256:7bb2034a3a290190cf4e3eb8ebf29e5025c90f0b06a00ba4d1fb94bf0c6448f7", + "sha256:c57074e594d2c6e3e316162734e8af3e15d40252022e69414cba67de66594417" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.7.1" + "version": "==1.10.0" }, "google-auth-oauthlib": { "hashes": [ @@ -1258,91 +1259,61 @@ ], "version": "==0.1.8" }, - "greenlet": { - "hashes": [ - "sha256:000546ad01e6389e98626c1367be58efa613fa82a1be98b0c6fc24b563acc6d0", - "sha256:0d48200bc50cbf498716712129eef819b1729339e34c3ae71656964dac907c28", - "sha256:23d12eacffa9d0f290c0fe0c4e81ba6d5f3a5b7ac3c30a5eaf0126bf4deda5c8", - "sha256:37c9ba82bd82eb6a23c2e5acc03055c0e45697253b2393c9a50cef76a3985304", - "sha256:51503524dd6f152ab4ad1fbd168fc6c30b5795e8c70be4410a64940b3abb55c0", - "sha256:8041e2de00e745c0e05a502d6e6db310db7faa7c979b3a5877123548a4c0b214", - "sha256:81fcd96a275209ef117e9ec91f75c731fa18dcfd9ffaa1c0adbdaa3616a86043", - "sha256:853da4f9563d982e4121fed8c92eea1a4594a2299037b3034c3c898cb8e933d6", - "sha256:8b4572c334593d449113f9dc8d19b93b7b271bdbe90ba7509eb178923327b625", - "sha256:9416443e219356e3c31f1f918a91badf2e37acf297e2fa13d24d1cc2380f8fbc", - "sha256:9854f612e1b59ec66804931df5add3b2d5ef0067748ea29dc60f0efdcda9a638", - "sha256:99a26afdb82ea83a265137a398f570402aa1f2b5dfb4ac3300c026931817b163", - "sha256:a19bf883b3384957e4a4a13e6bd1ae3d85ae87f4beb5957e35b0be287f12f4e4", - "sha256:a9f145660588187ff835c55a7d2ddf6abfc570c2651c276d3d4be8a2766db490", - "sha256:ac57fcdcfb0b73bb3203b58a14501abb7e5ff9ea5e2edfa06bb03035f0cff248", - "sha256:bcb530089ff24f6458a81ac3fa699e8c00194208a724b644ecc68422e1111939", - "sha256:beeabe25c3b704f7d56b573f7d2ff88fc99f0138e43480cecdfcaa3b87fe4f87", - "sha256:d634a7ea1fc3380ff96f9e44d8d22f38418c1c381d5fac680b272d7d90883720", - "sha256:d97b0661e1aead761f0ded3b769044bb00ed5d33e1ec865e891a8b128bf7c656" - ], - "markers": "platform_python_implementation == 'CPython'", - "version": "==0.4.15" - }, "grpcio": { "hashes": [ - "sha256:0419ae5a45f49c7c40d9ae77ae4de9442431b7822851dfbbe56ee0eacb5e5654", - "sha256:1e8631eeee0fb0b4230aeb135e4890035f6ef9159c2a3555fa184468e325691a", - "sha256:24db2fa5438f3815a4edb7a189035051760ca6aa2b0b70a6a948b28bfc63c76b", - "sha256:2adb1cdb7d33e91069517b41249622710a94a1faece1fed31cd36904e4201cde", - "sha256:2cd51f35692b551aeb1fdeb7a256c7c558f6d78fcddff00640942d42f7aeba5f", - "sha256:3247834d24964589f8c2b121b40cd61319b3c2e8d744a6a82008643ef8a378b1", - "sha256:3433cb848b4209717722b62392e575a77a52a34d67c6730138102abc0a441685", - "sha256:39671b7ff77a962bd745746d9d2292c8ed227c5748f16598d16d8631d17dd7e5", - "sha256:40a0b8b2e6f6dd630f8b267eede2f40a848963d0f3c40b1b1f453a4a870f679e", - "sha256:40f9a74c7aa210b3e76eb1c9d56aa8d08722b73426a77626967019df9bbac287", - "sha256:423f76aa504c84cb94594fb88b8a24027c887f1c488cf58f2173f22f4fbd046c", - "sha256:43bd04cec72281a96eb361e1b0232f0f542b46da50bcfe72ef7e5a1b41d00cb3", - "sha256:43e38762635c09e24885d15e3a8e374b72d105d4178ee2cc9491855a8da9c380", - "sha256:4413b11c2385180d7de03add6c8845dd66692b148d36e27ec8c9ef537b2553a1", - "sha256:4450352a87094fd58daf468b04c65a9fa19ad11a0ac8ac7b7ff17d46f873cbc1", - "sha256:49ffda04a6e44de028b3b786278ac9a70043e7905c3eea29eed88b6524d53a29", - "sha256:4a38c4dde4c9120deef43aaabaa44f19186c98659ce554c29788c4071ab2f0a4", - "sha256:50b1febdfd21e2144b56a9aa226829e93a79c354ef22a4e5b013d9965e1ec0ed", - "sha256:559b1a3a8be7395ded2943ea6c2135d096f8cc7039d6d12127110b6496f251fe", - "sha256:5de86c182667ec68cf84019aa0d8ceccf01d352cdca19bf9e373725204bdbf50", - "sha256:5fc069bb481fe3fad0ba24d3baaf69e22dfa6cc1b63290e6dfeaf4ac1e996fb7", - "sha256:6a19d654da49516296515d6f65de4bbcbd734bc57913b21a610cfc45e6df3ff1", - "sha256:7535b3e52f498270e7877dde1c8944d6b7720e93e2e66b89c82a11447b5818f5", - "sha256:7c4e495bcabc308198b8962e60ca12f53b27eb8f03a21ac1d2d711d6dd9ecfca", - "sha256:8a8fc4a0220367cb8370cedac02272d574079ccc32bffbb34d53aaf9e38b5060", - "sha256:8b008515e067232838daca020d1af628bf6520c8cc338bf383284efe6d8bd083", - "sha256:8d1684258e1385e459418f3429e107eec5fb3d75e1f5a8c52e5946b3f329d6ea", - "sha256:8eb5d54b87fb561dc2e00a5c5226c33ffe8dbc13f2e4033a412bafb7b37b194d", - "sha256:94cdef0c61bd014bb7af495e21a1c3a369dd0399c3cd1965b1502043f5c88d94", - "sha256:9d9f3be69c7a5e84c3549a8c4403fa9ac7672da456863d21e390b2bbf45ccad1", - "sha256:9fb6fb5975a448169756da2d124a1beb38c0924ff6c0306d883b6848a9980f38", - "sha256:a5eaae8700b87144d7dfb475aa4675e500ff707292caba3deff41609ddc5b845", - "sha256:aaeac2d552772b76d24eaff67a5d2325bc5205c74c0d4f9fbe71685d4a971db2", - "sha256:bb611e447559b3b5665e12a7da5160c0de6876097f62bf1d23ba66911564868e", - "sha256:bc0d41f4eb07da8b8d3ea85e50b62f6491ab313834db86ae2345be07536a4e5a", - "sha256:bf51051c129b847d1bb63a9b0826346b5f52fb821b15fe5e0d5ef86f268510f5", - "sha256:c948c034d8997526011960db54f512756fb0b4be1b81140a15b4ef094c6594a4", - "sha256:d435a01334157c3b126b4ee5141401d44bdc8440993b18b05e2f267a6647f92d", - "sha256:d46c1f95672b73288e08cdca181e14e84c6229b5879561b7b8cfd48374e09287", - "sha256:d5d58309b42064228b16b0311ff715d6c6e20230e81b35e8d0c8cfa1bbdecad8", - "sha256:dc6e2e91365a1dd6314d615d80291159c7981928b88a4c65654e3fefac83a836", - "sha256:e0dfb5f7a39029a6cbec23affa923b22a2c02207960fd66f109e01d6f632c1eb", - "sha256:eb4bf58d381b1373bd21d50837a53953d625d1693f1b58fed12743c75d3dd321", - "sha256:ebb211a85248dbc396b29320273c1ffde484b898852432613e8df0164c091006", - "sha256:ec759ece4786ae993a5b7dc3b3dead6e9375d89a6c65dfd6860076d2eb2abe7b", - "sha256:f55108397a8fa164268238c3e69cc134e945d1f693572a2f05a028b8d0d2b837", - "sha256:f6c706866d424ff285b85a02de7bbe5ed0ace227766b2c42cbe12f3d9ea5a8aa", - "sha256:f8370ad332b36fbad117440faf0dd4b910e80b9c49db5648afd337abdde9a1b6" - ], - "version": "==1.25.0" + "sha256:066630f6b62bffa291dacbee56994279a6a3682b8a11967e9ccaf3cc770fc11e", + "sha256:07e95762ca6b18afbeb3aa2793e827c841152d5e507089b1db0b18304edda105", + "sha256:0a0fb2f8e3a13537106bc77e4c63005bc60124a6203034304d9101921afa4e90", + "sha256:0c61b74dcfb302613926e785cb3542a0905b9a3a86e9410d8cf5d25e25e10104", + "sha256:13383bd70618da03684a8aafbdd9e3d9a6720bf8c07b85d0bc697afed599d8f0", + "sha256:1c6e0f6b9d091e3717e9a58d631c8bb4898be3b261c2a01fe46371fdc271052f", + "sha256:1cf710c04689daa5cc1e598efba00b028215700dcc1bf66fcb7b4f64f2ea5d5f", + "sha256:2da5cee9faf17bb8daf500cd0d28a17ae881ab5500f070a6aace457f4c08cac4", + "sha256:2f78ebf340eaf28fa09aba0f836a8b869af1716078dfe8f3b3f6ff785d8f2b0f", + "sha256:33a07a1a8e817d733588dbd18e567caad1a6fe0d440c165619866cd490c7911a", + "sha256:3d090c66af9c065b7228b07c3416f93173e9839b1d40bb0ce3dd2aa783645026", + "sha256:42b903a3596a10e2a3727bae2a76f8aefd324d498424b843cfa9606847faea7b", + "sha256:4fffbb58134c4f23e5a8312ac3412db6f5e39e961dc0eb5e3115ce5aa16bf927", + "sha256:57be5a6c509a406fe0ffa6f8b86904314c77b5e2791be8123368ad2ebccec874", + "sha256:5b0fa09efb33e2af4e8822b4eb8b2cbc201d562e3e185c439be7eaeee2e8b8aa", + "sha256:5ef42dfc18f9a63a06aca938770b69470bb322e4c137cf08cf21703d1ef4ae5c", + "sha256:6a43d2f2ff8250f200fdf7aa31fa191a997922aa9ea1182453acd705ad83ab72", + "sha256:6d8ab28559be98b02f8b3a154b53239df1aa5b0d28ff865ae5be4f30e7ed4d3f", + "sha256:6e47866b7dc14ca3a12d40c1d6082e7bea964670f1c5315ea0fb8b0550244d64", + "sha256:6edda1b96541187f73aab11800d25f18ee87e53d5f96bb74473873072bf28a0e", + "sha256:7109c8738a8a3c98cfb5dda1c45642a8d6d35dc00d257ab7a175099b2b4daecd", + "sha256:8d866aafb08657c456a18c4a31c8526ea62de42427c242b58210b9eae6c64559", + "sha256:9939727d9ae01690b24a2b159ac9dbca7b7e8e6edd5af6a6eb709243cae7b52b", + "sha256:99fd873699df17cb11c542553270ae2b32c169986e475df0d68a8629b8ef4df7", + "sha256:b6fda5674f990e15e1bcaacf026428cf50bce36e708ddcbd1de9673b14aab760", + "sha256:bdb2f3dcb664f0c39ef1312cd6acf6bc6375252e4420cf8f36fff4cb4fa55c71", + "sha256:bfd7d3130683a1a0a50c456273c21ec8a604f2d043b241a55235a78a0090ee06", + "sha256:c6c2db348ac73d73afe14e0833b18abbbe920969bf2c5c03c0922719f8020d06", + "sha256:cb7a4b41b5e2611f85c3402ac364f1d689f5d7ecbc24a55ef010eedcd6cf460f", + "sha256:cd3d3e328f20f7c807a862620c6ee748e8d57ba2a8fc960d48337ed71c6d9d32", + "sha256:d1a481777952e4f99b8a6956581f3ee866d7614100d70ae6d7e07327570b85ce", + "sha256:d1d49720ed636920bb3d74cedf549382caa9ad55aea89d1de99d817068d896b2", + "sha256:d42433f0086cccd192114343473d7dbd4aae9141794f939e2b7b83efc57543db", + "sha256:d44c34463a7c481e076f691d8fa25d080c3486978c2c41dca09a8dd75296c2d7", + "sha256:d7e5b7af1350e9c8c17a7baf99d575fbd2de69f7f0b0e6ebd47b57506de6493a", + "sha256:d9542366a0917b9b48bab1fee481ac01f56bdffc52437b598c09e7840148a6a9", + "sha256:df7cdfb40179acc9790a462c049e0b8e109481164dd7ad1a388dd67ff1528759", + "sha256:e1a9d9d2e7224d981aea8da79260c7f6932bf31ce1f99b7ccfa5eceeb30dc5d0", + "sha256:ed10e5fad105ecb0b12822f924e62d0deb07f46683a0b64416b17fd143daba1d", + "sha256:f0ec5371ce2363b03531ed522bfbe691ec940f51f0e111f0500fc0f44518c69d", + "sha256:f6580a8a4f5e701289b45fd62a8f6cb5ec41e4d77082424f8b676806dcd22564", + "sha256:f7b83e4b2842d44fce3cdc0d54db7a7e0d169a598751bf393601efaa401c83e0", + "sha256:ffec45b0db18a555fdfe0c6fa2d0a3fceb751b22b31e8fcd14ceed7bde05481e" + ], + "version": "==1.26.0" }, "gunicorn": { "hashes": [ - "sha256:0806b5e8a2eb8ba9ac1be65d7b743ec896fc25f5d6cb16c5e051540157b315bb", - "sha256:ef69dea4814df95e64e3f40b47b7ffedc6911c5009233be9d01cfd0d14aa3f50" + "sha256:1904bb2b8a43658807108d59c3f3d56c2b6121a701161de0ddf9ad140073c626", + "sha256:cd4a810dd51bf497552cf3f863b575dabd73d6ad6a91075b65936b151cbf4f9c" ], "index": "pypi", - "version": "==20.0.0" + "version": "==20.0.4" }, "h5py": { "hashes": [ @@ -1353,6 +1324,7 @@ "sha256:51ae56894c6c93159086ffa2c94b5b3388c0400548ab26555c143e7cfa05b8e5", "sha256:54817b696e87eb9e403e42643305f142cd8b940fe9b3b490bbf98c3b8a894cf4", "sha256:549ad124df27c056b2e255ea1c44d30fb7a17d17676d03096ad5cd85edb32dc1", + "sha256:64f74da4a1dd0d2042e7d04cf8294e04ddad686f8eba9bb79e517ae582f6668d", "sha256:6998be619c695910cb0effe5eb15d3a511d3d1a5d217d4bd0bebad1151ec2262", "sha256:6ef7ab1089e3ef53ca099038f3c0a94d03e3560e6aff0e9d6c64c55fb13fc681", "sha256:769e141512b54dee14ec76ed354fcacfc7d97fea5a7646b709f7400cf1838630", @@ -1367,6 +1339,7 @@ "sha256:c0d4b04bbf96c47b6d360cd06939e72def512b20a18a8547fa4af810258355d5", "sha256:c54a2c0dd4957776ace7f95879d81582298c5daf89e77fb8bee7378f132951de", "sha256:cbf28ae4b5af0f05aa6e7551cee304f1d317dbed1eb7ac1d827cee2f1ef97a99", + "sha256:d35f7a3a6cefec82bfdad2785e78359a0e6a5fbb3f605dd5623ce88082ccd681", "sha256:d3c59549f90a891691991c17f8e58c8544060fdf3ccdea267100fa5f561ff62f", "sha256:d7ae7a0576b06cb8e8a1c265a8bc4b73d05fdee6429bffc9a26a6eb531e79d72", "sha256:ecf4d0b56ee394a0984de15bceeb97cbe1fe485f1ac205121293fc44dcf3f31f", @@ -1417,18 +1390,11 @@ }, "importlib-metadata": { "hashes": [ - "sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26", - "sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af" + "sha256:073a852570f92da5f744a3472af1b61e28e9f78ccf0c9117658dc32b15de7b45", + "sha256:d95141fbfa7ef2ec65cfd945e2af7e5a6ddbd7c8d9a25e66ff3be8e3daf9f60f" ], - "markers": "python_version < '3.8'", - "version": "==0.23" - }, - "intervaltree": { - "hashes": [ - "sha256:cb4f61c81dcb4fea6c09903f3599015a83c9bdad1f0bbd232495e6681e19e273" - ], - "index": "pypi", - "version": "==3.0.2" + "markers": "python_version == '3.7'", + "version": "==1.3.0" }, "ipykernel": { "hashes": [ @@ -1440,11 +1406,11 @@ }, "ipython": { "hashes": [ - "sha256:dfd303b270b7b5232b3d08bd30ec6fd685d8a58cabd54055e3d69d8f029f7280", - "sha256:ed7ebe1cba899c1c3ccad6f7f1c2d2369464cc77dba8eebc65e2043e19cda995" + "sha256:0f4bcf18293fb666df8511feec0403bdb7e061a5842ea6e88a3177b0ceb34ead", + "sha256:387686dd7fc9caf29d2fddcf3116c4b07a11d9025701d220c589a430b0171d8a" ], "index": "pypi", - "version": "==7.9.0" + "version": "==7.11.1" }, "ipython-genutils": { "hashes": [ @@ -1460,6 +1426,13 @@ ], "version": "==7.5.1" }, + "isodate": { + "hashes": [ + "sha256:2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8", + "sha256:aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81" + ], + "version": "==0.6.0" + }, "isort": { "hashes": [ "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1", @@ -1478,11 +1451,11 @@ }, "jedi": { "hashes": [ - "sha256:786b6c3d80e2f06fd77162a07fed81b8baa22dde5d62896a790a331d6ac21a27", - "sha256:ba859c74fa3c966a22f2aeebe1b74ee27e2a462f56d3f5f7ca4a59af61bfe42e" + "sha256:1349c1e8c107095a55386628bb3b2a79422f3a2cab8381e34ce19909e0cf5064", + "sha256:e909527104a903606dd63bea6e8e888833f0ef087057829b89a18364a856f807" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==0.15.1" + "version": "==0.15.2" }, "jinja2": { "hashes": [ @@ -1501,11 +1474,11 @@ }, "joblib": { "hashes": [ - "sha256:006108c7576b3eb6c5b27761ddbf188eb6e6347696325ab2027ea1ee9a4b922d", - "sha256:6fcc57aacb4e89451fd449e9412687c51817c3f48662c3d8f38ba3f8a0a193ff" + "sha256:0630eea4f5664c463f23fbf5dcfc54a2bc6168902719fa8e19daf033022786c8", + "sha256:bdb4fd9b72915ffb49fde2229ce482dd7ae79d842ed8c2b4c932441495af1403" ], "index": "pypi", - "version": "==0.14.0" + "version": "==0.14.1" }, "json-logging-py": { "hashes": [ @@ -1611,13 +1584,12 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.1.0" }, - "kombu": { + "knack": { "hashes": [ - "sha256:1760b54b1d15a547c9a26d3598a1c8cdaf2436386ac1f5561934bc8a3cbbbd86", - "sha256:e7465aa85a1db889116819f08c5de29520d2fa103324dcdca5e90af345f01771" + "sha256:b1ac92669641b902e1aef97138666a21b8852f65d83cbde03eb9ddebf82ce121", + "sha256:bd240163d4e2ce9fc8535f77519358da0afd6c0ca19f001c639c3160b57630a9" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==4.6.6" + "version": "==0.6.3" }, "lazy-object-proxy": { "hashes": [ @@ -1655,10 +1627,10 @@ }, "limits": { "hashes": [ - "sha256:9df578f4161017d79f5188609f1d65f6b639f8aad2914c3960c9252e56a0ff95", - "sha256:a017b8d9e9da6761f4574642149c337f8f540d4edfe573fb91ad2c4001a2bc76" + "sha256:98accbccf66e6e2edc0bb7b6e295e6bb8596be3588a7c385de16c8e8463644a4", + "sha256:c071295307c447f85aaa3c3ab3ce058e29d67010f4fabf278a8e163916e4deab" ], - "version": "==1.3" + "version": "==1.4.1" }, "lru-dict": { "hashes": [ @@ -1667,38 +1639,6 @@ "index": "pypi", "version": "==1.1.6" }, - "lxml": { - "hashes": [ - "sha256:02ca7bf899da57084041bb0f6095333e4d239948ad3169443f454add9f4e9cb4", - "sha256:096b82c5e0ea27ce9138bcbb205313343ee66a6e132f25c5ed67e2c8d960a1bc", - "sha256:0a920ff98cf1aac310470c644bc23b326402d3ef667ddafecb024e1713d485f1", - "sha256:1409b14bf83a7d729f92e2a7fbfe7ec929d4883ca071b06e95c539ceedb6497c", - "sha256:17cae1730a782858a6e2758fd20dd0ef7567916c47757b694a06ffafdec20046", - "sha256:17e3950add54c882e032527795c625929613adbd2ce5162b94667334458b5a36", - "sha256:1f4f214337f6ee5825bf90a65d04d70aab05526c08191ab888cb5149501923c5", - "sha256:2e8f77db25b0a96af679e64ff9bf9dddb27d379c9900c3272f3041c4d1327c9d", - "sha256:4dffd405390a45ecb95ab5ab1c1b847553c18b0ef8ed01e10c1c8b1a76452916", - "sha256:6b899931a5648862c7b88c795eddff7588fb585e81cecce20f8d9da16eff96e0", - "sha256:726c17f3e0d7a7200718c9a890ccfeab391c9133e363a577a44717c85c71db27", - "sha256:760c12276fee05c36f95f8040180abc7fbebb9e5011447a97cdc289b5d6ab6fc", - "sha256:796685d3969815a633827c818863ee199440696b0961e200b011d79b9394bbe7", - "sha256:891fe897b49abb7db470c55664b198b1095e4943b9f82b7dcab317a19116cd38", - "sha256:9277562f175d2334744ad297568677056861070399cec56ff06abbe2564d1232", - "sha256:a471628e20f03dcdfde00770eeaf9c77811f0c331c8805219ca7b87ac17576c5", - "sha256:a63b4fd3e2cabdcc9d918ed280bdde3e8e9641e04f3c59a2a3109644a07b9832", - "sha256:ae88588d687bd476be588010cbbe551e9c2872b816f2da8f01f6f1fda74e1ef0", - "sha256:b0b84408d4eabc6de9dd1e1e0bc63e7731e890c0b378a62443e5741cfd0ae90a", - "sha256:be78485e5d5f3684e875dab60f40cddace2f5b2a8f7fede412358ab3214c3a6f", - "sha256:c27eaed872185f047bb7f7da2d21a7d8913457678c9a100a50db6da890bc28b9", - "sha256:c7fccd08b14aa437fe096c71c645c0f9be0655a9b1a4b7cffc77bcb23b3d61d2", - "sha256:c81cb40bff373ab7a7446d6bbca0190bccc5be3448b47b51d729e37799bb5692", - "sha256:d11874b3c33ee441059464711cd365b89fa1a9cf19ae75b0c189b01fbf735b84", - "sha256:e9c028b5897901361d81a4718d1db217b716424a0283afe9d6735fe0caf70f79", - "sha256:fe489d486cd00b739be826e8c1be188ddb74c7a1ca784d93d06fda882a6a1681" - ], - "index": "pypi", - "version": "==4.4.1" - }, "markdown": { "hashes": [ "sha256:2e50876bcdd74517e7b71f3e7a76102050edec255b3983403f1a63e7c8a41e7a", @@ -1743,18 +1683,22 @@ }, "matplotlib": { "hashes": [ - "sha256:1febd22afe1489b13c6749ea059d392c03261b2950d1d45c17e3aed812080c93", - "sha256:31a30d03f39528c79f3a592857be62a08595dec4ac034978ecd0f814fa0eec2d", - "sha256:4442ce720907f67a79d45de9ada47be81ce17e6c2f448b3c64765af93f6829c9", - "sha256:796edbd1182cbffa7e1e7a97f1e141f875a8501ba8dd834269ae3cd45a8c976f", - "sha256:934e6243df7165aad097572abf5b6003c77c9b6c480c3c4de6f2ef1b5fdd4ec0", - "sha256:bab9d848dbf1517bc58d1f486772e99919b19efef5dd8596d4b26f9f5ee08b6b", - "sha256:c1fe1e6cdaa53f11f088b7470c2056c0df7d80ee4858dadf6cbe433fcba4323b", - "sha256:e5b8aeca9276a3a988caebe9f08366ed519fff98f77c6df5b64d7603d0e42e36", - "sha256:ec6bd0a6a58df3628ff269978f4a4b924a0d371ad8ce1f8e2b635b99e482877a" + "sha256:08ccc8922eb4792b91c652d3e6d46b1c99073f1284d1b6705155643e8046463a", + "sha256:161dcd807c0c3232f4dcd4a12a382d52004a498174cbfafd40646106c5bcdcc8", + "sha256:1f9e885bfa1b148d16f82a6672d043ecf11197f6c71ae222d0546db706e52eb2", + "sha256:2d6ab54015a7c0d727c33e36f85f5c5e4172059efdd067f7527f6e5d16ad01aa", + "sha256:5d2e408a2813abf664bd79431107543ecb449136912eb55bb312317edecf597e", + "sha256:61c8b740a008218eb604de518eb411c4953db0cb725dd0b32adf8a81771cab9e", + "sha256:80f10af8378fccc136da40ea6aa4a920767476cdfb3241acb93ef4f0465dbf57", + "sha256:819d4860315468b482f38f1afe45a5437f60f03eaede495d5ff89f2eeac89500", + "sha256:8cc0e44905c2c8fda5637cad6f311eb9517017515a034247ab93d0cf99f8bb7a", + "sha256:8e8e2c2fe3d873108735c6ee9884e6f36f467df4a143136209cff303b183bada", + "sha256:98c2ffeab8b79a4e3a0af5dd9939f92980eb6e3fec10f7f313df5f35a84dacab", + "sha256:d59bb0e82002ac49f4152963f8a1079e66794a4f454457fd2f0dcc7bf0797d30", + "sha256:ee59b7bb9eb75932fe3787e54e61c99b628155b0cedc907864f24723ba55b309" ], "index": "pypi", - "version": "==3.1.1" + "version": "==3.1.2" }, "mccabe": { "hashes": [ @@ -1778,20 +1722,13 @@ "index": "pypi", "version": "==3.0.5" }, - "monotonic": { - "hashes": [ - "sha256:23953d55076df038541e648a53676fb24980f7a1be290cdda21300b3bc21dfb0", - "sha256:552a91f381532e33cbd07c6a2655a21908088962bb8fa7239ecbcc6ad1140cc7" - ], - "version": "==1.5" - }, "more-itertools": { "hashes": [ - "sha256:409cd48d4db7052af495b09dec721011634af3753ae1ef92d2b32f73a745f832", - "sha256:92b8c4b06dac4f0611c0729b2f2ede52b2e1bac1ab48f089c7ddc12e26bb60c4" + "sha256:b84b238cce0d9adad5ed87e745778d20a3f8487d0f0cb8b8a586816c7496458d", + "sha256:c833ef592a0324bcc6a60e48440da07645063c453880c9477ceb22490aec1564" ], - "markers": "python_version >= '3.4'", - "version": "==7.2.0" + "markers": "python_version >= '3.5'", + "version": "==8.0.2" }, "mpld3": { "hashes": [ @@ -1807,6 +1744,20 @@ "index": "pypi", "version": "==0.5.6" }, + "msrest": { + "hashes": [ + "sha256:56b8b5b4556fb2a92cac640df267d560889bdc9e2921187772d4691d97bc4e8d", + "sha256:f5153bfe60ee757725816aedaa0772cbfe0bddb52cd2d6db4cb8b4c3c6c6f928" + ], + "version": "==0.6.10" + }, + "msrestazure": { + "hashes": [ + "sha256:63db9f646fffc9244b332090e679d1e5f283ac491ee0cc321f5116f9450deb4a", + "sha256:fecb6a72a3eb5483e4deff38210d26ae42d3f6d488a7a275bd2423a1a014b22c" + ], + "version": "==0.6.2" + }, "nbconvert": { "hashes": [ "sha256:21fb48e700b43e82ba0e3142421a659d7739b65568cc832a13976a77be16b523", @@ -1817,18 +1768,18 @@ }, "nbformat": { "hashes": [ - "sha256:b9a0dbdbd45bb034f4f8893cafd6f652ea08c8c1674ba83f2dc55d3955743b0b", - "sha256:f7494ef0df60766b7cabe0a3651556345a963b74dbc16bc7c18479041170d402" + "sha256:cca9a1acfd4e049dcd6c3628d3c84db8e48a770182fb7b87d6a62f9ceacfae39", + "sha256:d1407544cf0c53ee88f504b6c732aef6e0f407a0858b405fcf133e0a25bb787b" ], - "version": "==4.4.0" + "version": "==5.0.3" }, "nbstripout": { "hashes": [ - "sha256:1960caf7d1c1e281126c6c5cb98053db89eca8aaa616b58eed381e3e1508c0f4", - "sha256:d35c553f724d3fb7ec9e9602c6e55a75101064a6bbec4f8c28e8c84d6e3dd060" + "sha256:62f1b1fe9c7c298061089fd9bd5d297eb6209f7fbef0758631dbe58d38fc828f", + "sha256:cf745ae8c49fccdb3068b73fc3b783898d5d62ee929429e9af37a6dfefba34b7" ], "index": "pypi", - "version": "==0.3.6" + "version": "==0.3.7" }, "networkx": { "hashes": [ @@ -1846,14 +1797,6 @@ "index": "pypi", "version": "==1.3.7" }, - "nose-parameterized": { - "hashes": [ - "sha256:8f519b9739ac67e3d95f69c15cc80416eea4d63559530d01a37b9565eb629277", - "sha256:d35e677aba2f15135b6b7ea7feb88f792b899492ba5365ec0e269015df5214ce" - ], - "index": "pypi", - "version": "==0.6.0" - }, "notebook": { "hashes": [ "sha256:399a4411e171170173344761e7fd4491a3625659881f76ce47c50231ed714d9b", @@ -1864,30 +1807,30 @@ }, "numpy": { "hashes": [ - "sha256:0a7a1dd123aecc9f0076934288ceed7fd9a81ba3919f11a855a7887cbe82a02f", - "sha256:0c0763787133dfeec19904c22c7e358b231c87ba3206b211652f8cbe1241deb6", - "sha256:3d52298d0be333583739f1aec9026f3b09fdfe3ddf7c7028cb16d9d2af1cca7e", - "sha256:43bb4b70585f1c2d153e45323a886839f98af8bfa810f7014b20be714c37c447", - "sha256:475963c5b9e116c38ad7347e154e5651d05a2286d86455671f5b1eebba5feb76", - "sha256:64874913367f18eb3013b16123c9fed113962e75d809fca5b78ebfbb73ed93ba", - "sha256:683828e50c339fc9e68720396f2de14253992c495fdddef77a1e17de55f1decc", - "sha256:6ca4000c4a6f95a78c33c7dadbb9495c10880be9c89316aa536eac359ab820ae", - "sha256:75fd817b7061f6378e4659dd792c84c0b60533e867f83e0d1e52d5d8e53df88c", - "sha256:7d81d784bdbed30137aca242ab307f3e65c8d93f4c7b7d8f322110b2e90177f9", - "sha256:8d0af8d3664f142414fd5b15cabfd3b6cc3ef242a3c7a7493257025be5a6955f", - "sha256:9679831005fb16c6df3dd35d17aa31dc0d4d7573d84f0b44cc481490a65c7725", - "sha256:a8f67ebfae9f575d85fa859b54d3bdecaeece74e3274b0b5c5f804d7ca789fe1", - "sha256:acbf5c52db4adb366c064d0b7c7899e3e778d89db585feadd23b06b587d64761", - "sha256:ada4805ed51f5bcaa3a06d3dd94939351869c095e30a2b54264f5a5004b52170", - "sha256:c7354e8f0eca5c110b7e978034cd86ed98a7a5ffcf69ca97535445a595e07b8e", - "sha256:e2e9d8c87120ba2c591f60e32736b82b67f72c37ba88a4c23c81b5b8fa49c018", - "sha256:e467c57121fe1b78a8f68dd9255fbb3bb3f4f7547c6b9e109f31d14569f490c3", - "sha256:ede47b98de79565fcd7f2decb475e2dcc85ee4097743e551fe26cfc7eb3ff143", - "sha256:f58913e9227400f1395c7b800503ebfdb0772f1c33ff8cb4d6451c06cabdf316", - "sha256:fe39f5fd4103ec4ca3cb8600b19216cd1ff316b4990f4c0b6057ad982c0a34d5" - ], - "index": "pypi", - "version": "==1.17.4" + "sha256:1786a08236f2c92ae0e70423c45e1e62788ed33028f94ca99c4df03f5be6b3c6", + "sha256:17aa7a81fe7599a10f2b7d95856dc5cf84a4eefa45bc96123cbbc3ebc568994e", + "sha256:20b26aaa5b3da029942cdcce719b363dbe58696ad182aff0e5dcb1687ec946dc", + "sha256:2d75908ab3ced4223ccba595b48e538afa5ecc37405923d1fea6906d7c3a50bc", + "sha256:39d2c685af15d3ce682c99ce5925cc66efc824652e10990d2462dfe9b8918c6a", + "sha256:56bc8ded6fcd9adea90f65377438f9fea8c05fcf7c5ba766bef258d0da1554aa", + "sha256:590355aeade1a2eaba17617c19edccb7db8d78760175256e3cf94590a1a964f3", + "sha256:70a840a26f4e61defa7bdf811d7498a284ced303dfbc35acb7be12a39b2aa121", + "sha256:77c3bfe65d8560487052ad55c6998a04b654c2fbc36d546aef2b2e511e760971", + "sha256:9537eecf179f566fd1c160a2e912ca0b8e02d773af0a7a1120ad4f7507cd0d26", + "sha256:9acdf933c1fd263c513a2df3dceecea6f3ff4419d80bf238510976bf9bcb26cd", + "sha256:ae0975f42ab1f28364dcda3dde3cf6c1ddab3e1d4b2909da0cb0191fa9ca0480", + "sha256:b3af02ecc999c8003e538e60c89a2b37646b39b688d4e44d7373e11c2debabec", + "sha256:b6ff59cee96b454516e47e7721098e6ceebef435e3e21ac2d6c3b8b02628eb77", + "sha256:b765ed3930b92812aa698a455847141869ef755a87e099fddd4ccf9d81fffb57", + "sha256:c98c5ffd7d41611407a1103ae11c8b634ad6a43606eca3e2a5a269e5d6e8eb07", + "sha256:cf7eb6b1025d3e169989416b1adcd676624c2dbed9e3bcb7137f51bfc8cc2572", + "sha256:d92350c22b150c1cae7ebb0ee8b5670cc84848f6359cf6b5d8f86617098a9b73", + "sha256:e422c3152921cece8b6a2fb6b0b4d73b6579bd20ae075e7d15143e711f3ca2ca", + "sha256:e840f552a509e3380b0f0ec977e8124d0dc34dc0e68289ca28f4d7c1d0d79474", + "sha256:f3d0a94ad151870978fb93538e95411c83899c9dc63e6fb65542f769568ecfa5" + ], + "index": "pypi", + "version": "==1.18.1" }, "oauthlib": { "hashes": [ @@ -1996,20 +1939,27 @@ ], "version": "==1.4.2" }, + "paramiko": { + "hashes": [ + "sha256:920492895db8013f6cc0179293147f830b8c7b21fdfc839b6bad760c27459d9f", + "sha256:9c980875fa4d2cb751604664e9a2d0f69096643f5be4db1b99599fe114a97b2f" + ], + "version": "==2.7.1" + }, "parso": { "hashes": [ - "sha256:63854233e1fadb5da97f2744b6b24346d2750b85965e7e399bec1620232797dc", - "sha256:666b0ee4a7a1220f65d367617f2cd3ffddff3e205f3f16a0284df30e774c2a9c" + "sha256:55cf25df1a35fd88b878715874d2c4dc1ad3f0eebd1e0266a67e1f55efccfbe1", + "sha256:5c1f7791de6bd5dbbeac8db0ef5594b36799de198b3f7f7014643b0c5536b9d3" ], - "version": "==0.5.1" + "version": "==0.5.2" }, "pbr": { "hashes": [ - "sha256:2c8e420cd4ed4cec4e7999ee47409e876af575d4c35a45840d59e8b5f3155ab8", - "sha256:b32c8ccaac7b1a20c0ce00ce317642e6cf231cf038f9875e0280e28af5bf7ac9" + "sha256:139d2625547dbfa5fb0b81daebb39601c478c21956dc57e2e07b74450a8c506b", + "sha256:61aa52a0f18b71c5cc58232d2cf8f8d09cd67fcad60b742a60124cb8d6951488" ], "index": "pypi", - "version": "==5.4.3" + "version": "==5.4.4" }, "percache": { "hashes": [ @@ -2035,39 +1985,38 @@ }, "pillow": { "hashes": [ - "sha256:047d9473cf68af50ac85f8ee5d5f21a60f849bc17d348da7fc85711287a75031", - "sha256:0f66dc6c8a3cc319561a633b6aa82c44107f12594643efa37210d8c924fc1c71", - "sha256:12c9169c4e8fe0a7329e8658c7e488001f6b4c8e88740e76292c2b857af2e94c", - "sha256:248cffc168896982f125f5c13e9317c059f74fffdb4152893339f3be62a01340", - "sha256:27faf0552bf8c260a5cee21a76e031acaea68babb64daf7e8f2e2540745082aa", - "sha256:285edafad9bc60d96978ed24d77cdc0b91dace88e5da8c548ba5937c425bca8b", - "sha256:384b12c9aa8ef95558abdcb50aada56d74bc7cc131dd62d28c2d0e4d3aadd573", - "sha256:38950b3a707f6cef09cd3cbb142474357ad1a985ceb44d921bdf7b4647b3e13e", - "sha256:4aad1b88933fd6dc2846552b89ad0c74ddbba2f0884e2c162aa368374bf5abab", - "sha256:4ac6148008c169603070c092e81f88738f1a0c511e07bd2bb0f9ef542d375da9", - "sha256:4deb1d2a45861ae6f0b12ea0a786a03d19d29edcc7e05775b85ec2877cb54c5e", - "sha256:59aa2c124df72cc75ed72c8d6005c442d4685691a30c55321e00ed915ad1a291", - "sha256:5a47d2123a9ec86660fe0e8d0ebf0aa6bc6a17edc63f338b73ea20ba11713f12", - "sha256:5cc901c2ab9409b4b7ac7b5bcc3e86ac14548627062463da0af3b6b7c555a871", - "sha256:6c1db03e8dff7b9f955a0fb9907eb9ca5da75b5ce056c0c93d33100a35050281", - "sha256:7ce80c0a65a6ea90ef9c1f63c8593fcd2929448613fc8da0adf3e6bfad669d08", - "sha256:809c19241c14433c5d6135e1b6c72da4e3b56d5c865ad5736ab99af8896b8f41", - "sha256:83792cb4e0b5af480588601467c0764242b9a483caea71ef12d22a0d0d6bdce2", - "sha256:846fa202bd7ee0f6215c897a1d33238ef071b50766339186687bd9b7a6d26ac5", - "sha256:9f5529fc02009f96ba95bea48870173426879dc19eec49ca8e08cd63ecd82ddb", - "sha256:a423c2ea001c6265ed28700df056f75e26215fd28c001e93ef4380b0f05f9547", - "sha256:ac4428094b42907aba5879c7c000d01c8278d451a3b7cccd2103e21f6397ea75", - "sha256:b1ae48d87f10d1384e5beecd169c77502fcc04a2c00a4c02b85f0a94b419e5f9", - "sha256:bf4e972a88f8841d8fdc6db1a75e0f8d763e66e3754b03006cbc3854d89f1cb1", - "sha256:c6414f6aad598364aaf81068cabb077894eb88fed99c6a65e6e8217bab62ae7a", - "sha256:c710fcb7ee32f67baf25aa9ffede4795fd5d93b163ce95fdc724383e38c9df96", - "sha256:c7be4b8a09852291c3c48d3c25d1b876d2494a0a674980089ac9d5e0d78bd132", - "sha256:c9e5ffb910b14f090ac9c38599063e354887a5f6d7e6d26795e916b4514f2c1a", - "sha256:e0697b826da6c2472bb6488db4c0a7fa8af0d52fa08833ceb3681358914b14e5", - "sha256:e9a3edd5f714229d41057d56ac0f39ad9bdba6767e8c888c951869f0bdd129b0" - ], - "index": "pypi", - "version": "==6.2.1" + "sha256:0a628977ac2e01ca96aaae247ec2bd38e729631ddf2221b4b715446fd45505be", + "sha256:4d9ed9a64095e031435af120d3c910148067087541131e82b3e8db302f4c8946", + "sha256:54ebae163e8412aff0b9df1e88adab65788f5f5b58e625dc5c7f51eaf14a6837", + "sha256:5bfef0b1cdde9f33881c913af14e43db69815c7e8df429ceda4c70a5e529210f", + "sha256:5f3546ceb08089cedb9e8ff7e3f6a7042bb5b37c2a95d392fb027c3e53a2da00", + "sha256:5f7ae9126d16194f114435ebb79cc536b5682002a4fa57fa7bb2cbcde65f2f4d", + "sha256:62a889aeb0a79e50ecf5af272e9e3c164148f4bd9636cc6bcfa182a52c8b0533", + "sha256:7406f5a9b2fd966e79e6abdaf700585a4522e98d6559ce37fc52e5c955fade0a", + "sha256:8453f914f4e5a3d828281a6628cf517832abfa13ff50679a4848926dac7c0358", + "sha256:87269cc6ce1e3dee11f23fa515e4249ae678dbbe2704598a51cee76c52e19cda", + "sha256:875358310ed7abd5320f21dd97351d62de4929b0426cdb1eaa904b64ac36b435", + "sha256:8ac6ce7ff3892e5deaab7abaec763538ffd011f74dc1801d93d3c5fc541feee2", + "sha256:91b710e3353aea6fc758cdb7136d9bbdcb26b53cefe43e2cba953ac3ee1d3313", + "sha256:9d2ba4ed13af381233e2d810ff3bab84ef9f18430a9b336ab69eaf3cd24299ff", + "sha256:a62ec5e13e227399be73303ff301f2865bf68657d15ea50b038d25fc41097317", + "sha256:ab76e5580b0ed647a8d8d2d2daee170e8e9f8aad225ede314f684e297e3643c2", + "sha256:bf4003aa538af3f4205c5fac56eacaa67a6dd81e454ffd9e9f055fff9f1bc614", + "sha256:bf598d2e37cf8edb1a2f26ed3fb255191f5232badea4003c16301cb94ac5bdd0", + "sha256:c18f70dc27cc5d236f10e7834236aff60aadc71346a5bc1f4f83a4b3abee6386", + "sha256:c5ed816632204a2fc9486d784d8e0d0ae754347aba99c811458d69fcdfd2a2f9", + "sha256:dc058b7833184970d1248135b8b0ab702e6daa833be14035179f2acb78ff5636", + "sha256:ff3797f2f16bf9d17d53257612da84dd0758db33935777149b3334c01ff68865" + ], + "index": "pypi", + "version": "==7.0.0" + }, + "portalocker": { + "hashes": [ + "sha256:6f57aabb25ba176462dc7c63b86c42ad6a9b5bd3d679a9d776d0536bfb803d54", + "sha256:dac62e53e5670cb40d2ee4cdc785e6b829665932c3ee75307ad677cf5f7d2e9f" + ], + "version": "==1.5.2" }, "pprofile": { "hashes": [ @@ -2092,42 +2041,27 @@ }, "protobuf": { "hashes": [ - "sha256:125713564d8cfed7610e52444c9769b8dcb0b55e25cc7841f2290ee7bc86636f", - "sha256:1accdb7a47e51503be64d9a57543964ba674edac103215576399d2d0e34eac77", - "sha256:27003d12d4f68e3cbea9eb67427cab3bfddd47ff90670cb367fcd7a3a89b9657", - "sha256:3264f3c431a631b0b31e9db2ae8c927b79fc1a7b1b06b31e8e5bcf2af91fe896", - "sha256:3c5ab0f5c71ca5af27143e60613729e3488bb45f6d3f143dc918a20af8bab0bf", - "sha256:45dcf8758873e3f69feab075e5f3177270739f146255225474ee0b90429adef6", - "sha256:56a77d61a91186cc5676d8e11b36a5feb513873e4ae88d2ee5cf530d52bbcd3b", - "sha256:5984e4947bbcef5bd849d6244aec507d31786f2dd3344139adc1489fb403b300", - "sha256:6b0441da73796dd00821763bb4119674eaf252776beb50ae3883bed179a60b2a", - "sha256:6f6677c5ade94d4fe75a912926d6796d5c71a2a90c2aeefe0d6f211d75c74789", - "sha256:84a825a9418d7196e2acc48f8746cf1ee75877ed2f30433ab92a133f3eaf8fbe", - "sha256:b842c34fe043ccf78b4a6cf1019d7b80113707d68c88842d061fa2b8fb6ddedc", - "sha256:ca33d2f09dae149a1dcf942d2d825ebb06343b77b437198c9e2ef115cf5d5bc1", - "sha256:cc9af00df3fc9302f537a8335668c20be27916b2277e9a5eaed510266e2bb33b", - "sha256:db83b5c12c0cd30150bb568e6feb2435c49ce4e68fe2d7b903113f0e221e58fe", - "sha256:f50f3b1c5c1c1334ca7ce9cad5992f098f460ffd6388a3cabad10b66c2006b09", - "sha256:f99f127909731cafb841c52f9216e447d3e4afb99b17bebfad327a75aee206de" - ], - "version": "==3.10.0" - }, - "psutil": { - "hashes": [ - "sha256:021d361439586a0fd8e64f8392eb7da27135db980f249329f1a347b9de99c695", - "sha256:145e0f3ab9138165f9e156c307100905fd5d9b7227504b8a9d3417351052dc3d", - "sha256:348ad4179938c965a27d29cbda4a81a1b2c778ecd330a221aadc7bd33681afbd", - "sha256:3feea46fbd634a93437b718518d15b5dd49599dfb59a30c739e201cc79bb759d", - "sha256:474e10a92eeb4100c276d4cc67687adeb9d280bbca01031a3e41fb35dfc1d131", - "sha256:47aeb4280e80f27878caae4b572b29f0ec7967554b701ba33cd3720b17ba1b07", - "sha256:73a7e002781bc42fd014dfebb3fc0e45f8d92a4fb9da18baea6fb279fbc1d966", - "sha256:d051532ac944f1be0179e0506f6889833cf96e466262523e57a871de65a15147", - "sha256:dfb8c5c78579c226841908b539c2374da54da648ee5a837a731aa6a105a54c00", - "sha256:e3f5f9278867e95970854e92d0f5fe53af742a7fc4f2eba986943345bcaed05d", - "sha256:e9649bb8fc5cea1f7723af53e4212056a6f984ee31784c10632607f472dec5ee" - ], - "index": "pypi", - "version": "==5.6.5" + "sha256:0329e86a397db2a83f9dcbe21d9be55a47f963cdabc893c3a24f4d3a8f117c37", + "sha256:0a7219254afec0d488211f3d482d8ed57e80ae735394e584a98d8f30a8c88a36", + "sha256:14d6ac53df9cb5bb87c4f91b677c1bc5cec9c0fd44327f367a3c9562de2877c4", + "sha256:180fc364b42907a1d2afa183ccbeffafe659378c236b1ec3daca524950bb918d", + "sha256:3d7a7d8d20b4e7a8f63f62de2d192cfd8b7a53c56caba7ece95367ca2b80c574", + "sha256:3f509f7e50d806a434fe4a5fbf602516002a0f092889209fff7db82060efffc0", + "sha256:4571da974019849201fc1ec6626b9cea54bd11b6bed140f8f737c0a33ea37de5", + "sha256:557686c43fbd04f5f7c533f00feee9a37dcca7b5896e3ae3664a33864e6dd546", + "sha256:56bd1d84fbf4505c7b73f04de987eef5682e5752c811141b0186a3809bfb396f", + "sha256:680c668d00b5eff08b86aef9e5ba9a705e621ea05d39071cfea8e28cb2400946", + "sha256:6b5b947dc8b3f2aec0eaad65b0b5113fcd642c358c31357c647da6281ee31104", + "sha256:6e96dffaf4d0a9a329e528b353ba62fd9ef13599688723d96bc9c165d0b6871e", + "sha256:919f0d6f6addc836d08658eba3b52be2e92fd3e76da3ce00c325d8e9826d17c7", + "sha256:9c7b19c30cf0644afd0e4218b13f637ce54382fdcb1c8f75bf3e84e49a5f6d0a", + "sha256:a2e6f57114933882ec701807f217df2fb4588d47f71f227c0a163446b930d507", + "sha256:a6b970a2eccfcbabe1acf230fbf112face1c4700036c95e195f3554d7bcb04c1", + "sha256:bc45641cbcdea068b67438244c926f9fd3e5cbdd824448a4a64370610df7c593", + "sha256:d61b14a9090da77fe87e38ba4c6c43d3533dcbeb5d84f5474e7ac63c532dcc9c", + "sha256:d6faf5dbefb593e127463f58076b62fcfe0784187be8fe1aa9167388f24a22a1" + ], + "version": "==3.11.2" }, "ptyprocess": { "hashes": [ @@ -2139,8 +2073,19 @@ }, "pyasn1": { "hashes": [ + "sha256:014c0e9976956a08139dc0712ae195324a75e142284d5f87f1a87ee1b068a359", + "sha256:03840c999ba71680a131cfaee6fab142e1ed9bbd9c693e285cc6aca0d555e576", + "sha256:0458773cfe65b153891ac249bcf1b5f8f320b7c2ce462151f8fa74de8934becf", + "sha256:08c3c53b75eaa48d71cf8c710312316392ed40899cb34710d092e96745a358b7", "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", - "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba" + "sha256:5c9414dcfede6e441f7e8f81b43b34e834731003427e5b09e4e00e3172a10f00", + "sha256:6e7545f1a61025a4e58bb336952c5061697da694db1cae97b116e9c46abcf7c8", + "sha256:78fa6da68ed2727915c4767bb386ab32cdba863caa7dbe473eaae45f9959da86", + "sha256:7ab8a544af125fb704feadb008c99a88805126fb525280b2270bb25cc1d78a12", + "sha256:99fcc3c8d804d1bc6d9a099921e39d827026409a58f2a720dcdb89374ea0c776", + "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba", + "sha256:e89bf84b5437b532b0803ba5c9a5e054d21fec423a89952a74f87fa2c9b7bce2", + "sha256:fec3e9d8e36808a28efb59b489e4528c10ad0f480e57dcc32b4de5c9d8c9fdf3" ], "version": "==0.4.8" }, @@ -2164,9 +2109,9 @@ }, "pycocotools": { "git": "https://github.com/cocodataset/cocoapi.git", - "ref": "636becdc73d54283b3aac6d4ec363cffbb6f9b20", + "ref": "e140a084d678eacd18e85a9d8cfa45d1d5911db9", "subdirectory": "PythonAPI", - "version": "==2.0" + "version": "==0.0.0" }, "pycparser": { "hashes": [ @@ -2215,11 +2160,11 @@ }, "pygments": { "hashes": [ - "sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127", - "sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297" + "sha256:2a3fe295e54a20164a9df49c75fa58526d3be48e14aceba6d6b1e8ac0bfd6f1b", + "sha256:98c8aa5a9f778fcd1026a17361ddaf7330d1b7c62ae97c3bb0ae73e0b9b6b0fe" ], "index": "pypi", - "version": "==2.4.2" + "version": "==2.5.2" }, "pyjwt": { "hashes": [ @@ -2246,40 +2191,65 @@ }, "pymongo": { "hashes": [ - "sha256:09f8196e1cb081713aa3face08d1806dc0a5dd64cb9f67fefc568519253a7ff2", - "sha256:1be549c0ce2ba8242c149156ae2064b12a5d4704448d49f630b4910606efd474", - "sha256:1f9fe869e289210250cba4ea20fbd169905b1793e1cd2737f423e107061afa98", - "sha256:3653cea82d1e35edd0a2355150daf8a27ebf12cf55182d5ad1046bfa288f5140", - "sha256:4249c6ba45587b959292a727532826c5032d59171f923f7f823788f413c2a5a3", - "sha256:4ff8f5e7c0a78983c1ee07894fff1b21c0e0ad3a122d9786cc3745fd60e4a2ce", - "sha256:56b29c638ab924716b48a3e94e3d7ac00b04acec1daa8190c36d61fc714c3629", - "sha256:56ec9358bbfe5ae3b25e785f8a14619d6799c855a44734c9098bb457174019bf", - "sha256:5b59bbde4eb417f3f9379f7b1a9de3669894f2bae9de933a836e2bffea2bbfa1", - "sha256:5dca250cbf1183c3e7b7b18c882c2b2199bfb20c74c4c68dbf11596808a296da", - "sha256:61101d1cc92881fac1f9ac7e99b033062f4c210178dc33193c8f5567feecb069", - "sha256:7b4aea184e4868ebd4f9f786ffee14a1121bda5436ad04f6bcbacfa2147f8386", - "sha256:86624c0205a403fb4fbfedef79c5b4ab27e21fd018fdb6a27cf03b3c32a9e2b9", - "sha256:88ac09e1b197c3b4531e43054d49c022a3ea1281431b2f4980abafa35d2a5ce2", - "sha256:8b0339809b12ea292d468524dd1777f1a9637d9bdc0353a9261b88f82537d606", - "sha256:93dbf7388f6bf9af48dbb32f265b75b3dbc743a7a2ce98e44c88c049c58d85d3", - "sha256:9b705daec636c560dd2d63935f428a6b3cddfe903fffc0f349e0e91007c893d6", - "sha256:a090a819fe6fefadc2901d3911c07c76c0935ec5c790a50e9f3c3c47bacd5978", - "sha256:a102b346f1921237eaa9a31ee89eda57ad3c3973d79be3a456d92524e7df8fec", - "sha256:a13363869f2f36291d6367069c65d51d7b8d1b2fb410266b0b6b1f3c90d6deb0", - "sha256:a409a43c76da50881b70cc9ee70a1744f882848e8e93a68fb434254379777fa3", - "sha256:a76475834a978058425b0163f1bad35a5f70e45929a543075633c3fc1df564c5", - "sha256:ad474e93525baa6c58d75d63a73143af24c9f93c8e26e8d382f32c4da637901a", - "sha256:b268c7fa03ac77a8662fab3b2ab0be4beecb82f60f4c24b584e69565691a107f", - "sha256:b67ec339b180acdbebcd03807ae4b1764a43e7069340fe860a60ac310b9d38be", - "sha256:cca4e1ab5ba0cd7877d3938167ee8ae9c2986cc0e10d3dcc3243d664d3a83fec", - "sha256:cef61de3f0f4441ec40266ff2ab42e5c16eaba1dc1fc6e1036f274621c52adc1", - "sha256:e28153b5d5ca33d4ba0c3bbc0e1ff161b9016e5e5f3f8ca10d6fa49106eb9e04", - "sha256:f30d7b37804daf0bab1143abc71666c630d7e270f5c14c5a7c300a6699c21108", - "sha256:f70f0133301cccf9bfd68fd20f67184ef991be578b646e78441106f9e27cc44d", - "sha256:fa75c21c1d82f20cce62f6fc4a68c2b0f33572ab406df1b17cd77a947d0b2993" - ], - "index": "pypi", - "version": "==3.9.0" + "sha256:0369136c6e79c5edc16aa5de2b48a1b1c1fe5e6f7fc5915a2deaa98bd6e9dad5", + "sha256:08364e1bea1507c516b18b826ec790cb90433aec2f235033ec5eecfd1011633b", + "sha256:0af1d2bc8cc9503bf92ec3669a77ec3a6d7938193b583fb867b7e9696eed52e8", + "sha256:0cfd1aeeb8c0a634646ab3ebeb4ce6828b94b2e33553a69ff7e6c07c250bf201", + "sha256:15bbd2b5397f7d22498e2f2769fd698a8a247b9cc1a630ee8dabf647fb333480", + "sha256:1b4a13dff15641e58620524db15d7a323d60572b2b187261c5cb58c36d74778d", + "sha256:22fbdb908257f9aaaa372a7684f3e094a05ca52eb84f8f381c8b1827c49556fd", + "sha256:264272fd1c95fc48002ad85d5e41270831777b4180f2500943e45e12b2a3ab43", + "sha256:3372e98eebbfd05ebf020388003f8a4438bed41e0fef1ef696d2c13633c416c8", + "sha256:339d24ecdc42745d2dc09b26fda8151988e806ca81134a7bd10513c4031d91e1", + "sha256:38281855fc3961ba5510fbb503b8d16cc1fcb326e9f7ba0dd096ed4eb72a7084", + "sha256:4acdd2e16392472bfd49ca49038845c95e5254b5af862b55f7f2cc79aa258886", + "sha256:4e0c006bc6e98e861b678432e05bf64ba3eb889b6ab7e7bf1ebaecf9f1ba0e58", + "sha256:4e4284bcbe4b7be1b37f9641509085b715c478e7fbf8f820358362b5dd359379", + "sha256:4e5e94a5f9823f0bd0c56012a57650bc6772636c29d83d253260c26b908fcfd9", + "sha256:4e61f30800a40f1770b2ec56bbf5dc0f0e3f7e9250eb05fa4feb9ccb7bbe39ca", + "sha256:53577cf57ba9d93b58ab41d45250277828ff83c5286dde14f855e4b17ec19976", + "sha256:681cb31e8631882804a6cc3c8cc8f54a74ff3a82261a78e50f20c5eec05ac855", + "sha256:6dfc2710f43dd1d66991a0f160d196356732ccc8aa9dbc6875aeba78388fa142", + "sha256:72218201b13d8169be5736417987e9a0a3b10d4349e40e4db7a6a5ac670c7ef2", + "sha256:7247fbcdbf7ab574eb70743461b3cfc14d9cfae3f27a9afb6ce14d87f67dd0b5", + "sha256:72651f4b4adf50201891580506c8cca465d94d38f26ed92abfc56440662c723c", + "sha256:87b3aaf12ad6a9b5570b12d2a4b8802757cb3588a903aafd3c25f07f9caf07e3", + "sha256:87c28b7b37617c5a01eb396487f7d3b61a453e1fa0475a175ab87712d6f5d52f", + "sha256:88efe627b628f36ef53f09abb218d4630f83d8ebde7028689439559475c43dae", + "sha256:89bfbca22266f12df7fb80092b7c876734751d02b93789580b68957ad4a8bf56", + "sha256:908a3caf348a672b28b8a06fe7b4a27c2fdcf7f873df671e4027d48bcd7f971f", + "sha256:9128e7bea85f3a3041306fa14a7aa82a24b47881918500e1b8396dd1c933b5a6", + "sha256:9737d6d688a15b8d5c0bfa909638b79261e195be817b9f1be79c722bbb23cd76", + "sha256:98a8305da158f46e99e7e51db49a2f8b5fcdd7683ea7083988ccb9c4450507a6", + "sha256:99285cd44c756f0900cbdb5fe75f567c0a76a273b7e0467f23cb76f47e60aac0", + "sha256:9ed568f8026ffeb00ce31e5351e0d09d704cc19a29549ba4da0ac145d2a26fdf", + "sha256:a006162035032021dfd00a879643dc06863dac275f9210d843278566c719eebc", + "sha256:a03cb336bc8d25a11ff33b94967478a9775b0d2b23b39e952d9cc6cb93b75d69", + "sha256:a863ceb67be163060d1099b7e89b6dd83d6dd50077c7ceae31ac844c4c2baff9", + "sha256:b82628eaf0a16c1f50e1c205fd1dd406d7874037dd84643da89e91b5043b5e82", + "sha256:bc6446a41fb7eeaf2c808bab961b9bac81db0f5de69eab74eebe1b8b072399f7", + "sha256:c42d290ed54096355838421cf9d2a56e150cb533304d2439ef1adf612a986eaf", + "sha256:c43879fe427ea6aa6e84dae9fbdc5aa14428a4cfe613fe0fee2cc004bf3f307c", + "sha256:c566cbdd1863ba3ccf838656a1403c3c81fdb57cbe3fdd3515be7c9616763d33", + "sha256:c5b7a0d7e6ca986de32b269b6dbbd5162c1a776ece72936f55decb4d1b197ee9", + "sha256:ca109fe9f74da4930590bb589eb8fdf80e5d19f5cd9f337815cac9309bbd0a76", + "sha256:d0260ba68f9bafd8775b2988b5aeace6e69a37593ec256e23e150c808160c05c", + "sha256:d12d86e771fc3072a0e6bdbf4e417c63fec85ee47cb052ba7ad239403bf5e154", + "sha256:d2ce33501149b373118fcfec88a292a87ef0b333fb30c7c6aac72fe64700bdf6", + "sha256:d582ea8496e2a0e124e927a67dca55c8833f0dbfbc2c84aaf0e5949a2dd30c51", + "sha256:d68b9ab0a900582a345fb279675b0ad4fac07d6a8c2678f12910d55083b7240d", + "sha256:dbf1fa571db6006907aeaf6473580aaa76041f4f3cd1ff8a0039fd0f40b83f6d", + "sha256:e032437a7d2b89dab880c79379d88059cee8019da0ff475d924c4ccab52db88f", + "sha256:e0f5798f3ad60695465a093e3d002f609c41fef3dcb97fcefae355d24d3274cf", + "sha256:e756355704a2cf91a7f4a649aa0bbf3bbd263018b9ed08f60198c262f4ee24b6", + "sha256:e824b4b87bd88cbeb25c8babeadbbaaaf06f02bbb95a93462b7c6193a064974e", + "sha256:ea1171470b52487152ed8bf27713cc2480dc8b0cd58e282a1bff742541efbfb8", + "sha256:fa19aef44d5ed8f798a8136ff981aedfa508edac3b1bed481eca5dde5f14fd3d", + "sha256:faf83d20c041637cb277e5fdb59abc217c40ab3202dd87cc95d6fbd9ce5ffd9b", + "sha256:fceb6ae5a149a42766efb8344b0df6cfb21b55c55f360170abaddb11d43af0f1" + ], + "index": "pypi", + "version": "==3.10.0" }, "pymysql": { "hashes": [ @@ -2324,13 +2294,20 @@ "index": "pypi", "version": "==1.15.0" }, + "pyopenssl": { + "hashes": [ + "sha256:621880965a720b8ece2f1b2f54ea2071966ab00e2970ad2ce11d596102063504", + "sha256:9a24494b2602aaf402be5c9e30a0b82d4a5c67528fe8fb475e3f3bc00dd69507" + ], + "version": "==19.1.0" + }, "pyparsing": { "hashes": [ - "sha256:20f995ecd72f2a1f4bf6b072b63b22e2eb457836601e76d6e5dfcd75436acc1f", - "sha256:4ca62001be367f01bd3e92ecbb79070272a9d4964dce6a48a82ff0b8bc7e683a" + "sha256:4c830582a84fb022400b85429791bc551f1f4871c33f23e44f353119e92f969f", + "sha256:c342dccb5250c08d45fd6f8b4a559613ca603b57498511740e65cd11a2e7dcec" ], "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.4.5" + "version": "==2.4.6" }, "pypolyline": { "hashes": [ @@ -2350,41 +2327,46 @@ }, "pyproj": { "hashes": [ - "sha256:0e59b9120ba4729d4bbbfb60bfb3206c9d119c55a92227d11b967892c3e82606", - "sha256:1ea692abc31199d3b0c614d0f8d0b8e8cf0ac9d104df6cbd1159ed4f6c12f318", - "sha256:346ceff4a5a07ef4ef19c51f617e30222554eb48418f22a370497918d389a6d4", - "sha256:3ad7c8c2e5cebd8c40e7101fb5f7c8dbe3dd73787b22611474c3db39a77affec", - "sha256:52d3c8ff42547c7f087d3adc08f7217a7d3c392923708e1ba9a3eb964caecd7c", - "sha256:53aa9b9febf247fc2f407682cd64a052d0a0275838ad4f9dd8bcb6960c8bd68b", - "sha256:5d11b2ff5721d4384388df18498513987979e327fb2dd675062a28024e462f0c", - "sha256:6343e499b4d430637616b1362197b6c4014516e7c2839fd9ff492b34b885f14f", - "sha256:817d4b762adee4479200471042e2393f75a8ec2384061979ccfe177b862b4f8b", - "sha256:8eb1eeaba895282a44e11e9c83696d7ac567925f00d847001f118e73335c7554", - "sha256:8f266a968085b3c1fbe9abc238127ecf3f058461e0cb2d1250dc86077e84e9ba", - "sha256:95cade1aa565e98b23585b1b1e900d949ffde0424f724290d8763f3df75fed4a", - "sha256:a1422da59673ca5bf56d89cf8e2a3cb2c9868bea27bbee6600ae603d322316a8", - "sha256:a25e50194af94e312d21952386522a7bbd97118056e913e47f2bb9cfca70a117", - "sha256:a2b08ac9c285e1adfec35756f561079638a333781e315777e497150e57d8dca9", - "sha256:b86c4c52d9bf0c7118541e9b001cddf0d027a8d49503641101faad60d6abb759", - "sha256:c173b6a33cb4c9eb40e78fc0d8a4c4e227f997f6a02ba665e27871cd308c346b", - "sha256:c32441a0526ff600cb69bad6f8f9748bca78b6be9e5ad8d0eade29aeb252fbce", - "sha256:cdb17bef8862a41c86cb51d8f3fdadee9fe1afd9a3362814c2eda59a5ce08133", - "sha256:e027eed39a6ba0f63ab108962c550995474be58f77b80470fa4a9bc0114161a5", - "sha256:efca2ef75eb75bf2a6451a2ea4760c3b371e08a66bfa8a6abafd997de1fcd74e", - "sha256:f93f42c50e40ee6358d6006c4b5be927d83ad402080438617c2182a62a7b3700" - ], - "index": "pypi", - "version": "==2.4.1" + "sha256:0608ac0aed84dcf57c859df87ac315b9acce18268f62bafc04071b7b1ff1c5a9", + "sha256:18265fb755e01df1d2248f1e837d81da4c9625e8f09481d64a9d6282c96f7467", + "sha256:190540946bb6fbfce285f46c08fcfd9d03e9331a0e952a3ef2047e6b8e8d8125", + "sha256:1da7f86d3b5e80ba3dabfd2c904a41bb6997ad9b55b47a934035492eaa0f331e", + "sha256:2ebbaee33e076664058effc3f6c943ed4c19a45df3989203ac081fca4a4722e3", + "sha256:32168c57450a1e6310b7ca331983d62d88393cc3e93b866fd6ea63dac30c7d3b", + "sha256:34b8ccf42032d89ebb8e0a839ae91e943ed222dab9bf3c1373f6fb972f8bcac4", + "sha256:432b4d28030635fac72713610aad2ed7424a7f07746fa1aa620c89761eb5e7a4", + "sha256:55103aa0adf25d207efd6f7f36d79dadee7706f22c1791955cc52033b40071e3", + "sha256:6bc74337edc1239f8c59d0d5b18a7996670b8fd523712d2dac599d5b792feae2", + "sha256:6d2838bec2d9ccd31dba68c76e8e7504bf819a4d4ace86adfca1e009d8f30f19", + "sha256:763ccac4398889cb798668824d34c4135f2e84a50681465a4199554aa1bd8611", + "sha256:8dbf1633ad2abdae6f73fe8989700c74a12dc82cb8597e66af28ff3d990d9c45", + "sha256:8ddffa4bcd9008c963840e8e79f2f3124f85f18d5987d4bbd9e7f38d9839a985", + "sha256:8f225c6186b0cd2cb07fe377786425a2ddc4183ae438fe63c60b4a879c91620f", + "sha256:97844a87cac739e389d1d0c69bc3b36c1d5c50c9f91443ef68bdef8fdf007f02", + "sha256:9d7a13def19a91836a2c84e5c7fcb6dd5e2c9bb205fb75ee102ffba24d80bf32", + "sha256:abd0784a017eedb3b03cd13f51b8852f4c68aa07affbee549bbd421f9b4268bb", + "sha256:acf150ca1506fcdaa52b0570f2903216413a2a4da78dfdf5ff7ee4eb92c2f8d5", + "sha256:b41522f8b77b64553280fb93823555bc8afb2469f77b8ce0e9aeed39abb50adc", + "sha256:c1058da6c02152d8637bb739dca940c6ab72683e59db6065fdcbe9102f66ca46", + "sha256:c70e713748c9c9d4a9d7bc42e1c71a17b1fc9b75b686b408a04eaf4909ead365", + "sha256:d47caa0a89dcb39ecd405e3899e07b69d8eaa6dbf267621087a4a5328da8492a", + "sha256:ed186edb4b610ed1e5589f3ba964d61da33d0bc54e89b8cbf8751da2e18555b3", + "sha256:f2dc8c2128f20ee9ed571783ce4730b181476083c403514714e15000b8b470cf", + "sha256:fba87f98344474da6df19bbfde4ca31c7d98a007069c8ef78cb27189f4bc7f04" + ], + "index": "pypi", + "version": "==2.4.2.post1" }, "pyqt5": { "hashes": [ - "sha256:14737bb4673868d15fa91dad79fe293d7a93d76c56d01b3757b350b8dcb32b2d", - "sha256:1936c321301f678d4e6703d52860e1955e5c4964e6fd00a1f86725ce5c29083c", - "sha256:3f79de6e9f29e858516cc36ffc2b992e262af841f3799246aec282b76a3eccdf", - "sha256:509daab1c5aca22e3cf9508128abf38e6e5ae311d7426b21f4189ffd66b196e9" + "sha256:2b79209aa6e4688f6ac46e6d2694236dcf91db5f3a87270150d0f82082e3d360", + "sha256:2f230f2dbd767099de7a0cb915abdf0cbc3256a0b5bb910eb09b99117db7a65b", + "sha256:3d6e315e6e2d6489a2e1e0148d00e784e277c6590c189227d6060f15b9be690a", + "sha256:812233bd155735377e2e9c7eea7a28815f357440334db51788d941e2a8b62f64", + "sha256:be10fa95e6bdc9cad616ebf368c51b3f5748138b2b3a600cf7c4f80b78cb9852" ], "index": "pypi", - "version": "==5.13.2" + "version": "==5.14.1" }, "pyqt5-sip": { "hashes": [ @@ -2411,9 +2393,9 @@ }, "pyrsistent": { "hashes": [ - "sha256:eb6545dbeb1aa69ab1fb4809bfbf5a8705e44d92ef8fc7c2361682a47c46c778" + "sha256:f3b280d030afb652f79d67c5586157c5c1355c9a58dfc7940566e28d28f3df1b" ], - "version": "==0.15.5" + "version": "==0.15.6" }, "pysdl2": { "hashes": [ @@ -2422,13 +2404,6 @@ "index": "pypi", "version": "==0.9.6" }, - "pysendfile": { - "hashes": [ - "sha256:510a414b270986fba3c79cb76d90a4c910c701bfb43ff983a5d4e92846050e17" - ], - "index": "pypi", - "version": "==2.0.1" - }, "python-dateutil": { "hashes": [ "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c", @@ -2439,10 +2414,10 @@ }, "python-engineio": { "hashes": [ - "sha256:4a13fb87c819b855c55a731fdf82559adb8311c04cfdfebd6b9ecd1c2afbb575", - "sha256:9c9a6035b4b5e5a225f426f846afa14cf627f7571d1ae02167cb703fefd134b7" + "sha256:47ae4a9b3b4f2e8a68929f37a518338838e119f24c9a9121af92c49f8bea55c3", + "sha256:c3a3822deb51fdf9c7fe4d78abf807c73b83ea538036a50862d3024450746253" ], - "version": "==3.10.0" + "version": "==3.11.2" }, "python-logstash": { "hashes": [ @@ -2453,18 +2428,18 @@ }, "python-logstash-async": { "hashes": [ - "sha256:897152edc052fbf7f711eef057570660ac5f33f9dac5fd4ea261a4898d2061eb", - "sha256:abc5bf9a367b49e20990398752b3be4aa67d7b37500fff7b551a5264a1609f4e" + "sha256:16a85e7c76265b06e2e42f5a2babc39811e3920aaa41119e059722d4185f1912", + "sha256:6f2da753ee2307704b0c0d2e3dc6a52e3ad0605184690b4495356e418700abaa" ], "index": "pypi", - "version": "==1.6.0" + "version": "==1.6.2" }, "python-socketio": { "hashes": [ - "sha256:506b2cf7a520b40ea0b3f25e1272eff8de134dce6f471c1f6bc0de8c90fe8c57", - "sha256:d4e2c23241afa0aae2a5bcc107523b2fcc71f5020df89a093f3634eb48955967" + "sha256:48cba5b827ac665dbf923a4f5ec590812aed5299a831fc43576a9af346272534", + "sha256:af6c23c35497960f82106e36688123ecb52ad5a77d0ca27954ff3811c4d9d562" ], - "version": "==4.3.1" + "version": "==4.4.0" }, "pytz": { "hashes": [ @@ -2473,14 +2448,6 @@ ], "version": "==2019.3" }, - "pyvcd": { - "hashes": [ - "sha256:791fd7608fb8113c9658f699cb6292d66d7fb90bcab9ebc00b05adc40da7a5ce", - "sha256:bdcb848b79cea2196ebf317178eff2c9c7d6354b85f9eb4991e9175f98e26937" - ], - "index": "pypi", - "version": "==0.1.4" - }, "pywavelets": { "hashes": [ "sha256:076ca8907001fdfe4205484f719d12b4a0262dfe6652fa1cfc3c5c362d14dc84", @@ -2508,6 +2475,23 @@ "markers": "python_version >= '3.5'", "version": "==1.1.1" }, + "pyyaml": { + "hashes": [ + "sha256:059b2ee3194d718896c0ad077dd8c043e5e909d9180f387ce42012662a4946d6", + "sha256:1cf708e2ac57f3aabc87405f04b86354f66799c8e62c28c5fc5f88b5521b2dbf", + "sha256:24521fa2890642614558b492b473bee0ac1f8057a7263156b02e8b14c88ce6f5", + "sha256:4fee71aa5bc6ed9d5f116327c04273e25ae31a3020386916905767ec4fc5317e", + "sha256:70024e02197337533eef7b85b068212420f950319cc8c580261963aefc75f811", + "sha256:74782fbd4d4f87ff04159e986886931456a1894c61229be9eaf4de6f6e44b99e", + "sha256:940532b111b1952befd7db542c370887a8611660d2b9becff75d39355303d82d", + "sha256:cb1f2f5e426dc9f07a7681419fe39cee823bb74f723f36f70399123f439e9b20", + "sha256:dbbb2379c19ed6042e8f11f2a2c66d39cceb8aeace421bfc29d085d93eda3689", + "sha256:e3a057b7a64f1222b56e47bcff5e4b94c4f61faac04c7c4ecb1985e18caa3994", + "sha256:e9f45bd5b92c7974e59bcd2dcc8631a6b6cc380a904725fce7bc08872e691615" + ], + "index": "pypi", + "version": "==5.3" + }, "pyzmq": { "hashes": [ "sha256:01b588911714a6696283de3904f564c550c9e12e8b4995e173f1011755e01086", @@ -2557,14 +2541,6 @@ "index": "pypi", "version": "==3.3.11" }, - "redlock": { - "hashes": [ - "sha256:b718646239d300745475a76e81d350ec523e7146cf84d696b3c4a7dfdd5dd4d4", - "sha256:ce7e6ab404882b64a9c5017c7a78b1a3714f2c712635bcb22cbb74d20719bbd1" - ], - "index": "pypi", - "version": "==1.2.0" - }, "requests": { "hashes": [ "sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4", @@ -2613,15 +2589,19 @@ "scikit-image": { "hashes": [ "sha256:063d1c20fcd53762f82ee58c29783ae4e8f6fbed445b41b704fa33b6f355729d", + "sha256:0715b7940778ba5d73da3908d60ddf2eb93863f7c394493a522fe56d3859295c", "sha256:0808ab5f8218d91a1c008036993636535a37efd67a52ab0f2e6e3f4b7e75aeda", "sha256:2a54bea469eb1b611bee1ce36e60710f5f94f29205bc5bd67a51793909b1e62b", "sha256:2aa962aa82d815606d7dad7f045f5d7ca55c65b4320d47e15a98fc92612c2d6c", "sha256:2d346d49b6852cffb47cbde995e2696d5b07f688d8c057a0a4548abf3a98f920", "sha256:3ad2efa792ab8de5fcefe6f4f5bc1ab64c411cdb5c829ce1526ab3a5a7729627", "sha256:3af3d781ce085573ced37b2b5b9abfd32ce3d4723bd17f37e829025d189b0421", + "sha256:41e28db0136f29ecd305bef0408fdfc64be9d415e54f5099a95555c65f5c1865", "sha256:6786b127f33470fd843e644435522fbf43bce05c9f5527946c390ccb9e1cac27", "sha256:8b2b768b02c6b7476f2e16ddd91f827d3817aef73f82cf28bff7a8dcdfd8c55c", + "sha256:a48fb0d34a090b578b87ffebab0fe035295c1945dbc2b28e1a55ea2cf6031751", "sha256:dd7fbd32da74d4e9967dc15845f731f16e7966cee61f5dc0e12e2abb1305068c", + "sha256:e18d73cc8893e2268b172c29f9aab530faf8cd3b7c11ae0bee3e763d719d35c5", "sha256:e774377876cb258e8f4d63f7809863f961c98aa02263b3ff54a39483bc6f7d26" ], "index": "pypi", @@ -2629,30 +2609,30 @@ }, "scipy": { "hashes": [ - "sha256:0359576d8cc058bd615999cf985e2423dc6cc824666d60e8b8d4810569a04655", - "sha256:07673b5b96dbe28c88f3a53ca9af67f802aa853de7402e31f473b4dd6501c799", - "sha256:0f81e71149539ac09053a3f9165659367b060eceef3bbde11e6600e1c341f1f2", - "sha256:125aa82f7b3d4bd7f77fed6c3c6e31be47e33f129d829799569389ae59f913e7", - "sha256:2dc26e5b3eb86b7adad506b6b04020f6a87e1102c9acd039e937d28bdcee7fa6", - "sha256:2e4b5fdb635dd425bf46fbd6381612692d3c795f1eb6fe62410305a440691d46", - "sha256:33ac3213ee617bbc0eac84d02b130d69093ed7738afb281dfdeb12a9dbdf1530", - "sha256:34c48d922760782732d6f8f4532e320984d1280763c6787c6582021d34c8ad79", - "sha256:3f556f63e070e9596624e42e99d23b259d8f0fc63ec093bef97a9f1c579565b2", - "sha256:470d8fc76ccab6cfff60a9de4ce316a23ee7f63615d948c7446dc7c1bb45042d", - "sha256:4ad7a3ae9831d2085d6f50b81bfcd76368293eafdf31f4ac9f109c6061309c24", - "sha256:61812a7db0d9bc3f13653e52b8ddb1935cf444ec55f39160fc2778aeb2719057", - "sha256:7a0477929e6f9d5928fe81fe75d00b7da9545a49109e66028d85848b18aeef99", - "sha256:9c3221039da50f3b60da70b65d6b020ea26cefbb097116cfec696010432d1f6c", - "sha256:a03939b431994289f39373c57bbe452974a7da724ae7f9620a1beee575434da4", - "sha256:df4dbd3d40db3f667e0145dba5f50954bf28b2dd5b8b400c79d5e3fe8cb67ce2", - "sha256:e837c8068bd1929a533e9d51562faf6584ddb5303d9e218d8c11aa4719dcd617", - "sha256:ecfd45ca0ce1d6c13bef17794b4052cc9a9574f4be8d44c9bcfd7e34294bd2d7", - "sha256:ee5888c62cd83c9bf9927ffcee08434e7d5c81a8f31e5b85af5470e511022c08", - "sha256:f018892621b787b9abf76d51d1f0c21611c71752ebb1891ccf7992e0bf973708", - "sha256:f2d5db81d90d14a32d4aff920f52fca5639bcaaaf87b4f61bce83a1d238f49fc" - ], - "index": "pypi", - "version": "==1.3.2" + "sha256:00af72998a46c25bdb5824d2b729e7dabec0c765f9deb0b504f928591f5ff9d4", + "sha256:0902a620a381f101e184a958459b36d3ee50f5effd186db76e131cbefcbb96f7", + "sha256:1e3190466d669d658233e8a583b854f6386dd62d655539b77b3fa25bfb2abb70", + "sha256:2cce3f9847a1a51019e8c5b47620da93950e58ebc611f13e0d11f4980ca5fecb", + "sha256:3092857f36b690a321a662fe5496cb816a7f4eecd875e1d36793d92d3f884073", + "sha256:386086e2972ed2db17cebf88610aab7d7f6e2c0ca30042dc9a89cf18dcc363fa", + "sha256:71eb180f22c49066f25d6df16f8709f215723317cc951d99e54dc88020ea57be", + "sha256:770254a280d741dd3436919d47e35712fb081a6ff8bafc0f319382b954b77802", + "sha256:787cc50cab3020a865640aba3485e9fbd161d4d3b0d03a967df1a2881320512d", + "sha256:8a07760d5c7f3a92e440ad3aedcc98891e915ce857664282ae3c0220f3301eb6", + "sha256:8d3bc3993b8e4be7eade6dcc6fd59a412d96d3a33fa42b0fa45dc9e24495ede9", + "sha256:9508a7c628a165c2c835f2497837bf6ac80eb25291055f56c129df3c943cbaf8", + "sha256:a144811318853a23d32a07bc7fd5561ff0cac5da643d96ed94a4ffe967d89672", + "sha256:a1aae70d52d0b074d8121333bc807a485f9f1e6a69742010b33780df2e60cfe0", + "sha256:a2d6df9eb074af7f08866598e4ef068a2b310d98f87dc23bd1b90ec7bdcec802", + "sha256:bb517872058a1f087c4528e7429b4a44533a902644987e7b2fe35ecc223bc408", + "sha256:c5cac0c0387272ee0e789e94a570ac51deb01c796b37fb2aad1fb13f85e2f97d", + "sha256:cc971a82ea1170e677443108703a2ec9ff0f70752258d0e9f5433d00dda01f59", + "sha256:dba8306f6da99e37ea08c08fef6e274b5bf8567bb094d1dbe86a20e532aca088", + "sha256:dc60bb302f48acf6da8ca4444cfa17d52c63c5415302a9ee77b3b21618090521", + "sha256:dee1bbf3a6c8f73b6b218cb28eed8dd13347ea2f87d572ce19b289d6fd3fbc59" + ], + "index": "pypi", + "version": "==1.4.1" }, "seaborn": { "hashes": [ @@ -2729,19 +2709,12 @@ "index": "pypi", "version": "==1.13.0" }, - "sortedcontainers": { - "hashes": [ - "sha256:974e9a32f56b17c1bac2aebd9dcf197f3eb9cd30553c5852a3187ad162e1a03a", - "sha256:d9e96492dd51fae31e60837736b38fe42a187b5404c16606ff7ee7cd582d4c60" - ], - "version": "==2.1.0" - }, "sqlalchemy": { "hashes": [ - "sha256:afa5541e9dea8ad0014251bc9d56171ca3d8b130c9627c6cb3681cff30be3f8a" + "sha256:bfb8f464a5000b567ac1d350b9090cf081180ec1ab4aa87e7bca12dab25320ec" ], "index": "pypi", - "version": "==1.3.11" + "version": "==1.3.12" }, "subprocess32": { "hashes": [ @@ -2751,13 +2724,11 @@ "index": "pypi", "version": "==3.5.4" }, - "supervisor": { + "tabulate": { "hashes": [ - "sha256:2dc86fe0476e945e61483d614ceb2cf4f93b95282eb243bdf792621994360383", - "sha256:a76b2f77a560f2dc411c0254a4eb15f555e99faac48621b0f1fc9ab013944f47" + "sha256:5470cc6687a091c7042cee89b2946d9235fe9f6d49c193a4ae2ac7bf386737c8" ], - "index": "pypi", - "version": "==4.1.0" + "version": "==0.8.6" }, "tenacity": { "hashes": [ @@ -2769,17 +2740,16 @@ }, "tensorboard": { "hashes": [ - "sha256:203bd0c2fa33e18c009fa21253b67b67b78ef9624c4df3f70d3ef1b4f0ca3f9c", - "sha256:bf66fc182fcbfff6fc2e770754a100ef5c6bdc8601fece92375f31da60733fdc" + "sha256:32d9dec38d053d7d75796eb7c2e0d77285af35f69ee1a6796ab5ecc896679fb3", + "sha256:ccae56f01acc78a138474081b631af52017c2075ffe1c453d58c49d5046ef081" ], "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.0.1" + "version": "==2.0.2" }, "tensorflow-estimator": { "hashes": [ "sha256:aa8deab25d09a9730dfbae8ec58f4eb00ec2a90b5ca3dcbd8fa0717103d3bbb3" ], - "index": "pypi", "version": "==2.0.1" }, "tensorflow-gpu": { @@ -2816,13 +2786,6 @@ ], "version": "==0.4.4" }, - "theano": { - "hashes": [ - "sha256:35c9bbef56b61ffa299265a42a4e8f8cb5a07b2997dabaef0f8830b397086913" - ], - "index": "pypi", - "version": "==1.0.4" - }, "tornado": { "hashes": [ "sha256:349884248c36801afa19e342a77cc4458caca694b0eda633f5878e458a44cb2c", @@ -2877,41 +2840,12 @@ "index": "pypi", "version": "==1.25.7" }, - "utm": { - "hashes": [ - "sha256:07e55707ed660eec1ae983bd54a406c437962618a6261b38d70592fe30f5f508" - ], - "index": "pypi", - "version": "==0.5.0" - }, - "uwsgi": { - "hashes": [ - "sha256:4972ac538800fb2d421027f49b4a1869b66048839507ccf0aa2fda792d99f583" - ], - "index": "pypi", - "version": "==2.0.18" - }, - "v4l2": { - "hashes": [ - "sha256:0d8f31f9d554ded4d0b50a31a7be5590b861df9e1ba256ee757e1c09175dd4a2" - ], - "index": "pypi", - "version": "==0.2" - }, - "vine": { - "hashes": [ - "sha256:133ee6d7a9016f177ddeaf191c1f58421a1dcc6ee9a42c58b34bed40e1d2cd87", - "sha256:ea4947cc56d1fd6f2095c8d543ee25dad966f78692528e68b4fada11ba3f98af" - ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==1.3.0" - }, "wcwidth": { "hashes": [ - "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e", - "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c" + "sha256:8fd29383f539be45b20bd4df0dc29c20ba48654a41e661925e612311e9f3c603", + "sha256:f28b3e8a6483e5d49e7f8949ac1a78314e740333ae305b4ba5defd3e74fb37a8" ], - "version": "==0.1.7" + "version": "==0.1.8" }, "webencodings": { "hashes": [ @@ -2930,11 +2864,11 @@ }, "wheel": { "hashes": [ - "sha256:10c9da68765315ed98850f8e048347c3eb06dd81822dc2ab1d4fde9dc9702646", - "sha256:f4da1763d3becf2e2cd92a14a7c920f0f00eca30fdde9ea992c836685b9faf28" + "sha256:9515fe0a94e823fd90b08d22de45d7bde57c90edce705b22f5e1ecf7e1b653c8", + "sha256:e721e53864f084f956f40f96124a74da0631ac13fbbd1ba99e8e2b5e9cafdf64" ], "markers": "python_version >= '3'", - "version": "==0.33.6" + "version": "==0.30.0" }, "widgetsnbextension": { "hashes": [ diff --git a/README.md b/README.md index 00ae8f9691..013397a774 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ openpilot should preserve all other vehicle's stock features, including, but are Supported Hardware ------ -At the moment, openpilot supports the [EON DevKit](https://comma.ai/shop/products/eon-dashcam-devkit). A [car harness](https://comma.ai/shop/products/car-harness) is recommended to connect the EON to the car. In the future, we'd like to support other platforms as well. +At the moment, openpilot supports the [EON DevKit](https://comma.ai/shop/products/eon-dashcam-devkit) and the [comma two](https://comma.ai/shop/products/comma-two-devkit). A [car harness](https://comma.ai/shop/products/car-harness) is recommended to connect the EON or comma two to the car. In the future, we'd like to support other platforms as well, like gaming PCs. Supported Cars ------ @@ -159,6 +159,8 @@ Limitations of openpilot ALC and LDW openpilot ALC and openpilot LDW do not automatically drive the vehicle or reduce the amount of attention that must be paid to operate your vehicle. The driver must always keep control of the steering wheel and be ready to correct the openpilot ALC action at all times. +While changing lanes, openpilot is not capable of looking next to you or checking your blind spot. Only nudge the wheel to initiate a lane change after you have confirmed it's safe to do so. + Many factors can impact the performance of openpilot ALC and openpilot LDW, causing them to be unable to function as intended. These include, but are not limited to: * Poor visibility (heavy rain, snow, fog, etc.) or weather conditions that may interfere with sensor operation. diff --git a/RELEASES.md b/RELEASES.md index 2e99a28bc0..1b4caf9634 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,12 @@ +Version 0.7.1 (2020-01-20) +======================== + * comma two support! + * Lane Change Assist above 45 mph! + * Replace zmq with custom messaging library, msgq! + * Supercombo model: calibration and driving models are combined for better lead estimate + * More robust updater thanks to jyoung8607! Requires NEOS update + * Improve low speed ACC tuning + Version 0.7 (2019-12-13) ======================== * Move to SCons build system! diff --git a/SConstruct b/SConstruct index 9de2ba53a1..404cc4491f 100644 --- a/SConstruct +++ b/SConstruct @@ -46,6 +46,7 @@ else: "#phonelibs/capnp-cpp/include", "#phonelibs/capnp-c/include", "#phonelibs/zmq/x64/include", + "#external/tensorflow/include", ] libpath = [ "#phonelibs/capnp-cpp/x64/lib", @@ -55,6 +56,7 @@ else: "#phonelibs/zmq/x64/lib", "#phonelibs/libyuv/x64/lib", "#external/zmq/lib", + "#external/tensorflow/lib", "#cereal", "#selfdrive/common", "/usr/lib", @@ -62,6 +64,7 @@ else: ] rpath = ["phonelibs/capnp-cpp/x64/lib", + "external/tensorflow/lib", "cereal", "selfdrive/common"] @@ -201,11 +204,13 @@ SConscript(['selfdrive/controls/lib/longitudinal_mpc/SConscript']) SConscript(['selfdrive/boardd/SConscript']) SConscript(['selfdrive/proclogd/SConscript']) +SConscript(['selfdrive/ui/SConscript']) +SConscript(['selfdrive/loggerd/SConscript']) + if arch == "aarch64": SConscript(['selfdrive/logcatd/SConscript']) - SConscript(['selfdrive/ui/SConscript']) SConscript(['selfdrive/sensord/SConscript']) - SConscript(['selfdrive/loggerd/SConscript']) + SConscript(['selfdrive/clocksd/SConscript']) SConscript(['selfdrive/locationd/SConscript']) diff --git a/apk/ai.comma.plus.frame.apk b/apk/ai.comma.plus.frame.apk index 58f22edb3e..11ba39d194 100644 Binary files a/apk/ai.comma.plus.frame.apk and b/apk/ai.comma.plus.frame.apk differ diff --git a/apk/ai.comma.plus.offroad.apk b/apk/ai.comma.plus.offroad.apk index 7e77114ab1..2a84019cb9 100644 Binary files a/apk/ai.comma.plus.offroad.apk and b/apk/ai.comma.plus.offroad.apk differ diff --git a/cereal/.gitignore b/cereal/.gitignore index 5053090f14..e90f8c750f 100644 --- a/cereal/.gitignore +++ b/cereal/.gitignore @@ -10,5 +10,5 @@ libmessaging.* libmessaging_shared.* services.h .sconsign.dblite -libcereal_shared.so +libcereal_shared.* diff --git a/cereal/README.md b/cereal/README.md new file mode 100644 index 0000000000..ec0efc6762 --- /dev/null +++ b/cereal/README.md @@ -0,0 +1,42 @@ +What is cereal? +---- + +cereal is both a messaging spec for robotics systems as well as generic high performance IPC pub sub messaging with a single publisher and multiple subscribers. + +Imagine this use case: +* A sensor process reads gyro measurements directly from an IMU and publishes a sensorEvents packet +* A calibration process subscribes to the sensorEvents packet to use the IMU +* A localization process subscribes to the sensorEvents packet to use the IMU also + + +Messaging Spec +---- + +You'll find the message types in [log.capnp](log.capnp). It uses [Cap'n proto](https://capnproto.org/capnp-tool.html) and defines one struct called Event. + +All Events have a logMonoTime and a valid. Then a big union defines the packet type. + + +Pub Sub Backends +---- + +cereal supports two backends, one based on [zmq](https://zeromq.org/), the other called msgq, a custom pub sub based on shared memory that doesn't require the bytes to pass through the kernel. + +Example +--- +```python +import cereal.messaging as messaging + +# in subscriber +sm = messaging.SubMaster(['sensorEvents']) +while 1: + sm.update() + print(sm['sensorEvents']) + +# in publisher +pm = messaging.PubMaster(['sensorEvents']) +dat = messaging.new_message() +dat.init('sensorEvents', 1) +dat.sensorEvents[0] = {"gyro": {"v": [0.1, -0.1, 0.1]}} +pm.send('sensorEvents', dat) +``` diff --git a/cereal/SConscript b/cereal/SConscript index 789e83023a..e0c1b2b52c 100644 --- a/cereal/SConscript +++ b/cereal/SConscript @@ -29,7 +29,7 @@ cereal_objects = env.SharedObject([ ]) env.Library('cereal', cereal_objects) -env.SharedLibrary('cereal_shared', cereal_objects) +env.SharedLibrary('cereal_shared', cereal_objects, LIBS=["capnp_c"]) cereal_dir = Dir('.') services_h = env.Command( @@ -49,7 +49,7 @@ Depends('messaging/impl_zmq.cc', services_h) # note, this rebuilds the deps shared, zmq is statically linked to make APK happy # TODO: get APK to load system zmq to remove the static link -shared_lib_shared_lib = [zmq, 'm', 'stdc++'] + ["gnustl_shared"] if arch == "aarch64" else [] +shared_lib_shared_lib = [zmq, 'm', 'stdc++'] + ["gnustl_shared"] if arch == "aarch64" else [zmq] env.SharedLibrary('messaging_shared', messaging_objects, LIBS=shared_lib_shared_lib) env.Program('messaging/bridge', ['messaging/bridge.cc'], LIBS=[messaging_lib, 'zmq']) diff --git a/cereal/car.capnp b/cereal/car.capnp index 68a723206a..48618a2780 100644 --- a/cereal/car.capnp +++ b/cereal/car.capnp @@ -88,6 +88,8 @@ struct CarEvent @0x9b1657f34caf3ad3 { lowMemory @63; stockAeb @64; ldw @65; + carUnrecognized @66; + radarCommIssue @67; } } @@ -410,11 +412,11 @@ struct CarParams { enum SafetyModel { silent @0; - honda @1; + hondaNidec @1; toyota @2; elm327 @3; gm @4; - hondaBosch @5; + hondaBoschGiraffe @5; ford @6; cadillac @7; hyundai @8; @@ -428,7 +430,9 @@ struct CarParams { toyotaIpas @16; allOutput @17; gmAscm @18; - noOutput @19; # like silent but with silent CAN TXs + noOutput @19; # like silent but without silent CAN TXs + hondaBoschHarness @20; + volkswagenPq @21; } enum SteerControlType { @@ -444,7 +448,9 @@ struct CarParams { struct CarFw { ecu @0 :Ecu; - fwVersion @1 :Text; + fwVersion @1 :Data; + address @2: UInt32; + subAddress @3: UInt8; } enum Ecu { @@ -452,5 +458,11 @@ struct CarParams { esp @1; fwdRadar @2; fwdCamera @3; + engine @4; + unknown @5; + + # Toyota only + dsu @6; + apgs @7; } } diff --git a/cereal/log.capnp b/cereal/log.capnp index b059218feb..bdd7ed1bb1 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -310,6 +310,7 @@ struct HealthData { hasGps @6 :Bool; canSendErrs @7 :UInt32; canFwdErrs @8 :UInt32; + canRxErrs @19 :UInt32; gmlanSendErrs @9 :UInt32; hwType @10 :HwType; fanSpeedRpm @11 :UInt16; @@ -484,6 +485,7 @@ struct ControlsState @0x97ff69c53601abf1 { decelForTurn @47 :Bool; decelForModel @54 :Bool; + canErrorCounter @57 :UInt32; lateralControlState :union { indiState @52 :LateralINDIState; @@ -575,6 +577,7 @@ struct ModelData { leadFuture @7 :LeadData; speed @8 :List(Float32); meta @10 :MetaData; + longitudinal @11 :LongitudinalData; struct PathData { points @0 :List(Float32); @@ -605,6 +608,7 @@ struct ModelData { yuvCorrection @5 :List(Float32); inputTransform @6 :List(Float32); } + struct MetaData { engagedProb @0 :Float32; desirePrediction @1 :List(Float32); @@ -612,6 +616,11 @@ struct ModelData { gasDisengageProb @3 :Float32; steerOverrideProb @4 :Float32; } + + struct LongitudinalData { + speeds @0 :List(Float32); + accelerations @1 :List(Float32); + } } struct CalibrationFeatures { @@ -1757,6 +1766,8 @@ struct DriverMonitoring { leftBlinkProb @8 :Float32; rightBlinkProb @9 :Float32; irPwrDEPRECATED @10 :Float32; + faceOrientationStd @11 :List(Float32); + facePositionStd @12 :List(Float32); } struct Boot { diff --git a/cereal/messaging/__init__.py b/cereal/messaging/__init__.py index 7a0d4936b3..e5a004740d 100644 --- a/cereal/messaging/__init__.py +++ b/cereal/messaging/__init__.py @@ -1,6 +1,7 @@ # must be build with scons from .messaging_pyx import Context, Poller, SubSocket, PubSocket # pylint: disable=no-name-in-module, import-error from .messaging_pyx import MultiplePublishersError, MessagingError # pylint: disable=no-name-in-module, import-error +import capnp assert MultiplePublishersError assert MessagingError @@ -116,6 +117,7 @@ def recv_one_retry(sock): if dat is not None: return log.Event.from_bytes(dat) +# TODO: This does not belong in messaging def get_one_can(logcan): while True: can = recv_one_retry(logcan) @@ -147,12 +149,12 @@ class SubMaster(): self.freq[s] = service_list[s].frequency data = new_message() - if s in ['can', 'sensorEvents', 'liveTracks', 'sendCan', - 'ethernetData', 'cellInfo', 'wifiScan', - 'trafficEvents', 'orbObservation', 'carEvents']: - data.init(s, 0) - else: + try: data.init(s) + except capnp.lib.capnp.KjException: + # lists + data.init(s, 0) + self.data[s] = getattr(data, s) self.logMonoTime[s] = 0 self.valid[s] = data.valid diff --git a/cereal/messaging/bridge.cc b/cereal/messaging/bridge.cc index 7abcdd09da..8e29566ca2 100644 --- a/cereal/messaging/bridge.cc +++ b/cereal/messaging/bridge.cc @@ -4,6 +4,8 @@ #include #include +typedef void (*sighandler_t)(int sig); + #include "services.h" #include "impl_msgq.hpp" diff --git a/cereal/messaging/impl_msgq.cc b/cereal/messaging/impl_msgq.cc index bf017d900b..d37b8c986d 100644 --- a/cereal/messaging/impl_msgq.cc +++ b/cereal/messaging/impl_msgq.cc @@ -85,7 +85,6 @@ Message * MSGQSubSocket::receive(bool non_blocking){ msgq_msg_t msg; MSGQMessage *r = NULL; - r = NULL; int rc = msgq_msg_recv(&msg, q); @@ -109,17 +108,23 @@ Message * MSGQSubSocket::receive(bool non_blocking){ } } - if (rc > 0){ - r = new MSGQMessage; - r->takeOwnership(msg.data, msg.size); - } - errno = msgq_do_exit ? EINTR : 0; if (!non_blocking){ std::signal(SIGINT, prev_handler_sigint); std::signal(SIGTERM, prev_handler_sigterm); } + errno = msgq_do_exit ? EINTR : 0; + + if (rc > 0){ + if (msgq_do_exit){ + msgq_msg_close(&msg); // Free unused message on exit + } else { + r = new MSGQMessage; + r->takeOwnership(msg.data, msg.size); + } + } + return (Message*)r; } diff --git a/cereal/messaging/messaging.cc b/cereal/messaging/messaging.cc index 9b12b29849..1a9f860cd3 100644 --- a/cereal/messaging/messaging.cc +++ b/cereal/messaging/messaging.cc @@ -4,20 +4,20 @@ Context * Context::create(){ Context * c; - if (std::getenv("MSGQ")){ - c = new MSGQContext(); - } else { + if (std::getenv("ZMQ")){ c = new ZMQContext(); + } else { + c = new MSGQContext(); } return c; } SubSocket * SubSocket::create(){ SubSocket * s; - if (std::getenv("MSGQ")){ - s = new MSGQSubSocket(); - } else { + if (std::getenv("ZMQ")){ s = new ZMQSubSocket(); + } else { + s = new MSGQSubSocket(); } return s; } @@ -60,10 +60,10 @@ SubSocket * SubSocket::create(Context * context, std::string endpoint, std::stri PubSocket * PubSocket::create(){ PubSocket * s; - if (std::getenv("MSGQ")){ - s = new MSGQPubSocket(); - } else { + if (std::getenv("ZMQ")){ s = new ZMQPubSocket(); + } else { + s = new MSGQPubSocket(); } return s; } @@ -82,10 +82,10 @@ PubSocket * PubSocket::create(Context * context, std::string endpoint){ Poller * Poller::create(){ Poller * p; - if (std::getenv("MSGQ")){ - p = new MSGQPoller(); - } else { + if (std::getenv("ZMQ")){ p = new ZMQPoller(); + } else { + p = new MSGQPoller(); } return p; } diff --git a/cereal/messaging/msgq.cc b/cereal/messaging/msgq.cc index 380b9c7fe6..4ccd13df44 100644 --- a/cereal/messaging/msgq.cc +++ b/cereal/messaging/msgq.cc @@ -23,8 +23,8 @@ #include "msgq.hpp" -void sigusr1_handler(int signal) { - assert(signal == SIGUSR1); +void sigusr2_handler(int signal) { + assert(signal == SIGUSR2); } uint64_t msgq_get_uid(void){ @@ -80,7 +80,7 @@ void msgq_wait_for_subscriber(msgq_queue_t *q){ int msgq_new_queue(msgq_queue_t * q, const char * path, size_t size){ assert(size < 0xFFFFFFFF); // Buffer must be smaller than 2^32 bytes - std::signal(SIGUSR1, sigusr1_handler); + std::signal(SIGUSR2, sigusr2_handler); const char * prefix = "/dev/shm/"; char * full_path = new char[strlen(path) + strlen(prefix) + 1]; @@ -136,7 +136,7 @@ void msgq_close_queue(msgq_queue_t *q){ void msgq_init_publisher(msgq_queue_t * q) { - std::cout << "Starting publisher" << std::endl; + //std::cout << "Starting publisher" << std::endl; uint64_t uid = msgq_get_uid(); *q->write_uid = uid; @@ -150,6 +150,15 @@ void msgq_init_publisher(msgq_queue_t * q) { q->write_uid_local = uid; } +static void thread_signal(uint32_t tid) { + #ifndef SYS_tkill + // TODO: this won't work for multithreaded programs + kill(tid, SIGUSR2); + #else + syscall(SYS_tkill, tid, SIGUSR2); + #endif +} + void msgq_init_subscriber(msgq_queue_t * q) { assert(q != NULL); assert(q->num_readers != NULL); @@ -173,7 +182,7 @@ void msgq_init_subscriber(msgq_queue_t * q) { *q->read_uids[i] = 0; // Wake up reader in case they are in a poll - syscall(SYS_tkill, old_uid & 0xFFFFFFFF, SIGUSR1); + thread_signal(old_uid & 0xFFFFFFFF); } continue; @@ -196,7 +205,7 @@ void msgq_init_subscriber(msgq_queue_t * q) { } } - std::cout << "New subscriber id: " << q->reader_id << " uid: " << q->read_uid_local << " " << q->endpoint << std::endl; + //std::cout << "New subscriber id: " << q->reader_id << " uid: " << q->read_uid_local << " " << q->endpoint << std::endl; msgq_reset_reader(q); } @@ -278,8 +287,7 @@ int msgq_msg_send(msgq_msg_t * msg, msgq_queue_t *q){ // Notify readers for (uint64_t i = 0; i < num_readers; i++){ uint64_t reader_uid = *q->read_uids[i]; - - syscall(SYS_tkill, reader_uid & 0xFFFFFFFF, SIGUSR1); + thread_signal(reader_uid & 0xFFFFFFFF); } return msg->size; diff --git a/cereal/service_list.yaml b/cereal/service_list.yaml index 884bfe9a5b..e551dac59f 100644 --- a/cereal/service_list.yaml +++ b/cereal/service_list.yaml @@ -25,7 +25,7 @@ encodeIdx: [8015, true, 20.] liveTracks: [8016, true, 20.] sendcan: [8017, true, 100.] logMessage: [8018, true, 0.] -liveCalibration: [8019, true, 5.] +liveCalibration: [8019, true, 4., 4] androidLog: [8020, true, 0.] carState: [8021, true, 100., 10] # 8022 is reserved for sshd @@ -68,7 +68,7 @@ orbFeaturesSummary: [8062, true, 0.] driverMonitoring: [8063, true, 5., 1] liveParameters: [8064, true, 10.] liveMapData: [8065, true, 0.] -cameraOdometry: [8066, true, 5.] +cameraOdometry: [8066, true, 20.] pathPlan: [8067, true, 20.] kalmanOdometry: [8068, true, 0.] thumbnail: [8069, true, 0.2, 1] diff --git a/common/android.py b/common/android.py index eda82385a8..e88080884c 100644 --- a/common/android.py +++ b/common/android.py @@ -1,20 +1,32 @@ +import os import binascii import itertools import re import struct import subprocess +ANDROID = os.path.isfile('/EON') + def getprop(key): + if not ANDROID: + return "" return subprocess.check_output(["getprop", key], encoding='utf8').strip() -def get_imei(): - ret = getprop("oem.device.imeicache") - if ret == "": +def get_imei(slot): + slot = str(slot) + if slot not in ("0", "1"): + raise ValueError("SIM slot must be 0 or 1") + + ret = parse_service_call_string(["iphonesubinfo", "3" ,"i32", str(slot)]) + if not ret: ret = "000000000000000" return ret def get_serial(): - return getprop("ro.serialno") + ret = getprop("ro.serialno") + if ret == "": + ret = "cccccccc" + return ret def get_subscriber_info(): ret = parse_service_call_string(["iphonesubinfo", "7"]) @@ -60,6 +72,8 @@ def parse_service_call_string(call): return None def parse_service_call_bytes(call): + if not ANDROID: + return None ret = subprocess.check_output(["service", "call", *call], encoding='utf8').strip() if 'Parcel' not in ret: return None diff --git a/common/logging_extra.py b/common/logging_extra.py index 43ae48882b..d573327806 100644 --- a/common/logging_extra.py +++ b/common/logging_extra.py @@ -78,28 +78,6 @@ class SwagLogger(logging.Logger): self.log_local = local() self.log_local.ctx = {} - def findCaller(self, stack_info=None): - """ - Find the stack frame of the caller so that we can note the source - file name, line number and function name. - """ - # f = currentframe() - f = sys._getframe(3) - #On some versions of IronPython, currentframe() returns None if - #IronPython isn't run with -X:Frames. - if f is not None: - f = f.f_back - rv = "(unknown file)", 0, "(unknown function)" - while hasattr(f, "f_code"): - co = f.f_code - filename = os.path.normcase(co.co_filename) - if filename in (logging._srcfile, _srcfile): - f = f.f_back - continue - rv = (co.co_filename, f.f_lineno, co.co_name) - break - return rv - def local_ctx(self): try: return self.log_local.ctx diff --git a/common/params.py b/common/params.py index 5067aa8d42..3a4e4a2a16 100755 --- a/common/params.py +++ b/common/params.py @@ -69,9 +69,10 @@ keys = { "IsLdwEnabled": [TxType.PERSISTENT], "IsGeofenceEnabled": [TxType.PERSISTENT], "IsMetric": [TxType.PERSISTENT], + "IsOffroad": [TxType.CLEAR_ON_MANAGER_START], "IsRHD": [TxType.PERSISTENT], "IsTakingSnapshot": [TxType.CLEAR_ON_MANAGER_START], - "IsUpdateAvailable": [TxType.PERSISTENT], + "IsUpdateAvailable": [TxType.CLEAR_ON_MANAGER_START], "IsUploadRawEnabled": [TxType.PERSISTENT], "LastUpdateTime": [TxType.PERSISTENT], "LimitSetSpeed": [TxType.PERSISTENT], @@ -80,6 +81,7 @@ keys = { "LongitudinalControl": [TxType.PERSISTENT], "OpenpilotEnabledToggle": [TxType.PERSISTENT], "PandaFirmware": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], + "PandaFirmwareHex": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], "PandaDongleId": [TxType.CLEAR_ON_MANAGER_START, TxType.CLEAR_ON_PANDA_DISCONNECT], "Passive": [TxType.PERSISTENT], "RecordFront": [TxType.PERSISTENT], diff --git a/common/spinner.py b/common/spinner.py index 734015bcf0..3582d3feed 100644 --- a/common/spinner.py +++ b/common/spinner.py @@ -5,21 +5,31 @@ from common.basedir import BASEDIR class Spinner(): def __init__(self): - self.spinner_proc = subprocess.Popen(["./spinner"], - stdin=subprocess.PIPE, - cwd=os.path.join(BASEDIR, "selfdrive", "ui", "spinner"), - close_fds=True) + try: + self.spinner_proc = subprocess.Popen(["./spinner"], + stdin=subprocess.PIPE, + cwd=os.path.join(BASEDIR, "selfdrive", "ui", "spinner"), + close_fds=True) + except OSError: + self.spinner_proc = None def __enter__(self): return self def update(self, spinner_text): - self.spinner_proc.stdin.write(spinner_text.encode('utf8') + b"\n") - self.spinner_proc.stdin.flush() + if self.spinner_proc is not None: + self.spinner_proc.stdin.write(spinner_text.encode('utf8') + b"\n") + try: + self.spinner_proc.stdin.flush() + except BrokenPipeError: + pass def close(self): if self.spinner_proc is not None: - self.spinner_proc.stdin.close() + try: + self.spinner_proc.stdin.close() + except BrokenPipeError: + pass self.spinner_proc.terminate() self.spinner_proc = None diff --git a/common/transformations/camera.py b/common/transformations/camera.py index 960c063f94..489874eb6e 100644 --- a/common/transformations/camera.py +++ b/common/transformations/camera.py @@ -44,6 +44,7 @@ def get_calib_from_vp(vp): roll_calib = 0 return roll_calib, pitch_calib, yaw_calib + # aka 'extrinsic_matrix' # road : x->forward, y -> left, z->up def get_view_frame_from_road_frame(roll, pitch, yaw, height): @@ -61,6 +62,13 @@ def vp_from_ke(m): """ return (m[0, 0]/m[2,0], m[1,0]/m[2,0]) + +def vp_from_rpy(rpy): + e = get_view_frame_from_road_frame(rpy[0], rpy[1], rpy[2], 1.22) + ke = np.dot(eon_intrinsics, e) + return vp_from_ke(ke) + + def roll_from_ke(m): # note: different from calibration.h/RollAnglefromKE: i think that one's just wrong return np.arctan2(-(m[1, 0] - m[1, 1] * m[2, 0] / m[2, 1]), diff --git a/installer/updater/update.json b/installer/updater/update.json index fb009b4c1c..6e2692bfad 100644 --- a/installer/updater/update.json +++ b/installer/updater/update.json @@ -1,7 +1,7 @@ { - "ota_url": "https://commadist.azureedge.net/neosupdate/ota-signed-07df505453684371b6c22583ffbb74ee414fcd389a46ff369ffd1b6bac75414e.zip", - "ota_hash": "07df505453684371b6c22583ffbb74ee414fcd389a46ff369ffd1b6bac75414e", - "recovery_url": "https://commadist.azureedge.net/neosupdate/recovery-3a6f973295ded6e4ff5cfff3b12e19c80d3bf45e2e8dd8699da3fc25b23ed7c6.img", - "recovery_len": 15848748, - "recovery_hash": "3a6f973295ded6e4ff5cfff3b12e19c80d3bf45e2e8dd8699da3fc25b23ed7c6" + "ota_url": "https://commadist.azureedge.net/neosupdate/ota-signed-efdf7de63b1aef63d68301e6175930991bf9a5927d16ec6fcc69287e2ee7ca4a.zip", + "ota_hash": "efdf7de63b1aef63d68301e6175930991bf9a5927d16ec6fcc69287e2ee7ca4a", + "recovery_url": "https://commadist.azureedge.net/neosupdate/recovery-97c27e6ed04ed6bb0608b845a2d4100912093f9380c3f2ba6b56bccd608e5f6e.img", + "recovery_len": 15861036, + "recovery_hash": "97c27e6ed04ed6bb0608b845a2d4100912093f9380c3f2ba6b56bccd608e5f6e" } diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index 5e2389fe37..a33deaafd6 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -6,20 +6,53 @@ export NUMEXPR_NUM_THREADS=1 export OPENBLAS_NUM_THREADS=1 export VECLIB_MAXIMUM_THREADS=1 +if [ -z "$BASEDIR" ]; then + BASEDIR="/data/openpilot" +fi + if [ -z "$PASSIVE" ]; then export PASSIVE="1" fi +STAGING_ROOT="/data/safe_staging" + function launch { # Wifi scan wpa_cli IFNAME=wlan0 SCAN - # apply update - if [ "$(git rev-parse HEAD)" != "$(git rev-parse @{u})" ]; then - git reset --hard @{u} && - git clean -xdf && + # Check to see if there's a valid overlay-based update available. Conditions + # are as follows: + # + # 1. The BASEDIR init file has to exist, with a newer modtime than anything in + # the BASEDIR Git repo. This checks for local development work or the user + # switching branches/forks, which should not be overwritten. + # 2. The FINALIZED consistent file has to exist, indicating there's an update + # that completed successfully and synced to disk. + + if [ -f "${BASEDIR}/.overlay_init" ]; then + find ${BASEDIR}/.git -newer ${BASEDIR}/.overlay_init | grep -q '.' 2> /dev/null + if [ $? -eq 0 ]; then + echo "${BASEDIR} has been modified, skipping overlay update installation" + else + if [ -f "${STAGING_ROOT}/finalized/.overlay_consistent" ]; then + if [ ! -d /data/safe_staging/old_openpilot ]; then + echo "Valid overlay update found, installing" + LAUNCHER_LOCATION="${BASH_SOURCE[0]}" - exec "${BASH_SOURCE[0]}" + mv $BASEDIR /data/safe_staging/old_openpilot + mv "${STAGING_ROOT}/finalized" $BASEDIR + + # The mv changed our working directory to /data/safe_staging/old_openpilot + cd "${BASEDIR}" + + echo "Restarting launch script ${LAUNCHER_LOCATION}" + exec "${LAUNCHER_LOCATION}" + else + echo "openpilot backup found, not updating" + # TODO: restore backup? This means the updater didn't start after swapping + fi + fi + fi fi # no cpu rationing for now @@ -32,17 +65,17 @@ function launch { DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )" # Remove old NEOS update file + # TODO: move this code to the updater if [ -d /data/neoupdate ]; then rm -rf /data/neoupdate fi # Check for NEOS update - if [ $(< /VERSION) != "13" ]; then + if [ $(< /VERSION) != "14" ]; then if [ -f "$DIR/scripts/continue.sh" ]; then cp "$DIR/scripts/continue.sh" "/data/data/com.termux/files/continue.sh" fi - git clean -xdf "$DIR/installer/updater/updater" "file://$DIR/installer/updater/update.json" fi diff --git a/models/driving_model.dlc b/models/driving_model.dlc deleted file mode 100644 index 2ff6435ed2..0000000000 Binary files a/models/driving_model.dlc and /dev/null differ diff --git a/models/monitoring_model_q.dlc b/models/monitoring_model_q.dlc index 74a4337a9a..59104e18e8 100644 Binary files a/models/monitoring_model_q.dlc and b/models/monitoring_model_q.dlc differ diff --git a/models/posenet.dlc b/models/posenet.dlc deleted file mode 100644 index 58dee250f7..0000000000 Binary files a/models/posenet.dlc and /dev/null differ diff --git a/models/supercombo.dlc b/models/supercombo.dlc new file mode 100644 index 0000000000..fb48eb2ecb Binary files /dev/null and b/models/supercombo.dlc differ diff --git a/opendbc/.gitignore b/opendbc/.gitignore index 5eb52dcca3..9e48c6745a 100644 --- a/opendbc/.gitignore +++ b/opendbc/.gitignore @@ -1,6 +1,7 @@ *.pyc *.os *.tmp +*.dylib .*.swp can/*.so can/build/ diff --git a/opendbc/acura_ilx_2016_can_generated.dbc b/opendbc/acura_ilx_2016_can_generated.dbc index 235383eb2d..b1e2b2cb85 100644 --- a/opendbc/acura_ilx_2016_can_generated.dbc +++ b/opendbc/acura_ilx_2016_can_generated.dbc @@ -86,6 +86,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 432 STANDSTILL: 7 VSA SG_ CONTROLLED_STANDSTILL : 0|1@0+ (1,0) [0|1] "" EON SG_ WHEELS_MOVING : 12|1@0+ (1,0) [0|1] "" EON @@ -274,9 +281,10 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" EON diff --git a/opendbc/acura_rdx_2018_can_generated.dbc b/opendbc/acura_rdx_2018_can_generated.dbc index 56f4201a14..1a87ebc550 100644 --- a/opendbc/acura_rdx_2018_can_generated.dbc +++ b/opendbc/acura_rdx_2018_can_generated.dbc @@ -86,6 +86,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 432 STANDSTILL: 7 VSA SG_ CONTROLLED_STANDSTILL : 0|1@0+ (1,0) [0|1] "" EON SG_ WHEELS_MOVING : 12|1@0+ (1,0) [0|1] "" EON @@ -262,7 +269,7 @@ BO_ 392 GEARBOX: 6 XXX BO_ 399 STEER_STATUS: 6 EPS SG_ STEER_TORQUE_SENSOR : 7|12@0- (-1,0) [-2047.5|2047.5] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 35|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 36|1@0+ (1,0) [0|1] "" EON SG_ COUNTER : 45|2@0+ (1,0) [0|3] "" EON diff --git a/opendbc/azure-pipelines.yml b/opendbc/azure-pipelines.yml index 3841610a6a..6ac0f9ddd5 100644 --- a/opendbc/azure-pipelines.yml +++ b/opendbc/azure-pipelines.yml @@ -14,3 +14,6 @@ steps: docker run opendbc bash -c "cd opendbc/can/tests/linter_python; PYTHONPATH=/ ./flake8_opendbc.sh" docker run opendbc bash -c "cd opendbc/can/tests/linter_python; PYTHONPATH=/ ./pylint_opendbc.sh" displayName: 'Python linter' +- script: | + docker run opendbc bash -c "cd opendbc/can/tests/; PYTHONPATH=/ ./test_generator.sh" + displayName: 'Generator test' diff --git a/opendbc/can/packer_pyx_setup.py b/opendbc/can/packer_pyx_setup.py index 6f7a47d0ae..48d1c260a9 100644 --- a/opendbc/can/packer_pyx_setup.py +++ b/opendbc/can/packer_pyx_setup.py @@ -1,6 +1,7 @@ import os import sysconfig import subprocess +import platform from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module from Cython.Build import cythonize @@ -38,6 +39,10 @@ ARCH = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() # pyl if ARCH == "aarch64": extra_compile_args += ["-Wno-deprecated-register"] +if platform.system() == "Darwin": + libdbc = "libdbc.dylib" +else: + libdbc = "libdbc.so" setup(name='CAN packer', cmdclass={'build_ext': BuildExtWithoutPlatformSuffix}, @@ -52,9 +57,13 @@ setup(name='CAN packer', os.path.join(BASEDIR, 'phonelibs', 'capnp-cpp/include'), ], extra_link_args=[ - os.path.join(BASEDIR, 'opendbc', 'can', 'libdbc.so'), + os.path.join(BASEDIR, 'opendbc', 'can', libdbc), ], ) ), nthreads=4, ) + +if platform.system() == "Darwin": + os.system("install_name_tool -change opendbc/can/libdbc.dylib "+BASEDIR+"/opendbc/can/libdbc.dylib packer_pyx.so") + diff --git a/opendbc/can/parser_pyx_setup.py b/opendbc/can/parser_pyx_setup.py index 8ce6e7e7b4..5662530d7d 100644 --- a/opendbc/can/parser_pyx_setup.py +++ b/opendbc/can/parser_pyx_setup.py @@ -1,6 +1,7 @@ import os import subprocess import sysconfig +import platform from distutils.core import Extension, setup # pylint: disable=import-error,no-name-in-module from Cython.Build import cythonize @@ -38,6 +39,11 @@ ARCH = subprocess.check_output(["uname", "-m"], encoding='utf8').rstrip() # pyl if ARCH == "aarch64": extra_compile_args += ["-Wno-deprecated-register"] +if platform.system() == "Darwin": + libdbc = "libdbc.dylib" +else: + libdbc = "libdbc.so" + setup(name='CAN parser', cmdclass={'build_ext': BuildExtWithoutPlatformSuffix}, ext_modules=cythonize( @@ -51,9 +57,13 @@ setup(name='CAN parser', os.path.join(BASEDIR, 'phonelibs', 'capnp-cpp/include'), ], extra_link_args=[ - os.path.join(BASEDIR, 'opendbc', 'can', 'libdbc.so'), + os.path.join(BASEDIR, 'opendbc', 'can', libdbc), ], ) ), nthreads=4, ) + +if platform.system() == "Darwin": + os.system("install_name_tool -change opendbc/can/libdbc.dylib "+BASEDIR+"/opendbc/can/libdbc.dylib parser_pyx.so") + diff --git a/opendbc/can/tests/test_generator.sh b/opendbc/can/tests/test_generator.sh new file mode 100755 index 0000000000..c4df547dca --- /dev/null +++ b/opendbc/can/tests/test_generator.sh @@ -0,0 +1,13 @@ +#!/bin/bash -e + +cd ../../generator/ + +# run generator +./generator.py + +if [ -n "$(git status --untracked-files=no --porcelain)" ]; then + echo "Unexpected changes after running generator.py"; + exit 1 +else + echo "Success"; +fi diff --git a/opendbc/generator/honda/_bosch_2018.dbc b/opendbc/generator/honda/_bosch_2018.dbc index 19585529f0..488eed4241 100644 --- a/opendbc/generator/honda/_bosch_2018.dbc +++ b/opendbc/generator/honda/_bosch_2018.dbc @@ -64,7 +64,9 @@ BO_ 304 GAS_PEDAL_2: 8 PCM BO_ 330 STEERING_SENSORS: 8 EPS SG_ STEER_ANGLE : 7|16@0- (-0.1,0) [-500|500] "deg" EON SG_ STEER_ANGLE_RATE : 23|16@0- (-1,0) [-3000|3000] "deg/s" EON - SG_ STEER_ANGLE_OFFSET : 39|8@0- (-0.1,0) [-128|127] "deg" EON + SG_ STEER_SENSOR_STATUS_1 : 34|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_2 : 33|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_3 : 32|1@0+ (1,0) [0|1] "" EON SG_ STEER_WHEEL_ANGLE : 47|16@0- (-0.1,0) [-500|500] "deg" EON SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON @@ -92,9 +94,10 @@ BO_ 380 POWERTRAIN_DATA: 8 PCM BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|15] "" EON @@ -106,6 +109,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 450 EPB_STATUS: 8 EPB SG_ EPB_ACTIVE : 3|1@0+ (1,0) [0|1] "" EON SG_ EPB_STATE : 29|2@0+ (1,0) [0|3] "" EON diff --git a/opendbc/generator/honda/_honda_2017.dbc b/opendbc/generator/honda/_honda_2017.dbc index d805d45e87..de78403179 100644 --- a/opendbc/generator/honda/_honda_2017.dbc +++ b/opendbc/generator/honda/_honda_2017.dbc @@ -64,6 +64,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 432 STANDSTILL: 7 VSA SG_ CONTROLLED_STANDSTILL : 0|1@0+ (1,0) [0|1] "" EON SG_ WHEELS_MOVING : 12|1@0+ (1,0) [0|1] "" EON @@ -142,7 +149,7 @@ BO_ 780 ACC_HUD: 8 ADAS SG_ BOH : 38|1@0+ (1,0) [0|1] "" BDY SG_ ACC_PROBLEM : 37|1@0+ (1,0) [0|1] "" BDY SG_ FCM_OFF : 36|1@0+ (1,0) [0|1] "" BDY - SG_ BOH_2 : 35|1@0+ (1,0) [0|1] "" BDY + SG_ FCM_OFF_2 : 35|1@0+ (1,0) [0|1] "" BDY SG_ FCM_PROBLEM : 34|1@0+ (1,0) [0|1] "" BDY SG_ RADAR_OBSTRUCTED : 33|1@0+ (1,0) [0|1] "" BDY SG_ ENABLE_MINI_CAR : 32|1@0+ (1,0) [0|1] "" BDY @@ -152,10 +159,12 @@ BO_ 780 ACC_HUD: 8 ADAS SG_ BOH_4 : 42|1@0+ (1,0) [0|3] "" BDY SG_ BOH_5 : 41|1@0+ (1,0) [0|3] "" BDY SG_ CRUISE_CONTROL_LABEL : 40|1@0+ (1,0) [0|3] "" BDY - SG_ HUD_DISTANCE_3 : 52|1@0+ (1,0) [0|1] "" BDY - SG_ IMPERIAL_UNIT : 54|1@0+ (1,0) [0|1] "" BDY SG_ SET_ME_X01_2 : 55|1@0+ (1,0) [0|1] "" BDY + SG_ IMPERIAL_UNIT : 54|1@0+ (1,0) [0|1] "" BDY + SG_ HUD_DISTANCE_3 : 52|1@0+ (1,0) [0|1] "" BDY + SG_ CHIME : 51|3@0+ (1,0) [0|1] "" BDY SG_ SET_ME_X01 : 48|1@0+ (1,0) [0|1] "" BDY + SG_ ICONS : 63|2@0+ (1,0) [0|1] "" BDY SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" BDY SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" BDY diff --git a/opendbc/generator/honda/acura_ilx_2016_can.dbc b/opendbc/generator/honda/acura_ilx_2016_can.dbc index df77448204..2d3c1a9d2e 100644 --- a/opendbc/generator/honda/acura_ilx_2016_can.dbc +++ b/opendbc/generator/honda/acura_ilx_2016_can.dbc @@ -27,9 +27,10 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" EON diff --git a/opendbc/generator/honda/acura_rdx_2018_can.dbc b/opendbc/generator/honda/acura_rdx_2018_can.dbc index 2fccfd1b2e..01d9d64383 100644 --- a/opendbc/generator/honda/acura_rdx_2018_can.dbc +++ b/opendbc/generator/honda/acura_rdx_2018_can.dbc @@ -15,7 +15,7 @@ BO_ 392 GEARBOX: 6 XXX BO_ 399 STEER_STATUS: 6 EPS SG_ STEER_TORQUE_SENSOR : 7|12@0- (-1,0) [-2047.5|2047.5] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 35|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 36|1@0+ (1,0) [0|1] "" EON SG_ COUNTER : 45|2@0+ (1,0) [0|3] "" EON diff --git a/opendbc/generator/honda/honda_civic_touring_2016_can.dbc b/opendbc/generator/honda/honda_civic_touring_2016_can.dbc index 2cce31609d..da4f59bdaa 100644 --- a/opendbc/generator/honda/honda_civic_touring_2016_can.dbc +++ b/opendbc/generator/honda/honda_civic_touring_2016_can.dbc @@ -25,16 +25,19 @@ BO_ 304 GAS_PEDAL_2: 8 PCM BO_ 330 STEERING_SENSORS: 8 EPS SG_ STEER_ANGLE : 7|16@0- (-0.1,0) [-500|500] "deg" EON SG_ STEER_ANGLE_RATE : 23|16@0- (-1,0) [-3000|3000] "deg/s" EON - SG_ STEER_ANGLE_OFFSET : 39|8@0- (-0.1,0) [-128|127] "deg" EON + SG_ STEER_SENSOR_STATUS_1 : 34|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_2 : 33|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_3 : 32|1@0+ (1,0) [0|1] "" EON SG_ STEER_WHEEL_ANGLE : 47|16@0- (-0.1,0) [-500|500] "deg" EON SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" EON BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" EON diff --git a/opendbc/generator/honda/honda_crv_touring_2016_can.dbc b/opendbc/generator/honda/honda_crv_touring_2016_can.dbc index b41171d434..6d113fafdc 100644 --- a/opendbc/generator/honda/honda_crv_touring_2016_can.dbc +++ b/opendbc/generator/honda/honda_crv_touring_2016_can.dbc @@ -9,7 +9,7 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 6 EPS SG_ STEER_TORQUE_SENSOR : 7|12@0- (-1,0) [-2047.5|2047.5] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_CONTROL_ACTIVE : 36|1@0+ (1,0) [0|1] "" EON SG_ STEER_STATUS : 35|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 45|2@0+ (1,0) [0|3] "" EON diff --git a/opendbc/generator/honda/honda_fit_ex_2018_can.dbc b/opendbc/generator/honda/honda_fit_ex_2018_can.dbc index 9c2bf64b5a..ed64c1feeb 100644 --- a/opendbc/generator/honda/honda_fit_ex_2018_can.dbc +++ b/opendbc/generator/honda/honda_fit_ex_2018_can.dbc @@ -27,9 +27,10 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" EON diff --git a/opendbc/generator/honda/honda_fit_hybrid_2018_can.dbc b/opendbc/generator/honda/honda_fit_hybrid_2018_can.dbc index 4ad9f2a062..4ceda6aefa 100644 --- a/opendbc/generator/honda/honda_fit_hybrid_2018_can.dbc +++ b/opendbc/generator/honda/honda_fit_hybrid_2018_can.dbc @@ -27,9 +27,10 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" EON diff --git a/opendbc/generator/honda/honda_odyssey_exl_2018.dbc b/opendbc/generator/honda/honda_odyssey_exl_2018.dbc index 8f04548910..64cff2e01f 100644 --- a/opendbc/generator/honda/honda_odyssey_exl_2018.dbc +++ b/opendbc/generator/honda/honda_odyssey_exl_2018.dbc @@ -19,9 +19,10 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" EON diff --git a/opendbc/generator/honda/honda_odyssey_extreme_edition_2018_china_can.dbc b/opendbc/generator/honda/honda_odyssey_extreme_edition_2018_china_can.dbc index 7927f8c80f..3ffe59a118 100644 --- a/opendbc/generator/honda/honda_odyssey_extreme_edition_2018_china_can.dbc +++ b/opendbc/generator/honda/honda_odyssey_extreme_edition_2018_china_can.dbc @@ -12,11 +12,12 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-2985|2985] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ CHECKSUM : 51|4@0+ (1,0) [0|15] "" EON - SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 43|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON + SG_ CHECKSUM : 51|4@0+ (1,0) [0|15] "" EON + SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON BO_ 401 GEARBOX: 8 PCM SG_ GEAR_SHIFTER : 5|6@0+ (1,0) [0|63] "" EON diff --git a/opendbc/generator/honda/honda_pilot_touring_2017_can.dbc b/opendbc/generator/honda/honda_pilot_touring_2017_can.dbc index ea9ec39644..1da2248b60 100644 --- a/opendbc/generator/honda/honda_pilot_touring_2017_can.dbc +++ b/opendbc/generator/honda/honda_pilot_touring_2017_can.dbc @@ -27,9 +27,10 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" EON diff --git a/opendbc/generator/honda/honda_ridgeline_black_edition_2017_can.dbc b/opendbc/generator/honda/honda_ridgeline_black_edition_2017_can.dbc index cec7a08e7d..adc23d6879 100644 --- a/opendbc/generator/honda/honda_ridgeline_black_edition_2017_can.dbc +++ b/opendbc/generator/honda/honda_ridgeline_black_edition_2017_can.dbc @@ -22,9 +22,10 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" EON diff --git a/opendbc/honda_accord_lx15t_2018_can_generated.dbc b/opendbc/honda_accord_lx15t_2018_can_generated.dbc index 0cf9ea5662..48c571df1f 100644 --- a/opendbc/honda_accord_lx15t_2018_can_generated.dbc +++ b/opendbc/honda_accord_lx15t_2018_can_generated.dbc @@ -68,7 +68,9 @@ BO_ 304 GAS_PEDAL_2: 8 PCM BO_ 330 STEERING_SENSORS: 8 EPS SG_ STEER_ANGLE : 7|16@0- (-0.1,0) [-500|500] "deg" EON SG_ STEER_ANGLE_RATE : 23|16@0- (-1,0) [-3000|3000] "deg/s" EON - SG_ STEER_ANGLE_OFFSET : 39|8@0- (-0.1,0) [-128|127] "deg" EON + SG_ STEER_SENSOR_STATUS_1 : 34|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_2 : 33|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_3 : 32|1@0+ (1,0) [0|1] "" EON SG_ STEER_WHEEL_ANGLE : 47|16@0- (-0.1,0) [-500|500] "deg" EON SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON @@ -96,9 +98,10 @@ BO_ 380 POWERTRAIN_DATA: 8 PCM BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|15] "" EON @@ -110,6 +113,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 450 EPB_STATUS: 8 EPB SG_ EPB_ACTIVE : 3|1@0+ (1,0) [0|1] "" EON SG_ EPB_STATE : 29|2@0+ (1,0) [0|3] "" EON diff --git a/opendbc/honda_accord_s2t_2018_can_generated.dbc b/opendbc/honda_accord_s2t_2018_can_generated.dbc index 770cfdf1fd..b160dff853 100644 --- a/opendbc/honda_accord_s2t_2018_can_generated.dbc +++ b/opendbc/honda_accord_s2t_2018_can_generated.dbc @@ -68,7 +68,9 @@ BO_ 304 GAS_PEDAL_2: 8 PCM BO_ 330 STEERING_SENSORS: 8 EPS SG_ STEER_ANGLE : 7|16@0- (-0.1,0) [-500|500] "deg" EON SG_ STEER_ANGLE_RATE : 23|16@0- (-1,0) [-3000|3000] "deg/s" EON - SG_ STEER_ANGLE_OFFSET : 39|8@0- (-0.1,0) [-128|127] "deg" EON + SG_ STEER_SENSOR_STATUS_1 : 34|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_2 : 33|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_3 : 32|1@0+ (1,0) [0|1] "" EON SG_ STEER_WHEEL_ANGLE : 47|16@0- (-0.1,0) [-500|500] "deg" EON SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON @@ -96,9 +98,10 @@ BO_ 380 POWERTRAIN_DATA: 8 PCM BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|15] "" EON @@ -110,6 +113,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 450 EPB_STATUS: 8 EPB SG_ EPB_ACTIVE : 3|1@0+ (1,0) [0|1] "" EON SG_ EPB_STATE : 29|2@0+ (1,0) [0|3] "" EON diff --git a/opendbc/honda_civic_hatchback_ex_2017_can_generated.dbc b/opendbc/honda_civic_hatchback_ex_2017_can_generated.dbc index 06c6edabdf..d6c9505d94 100644 --- a/opendbc/honda_civic_hatchback_ex_2017_can_generated.dbc +++ b/opendbc/honda_civic_hatchback_ex_2017_can_generated.dbc @@ -68,7 +68,9 @@ BO_ 304 GAS_PEDAL_2: 8 PCM BO_ 330 STEERING_SENSORS: 8 EPS SG_ STEER_ANGLE : 7|16@0- (-0.1,0) [-500|500] "deg" EON SG_ STEER_ANGLE_RATE : 23|16@0- (-1,0) [-3000|3000] "deg/s" EON - SG_ STEER_ANGLE_OFFSET : 39|8@0- (-0.1,0) [-128|127] "deg" EON + SG_ STEER_SENSOR_STATUS_1 : 34|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_2 : 33|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_3 : 32|1@0+ (1,0) [0|1] "" EON SG_ STEER_WHEEL_ANGLE : 47|16@0- (-0.1,0) [-500|500] "deg" EON SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON @@ -96,9 +98,10 @@ BO_ 380 POWERTRAIN_DATA: 8 PCM BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|15] "" EON @@ -110,6 +113,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 450 EPB_STATUS: 8 EPB SG_ EPB_ACTIVE : 3|1@0+ (1,0) [0|1] "" EON SG_ EPB_STATE : 29|2@0+ (1,0) [0|3] "" EON diff --git a/opendbc/honda_civic_touring_2016_can_generated.dbc b/opendbc/honda_civic_touring_2016_can_generated.dbc index cb83511b3d..26173859b4 100644 --- a/opendbc/honda_civic_touring_2016_can_generated.dbc +++ b/opendbc/honda_civic_touring_2016_can_generated.dbc @@ -86,6 +86,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 432 STANDSTILL: 7 VSA SG_ CONTROLLED_STANDSTILL : 0|1@0+ (1,0) [0|1] "" EON SG_ WHEELS_MOVING : 12|1@0+ (1,0) [0|1] "" EON @@ -272,16 +279,19 @@ BO_ 304 GAS_PEDAL_2: 8 PCM BO_ 330 STEERING_SENSORS: 8 EPS SG_ STEER_ANGLE : 7|16@0- (-0.1,0) [-500|500] "deg" EON SG_ STEER_ANGLE_RATE : 23|16@0- (-1,0) [-3000|3000] "deg/s" EON - SG_ STEER_ANGLE_OFFSET : 39|8@0- (-0.1,0) [-128|127] "deg" EON + SG_ STEER_SENSOR_STATUS_1 : 34|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_2 : 33|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_3 : 32|1@0+ (1,0) [0|1] "" EON SG_ STEER_WHEEL_ANGLE : 47|16@0- (-0.1,0) [-500|500] "deg" EON SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|3] "" EON BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" EON diff --git a/opendbc/honda_crv_ex_2017_can_generated.dbc b/opendbc/honda_crv_ex_2017_can_generated.dbc index 7aa93a9635..db11aa3a71 100644 --- a/opendbc/honda_crv_ex_2017_can_generated.dbc +++ b/opendbc/honda_crv_ex_2017_can_generated.dbc @@ -68,7 +68,9 @@ BO_ 304 GAS_PEDAL_2: 8 PCM BO_ 330 STEERING_SENSORS: 8 EPS SG_ STEER_ANGLE : 7|16@0- (-0.1,0) [-500|500] "deg" EON SG_ STEER_ANGLE_RATE : 23|16@0- (-1,0) [-3000|3000] "deg/s" EON - SG_ STEER_ANGLE_OFFSET : 39|8@0- (-0.1,0) [-128|127] "deg" EON + SG_ STEER_SENSOR_STATUS_1 : 34|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_2 : 33|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_3 : 32|1@0+ (1,0) [0|1] "" EON SG_ STEER_WHEEL_ANGLE : 47|16@0- (-0.1,0) [-500|500] "deg" EON SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON @@ -96,9 +98,10 @@ BO_ 380 POWERTRAIN_DATA: 8 PCM BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|15] "" EON @@ -110,6 +113,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 450 EPB_STATUS: 8 EPB SG_ EPB_ACTIVE : 3|1@0+ (1,0) [0|1] "" EON SG_ EPB_STATE : 29|2@0+ (1,0) [0|3] "" EON diff --git a/opendbc/honda_crv_hybrid_2019_can_generated.dbc b/opendbc/honda_crv_hybrid_2019_can_generated.dbc index 5d3e81ecbd..ed90b9408d 100644 --- a/opendbc/honda_crv_hybrid_2019_can_generated.dbc +++ b/opendbc/honda_crv_hybrid_2019_can_generated.dbc @@ -68,7 +68,9 @@ BO_ 304 GAS_PEDAL_2: 8 PCM BO_ 330 STEERING_SENSORS: 8 EPS SG_ STEER_ANGLE : 7|16@0- (-0.1,0) [-500|500] "deg" EON SG_ STEER_ANGLE_RATE : 23|16@0- (-1,0) [-3000|3000] "deg/s" EON - SG_ STEER_ANGLE_OFFSET : 39|8@0- (-0.1,0) [-128|127] "deg" EON + SG_ STEER_SENSOR_STATUS_1 : 34|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_2 : 33|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_3 : 32|1@0+ (1,0) [0|1] "" EON SG_ STEER_WHEEL_ANGLE : 47|16@0- (-0.1,0) [-500|500] "deg" EON SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON @@ -96,9 +98,10 @@ BO_ 380 POWERTRAIN_DATA: 8 PCM BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|15] "" EON @@ -110,6 +113,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 450 EPB_STATUS: 8 EPB SG_ EPB_ACTIVE : 3|1@0+ (1,0) [0|1] "" EON SG_ EPB_STATE : 29|2@0+ (1,0) [0|3] "" EON diff --git a/opendbc/honda_crv_touring_2016_can_generated.dbc b/opendbc/honda_crv_touring_2016_can_generated.dbc index ec9cc18abd..8730e03575 100644 --- a/opendbc/honda_crv_touring_2016_can_generated.dbc +++ b/opendbc/honda_crv_touring_2016_can_generated.dbc @@ -86,6 +86,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 432 STANDSTILL: 7 VSA SG_ CONTROLLED_STANDSTILL : 0|1@0+ (1,0) [0|1] "" EON SG_ WHEELS_MOVING : 12|1@0+ (1,0) [0|1] "" EON @@ -256,7 +263,7 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 6 EPS SG_ STEER_TORQUE_SENSOR : 7|12@0- (-1,0) [-2047.5|2047.5] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_CONTROL_ACTIVE : 36|1@0+ (1,0) [0|1] "" EON SG_ STEER_STATUS : 35|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 45|2@0+ (1,0) [0|3] "" EON diff --git a/opendbc/honda_fit_ex_2018_can_generated.dbc b/opendbc/honda_fit_ex_2018_can_generated.dbc index d973416b6e..a9cf3eb9e6 100644 --- a/opendbc/honda_fit_ex_2018_can_generated.dbc +++ b/opendbc/honda_fit_ex_2018_can_generated.dbc @@ -86,6 +86,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 432 STANDSTILL: 7 VSA SG_ CONTROLLED_STANDSTILL : 0|1@0+ (1,0) [0|1] "" EON SG_ WHEELS_MOVING : 12|1@0+ (1,0) [0|1] "" EON @@ -274,9 +281,10 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" EON diff --git a/opendbc/honda_fit_hybrid_2018_can_generated.dbc b/opendbc/honda_fit_hybrid_2018_can_generated.dbc index 3490737c8e..fe76cbf57a 100644 --- a/opendbc/honda_fit_hybrid_2018_can_generated.dbc +++ b/opendbc/honda_fit_hybrid_2018_can_generated.dbc @@ -266,9 +266,10 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" EON diff --git a/opendbc/honda_insight_ex_2019_can_generated.dbc b/opendbc/honda_insight_ex_2019_can_generated.dbc index 890ae8a2e6..775e22adad 100644 --- a/opendbc/honda_insight_ex_2019_can_generated.dbc +++ b/opendbc/honda_insight_ex_2019_can_generated.dbc @@ -68,7 +68,9 @@ BO_ 304 GAS_PEDAL_2: 8 PCM BO_ 330 STEERING_SENSORS: 8 EPS SG_ STEER_ANGLE : 7|16@0- (-0.1,0) [-500|500] "deg" EON SG_ STEER_ANGLE_RATE : 23|16@0- (-1,0) [-3000|3000] "deg/s" EON - SG_ STEER_ANGLE_OFFSET : 39|8@0- (-0.1,0) [-128|127] "deg" EON + SG_ STEER_SENSOR_STATUS_1 : 34|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_2 : 33|1@0+ (1,0) [0|1] "" EON + SG_ STEER_SENSOR_STATUS_3 : 32|1@0+ (1,0) [0|1] "" EON SG_ STEER_WHEEL_ANGLE : 47|16@0- (-0.1,0) [-500|500] "deg" EON SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON @@ -96,9 +98,10 @@ BO_ 380 POWERTRAIN_DATA: 8 PCM BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|15] "" EON @@ -110,6 +113,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 450 EPB_STATUS: 8 EPB SG_ EPB_ACTIVE : 3|1@0+ (1,0) [0|1] "" EON SG_ EPB_STATE : 29|2@0+ (1,0) [0|3] "" EON diff --git a/opendbc/honda_odyssey_exl_2018_generated.dbc b/opendbc/honda_odyssey_exl_2018_generated.dbc index 50868b6188..36af55b113 100644 --- a/opendbc/honda_odyssey_exl_2018_generated.dbc +++ b/opendbc/honda_odyssey_exl_2018_generated.dbc @@ -86,6 +86,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 432 STANDSTILL: 7 VSA SG_ CONTROLLED_STANDSTILL : 0|1@0+ (1,0) [0|1] "" EON SG_ WHEELS_MOVING : 12|1@0+ (1,0) [0|1] "" EON @@ -266,9 +273,10 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" EON diff --git a/opendbc/honda_odyssey_extreme_edition_2018_china_can_generated.dbc b/opendbc/honda_odyssey_extreme_edition_2018_china_can_generated.dbc index 9ac4b79f99..3c5a88a356 100644 --- a/opendbc/honda_odyssey_extreme_edition_2018_china_can_generated.dbc +++ b/opendbc/honda_odyssey_extreme_edition_2018_china_can_generated.dbc @@ -86,6 +86,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 432 STANDSTILL: 7 VSA SG_ CONTROLLED_STANDSTILL : 0|1@0+ (1,0) [0|1] "" EON SG_ WHEELS_MOVING : 12|1@0+ (1,0) [0|1] "" EON @@ -259,11 +266,12 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-2985|2985] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ CHECKSUM : 51|4@0+ (1,0) [0|15] "" EON - SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 43|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON + SG_ CHECKSUM : 51|4@0+ (1,0) [0|15] "" EON + SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON BO_ 401 GEARBOX: 8 PCM SG_ GEAR_SHIFTER : 5|6@0+ (1,0) [0|63] "" EON diff --git a/opendbc/honda_pilot_touring_2017_can_generated.dbc b/opendbc/honda_pilot_touring_2017_can_generated.dbc index 4c6b14dcd7..1f8221323d 100644 --- a/opendbc/honda_pilot_touring_2017_can_generated.dbc +++ b/opendbc/honda_pilot_touring_2017_can_generated.dbc @@ -86,6 +86,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 432 STANDSTILL: 7 VSA SG_ CONTROLLED_STANDSTILL : 0|1@0+ (1,0) [0|1] "" EON SG_ WHEELS_MOVING : 12|1@0+ (1,0) [0|1] "" EON @@ -274,9 +281,10 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" EON diff --git a/opendbc/honda_ridgeline_black_edition_2017_can_generated.dbc b/opendbc/honda_ridgeline_black_edition_2017_can_generated.dbc index a6f719ece1..cdfb231003 100644 --- a/opendbc/honda_ridgeline_black_edition_2017_can_generated.dbc +++ b/opendbc/honda_ridgeline_black_edition_2017_can_generated.dbc @@ -86,6 +86,13 @@ BO_ 420 VSA_STATUS: 8 VSA SG_ COUNTER : 61|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 59|4@0+ (1,0) [0|15] "" EON +BO_ 427 STEER_MOTOR_TORQUE: 3 EPS + SG_ CONFIG_VALID : 7|1@0+ (1,0) [0|1] "" EON + SG_ MOTOR_TORQUE : 1|10@0+ (1,0) [0|256] "" EON + SG_ OUTPUT_DISABLED : 22|1@0+ (1,0) [0|1] "" EON + SG_ COUNTER : 21|2@0+ (1,0) [0|3] "" EON + SG_ CHECKSUM : 19|4@0+ (1,0) [0|15] "" EON + BO_ 432 STANDSTILL: 7 VSA SG_ CONTROLLED_STANDSTILL : 0|1@0+ (1,0) [0|1] "" EON SG_ WHEELS_MOVING : 12|1@0+ (1,0) [0|1] "" EON @@ -269,9 +276,10 @@ BO_ 342 STEERING_SENSORS: 6 EPS BO_ 399 STEER_STATUS: 7 EPS SG_ STEER_TORQUE_SENSOR : 7|16@0- (-1,0) [-31000|31000] "tbd" EON - SG_ STEER_TORQUE_MOTOR : 23|16@0- (-1,0) [-31000|31000] "tbd" EON + SG_ STEER_ANGLE_RATE : 23|16@0- (-0.1,0) [-31000|31000] "deg/s" EON SG_ STEER_STATUS : 39|4@0+ (1,0) [0|15] "" EON SG_ STEER_CONTROL_ACTIVE : 35|1@0+ (1,0) [0|1] "" EON + SG_ STEER_CONFIG_INDEX : 43|4@0+ (1,0) [0|15] "" EON SG_ COUNTER : 53|2@0+ (1,0) [0|3] "" EON SG_ CHECKSUM : 51|4@0+ (1,0) [0|3] "" EON diff --git a/panda/README.md b/panda/README.md index ea0df2a19c..9979295a0b 100644 --- a/panda/README.md +++ b/panda/README.md @@ -39,9 +39,11 @@ Find user made scripts on the [wiki](https://community.comma.ai/wiki/index.php/P Note that you may have to setup [udev rules](https://community.comma.ai/wiki/index.php/Panda#Linux_udev_rules) for Linux, such as ``` -sudo -i -echo 'SUBSYSTEMS=="usb", ATTR{idVendor}=="bbaa", ATTR{idProduct}=="ddcc", MODE:="0666"' > /etc/udev/rules.d/11-panda.rules -exit +sudo tee /etc/udev/rules.d/11-panda.rules <set_esp_gps_mode(ESP_GPS_ENABLED); } +void grey_set_esp_gps_mode(uint8_t mode) { + switch (mode) { + case ESP_GPS_DISABLED: + // GPS OFF + set_gpio_output(GPIOC, 14, 0); + set_gpio_output(GPIOC, 5, 0); + break; + case ESP_GPS_ENABLED: + // GPS ON + set_gpio_output(GPIOC, 14, 1); + set_gpio_output(GPIOC, 5, 1); + break; + case ESP_GPS_BOOTMODE: + set_gpio_output(GPIOC, 14, 1); + set_gpio_output(GPIOC, 5, 0); + break; + default: + puts("Invalid ESP/GPS mode\n"); + break; + } +} + const board board_grey = { .board_type = "Grey", .harness_config = &white_harness_config, @@ -19,7 +41,7 @@ const board board_grey = { .enable_can_transcievers = white_enable_can_transcievers, .set_led = white_set_led, .set_usb_power_mode = white_set_usb_power_mode, - .set_esp_gps_mode = white_set_esp_gps_mode, + .set_esp_gps_mode = grey_set_esp_gps_mode, .set_can_mode = white_set_can_mode, .usb_power_mode_tick = white_usb_power_mode_tick, .check_ignition = white_check_ignition, diff --git a/panda/board/drivers/can.h b/panda/board/drivers/can.h index 07895e3e08..93db2565ca 100644 --- a/panda/board/drivers/can.h +++ b/panda/board/drivers/can.h @@ -14,6 +14,7 @@ typedef struct { #define BUS_MAX 4U +uint32_t can_rx_errs = 0; uint32_t can_send_errs = 0; uint32_t can_fwd_errs = 0; uint32_t gmlan_send_errs = 0; @@ -381,7 +382,7 @@ void can_rx(uint8_t can_number) { can_send(&to_send, bus_fwd_num, true); } - safety_rx_hook(&to_push); + can_rx_errs += safety_rx_hook(&to_push) ? 0U : 1U; ignition_can_hook(&to_push); current_board->set_led(LED_BLUE, true); diff --git a/panda/board/main.c b/panda/board/main.c index dd4edb33d1..a758bf7052 100644 --- a/panda/board/main.c +++ b/panda/board/main.c @@ -45,6 +45,7 @@ struct __attribute__((packed)) health_t { uint32_t uptime_pkt; uint32_t voltage_pkt; uint32_t current_pkt; + uint32_t can_rx_errs_pkt; uint32_t can_send_errs_pkt; uint32_t can_fwd_errs_pkt; uint32_t gmlan_send_errs_pkt; @@ -170,6 +171,7 @@ int get_health_pkt(void *dat) { health->controls_allowed_pkt = controls_allowed; health->gas_interceptor_detected_pkt = gas_interceptor_detected; + health->can_rx_errs_pkt = can_rx_errs; health->can_send_errs_pkt = can_send_errs; health->can_fwd_errs_pkt = can_fwd_errs; health->gmlan_send_errs_pkt = gmlan_send_errs; @@ -475,12 +477,6 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) can_init(CAN_NUM_FROM_BUS_NUM(setup->b.wValue.w)); } break; - // **** 0xdf: set long controls allowed - case 0xdf: - if (hardwired) { - long_controls_allowed = setup->b.wValue.w & 1U; - } - break; // **** 0xe0: uart read case 0xe0: ur = get_ring_by_number(setup->b.wValue.w); @@ -671,7 +667,7 @@ void __attribute__ ((noinline)) enable_fpu(void) { #define EON_HEARTBEAT_IGNITION_CNT_ON 5U #define EON_HEARTBEAT_IGNITION_CNT_OFF 2U -// called once per second +// called at 1Hz void TIM1_BRK_TIM9_IRQ_Handler(void) { if (TIM9->SR != 0) { can_live = pending_can_live; @@ -740,6 +736,9 @@ void TIM1_BRK_TIM9_IRQ_Handler(void) { uptime_cnt += 1U; safety_mode_cnt += 1U; ignition_can_cnt += 1U; + + // synchronous safety check + safety_tick(current_hooks); } TIM9->SR = 0; } diff --git a/panda/board/obj/panda.bin.signed b/panda/board/obj/panda.bin.signed index 8526a5b993..f48f6203cb 100644 Binary files a/panda/board/obj/panda.bin.signed and b/panda/board/obj/panda.bin.signed differ diff --git a/panda/board/provision.h b/panda/board/provision.h index 9091322f1a..0b09d8ff8b 100644 --- a/panda/board/provision.h +++ b/panda/board/provision.h @@ -11,3 +11,9 @@ void get_provision_chunk(uint8_t *resp) { } } +uint8_t chunk[PROVISION_CHUNK_LEN]; +bool is_provisioned(void) { + (void)memcpy(chunk, (uint8_t *)0x1fff79e0, PROVISION_CHUNK_LEN); + return (memcmp(chunk, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", 0x20) != 0); +} + diff --git a/panda/board/safety.h b/panda/board/safety.h index 0a216e5b1f..4588eece65 100644 --- a/panda/board/safety.h +++ b/panda/board/safety.h @@ -19,11 +19,11 @@ // from cereal.car.CarParams.SafetyModel #define SAFETY_SILENT 0U -#define SAFETY_HONDA 1U +#define SAFETY_HONDA_NIDEC 1U #define SAFETY_TOYOTA 2U #define SAFETY_ELM327 3U #define SAFETY_GM 4U -#define SAFETY_HONDA_BOSCH 5U +#define SAFETY_HONDA_BOSCH_GIRAFFE 5U #define SAFETY_FORD 6U #define SAFETY_CADILLAC 7U #define SAFETY_HYUNDAI 8U @@ -36,12 +36,13 @@ #define SAFETY_ALLOUTPUT 17U #define SAFETY_GM_ASCM 18U #define SAFETY_NOOUTPUT 19U +#define SAFETY_HONDA_BOSCH_HARNESS 20U uint16_t current_safety_mode = SAFETY_SILENT; const safety_hooks *current_hooks = &nooutput_hooks; -void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push){ - current_hooks->rx(to_push); +int safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push){ + return current_hooks->rx(to_push); } int safety_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { @@ -56,7 +57,7 @@ int safety_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { return current_hooks->fwd(bus_num, to_fwd); } -bool addr_allowed(int addr, int bus, const AddrBus addr_list[], int len) { +bool msg_allowed(int addr, int bus, const AddrBus addr_list[], int len) { bool allowed = false; for (int i = 0; i < len; i++) { if ((addr == addr_list[i].addr) && (bus == addr_list[i].bus)) { @@ -67,6 +68,106 @@ bool addr_allowed(int addr, int bus, const AddrBus addr_list[], int len) { return allowed; } +// compute the time elapsed (in microseconds) from 2 counter samples +// case where ts < ts_last is ok: overflow is properly re-casted into uint32_t +uint32_t get_ts_elapsed(uint32_t ts, uint32_t ts_last) { + return ts - ts_last; +} + +int get_addr_check_index(CAN_FIFOMailBox_TypeDef *to_push, AddrCheckStruct addr_list[], const int len) { + int bus = GET_BUS(to_push); + int addr = GET_ADDR(to_push); + + int index = -1; + for (int i = 0; i < len; i++) { + for (uint8_t j = 0U; addr_list[i].addr[j] != 0; j++) { + if ((addr == addr_list[i].addr[j]) && (bus == addr_list[i].bus)) { + index = i; + goto Return; + } + } + } +Return: + return index; +} + +// 1Hz safety function called by main. Now just a check for lagging safety messages +void safety_tick(const safety_hooks *hooks) { + uint32_t ts = TIM2->CNT; + if (hooks->addr_check != NULL) { + for (int i=0; i < hooks->addr_check_len; i++) { + uint32_t elapsed_time = get_ts_elapsed(ts, hooks->addr_check[i].last_timestamp); + // lag threshold is max of: 1s and MAX_MISSED_MSGS * expected timestep. + // Quite conservative to not risk false triggers. + // 2s of lag is worse case, since the function is called at 1Hz + bool lagging = elapsed_time > MAX(hooks->addr_check[i].expected_timestep * MAX_MISSED_MSGS, 1e6); + hooks->addr_check[i].lagging = lagging; + if (lagging) { + controls_allowed = 0; + } + } + } +} + +void update_counter(AddrCheckStruct addr_list[], int index, uint8_t counter) { + if (index != -1) { + uint8_t expected_counter = (addr_list[index].last_counter + 1U) % (addr_list[index].max_counter + 1U); + addr_list[index].wrong_counters += (expected_counter == counter) ? -1 : 1; + addr_list[index].wrong_counters = MAX(MIN(addr_list[index].wrong_counters, MAX_WRONG_COUNTERS), 0); + addr_list[index].last_counter = counter; + } +} + +bool is_msg_valid(AddrCheckStruct addr_list[], int index) { + bool valid = true; + if (index != -1) { + if ((!addr_list[index].valid_checksum) || (addr_list[index].wrong_counters >= MAX_WRONG_COUNTERS)) { + valid = false; + controls_allowed = 0; + } + } + return valid; +} + +void update_addr_timestamp(AddrCheckStruct addr_list[], int index) { + if (index != -1) { + uint32_t ts = TIM2->CNT; + addr_list[index].last_timestamp = ts; + } +} + +bool addr_safety_check(CAN_FIFOMailBox_TypeDef *to_push, + AddrCheckStruct *rx_checks, + const int rx_checks_len, + uint8_t (*get_checksum)(CAN_FIFOMailBox_TypeDef *to_push), + uint8_t (*compute_checksum)(CAN_FIFOMailBox_TypeDef *to_push), + uint8_t (*get_counter)(CAN_FIFOMailBox_TypeDef *to_push)) { + + int index = get_addr_check_index(to_push, rx_checks, rx_checks_len); + update_addr_timestamp(rx_checks, index); + + if (index != -1) { + // checksum check + if ((get_checksum != NULL) && (compute_checksum != NULL)) { + if (rx_checks[index].check_checksum) { + uint8_t checksum = get_checksum(to_push); + uint8_t checksum_comp = compute_checksum(to_push); + rx_checks[index].valid_checksum = checksum_comp == checksum; + } + } + + // counter check + if (get_counter != NULL) { + if (rx_checks[index].max_counter > 0U) { + uint8_t counter = get_counter(to_push); + update_counter(rx_checks, index, counter); + } + } + } + return is_msg_valid(rx_checks, index); +} + + typedef struct { uint16_t id; const safety_hooks *hooks; @@ -74,11 +175,12 @@ typedef struct { const safety_hook_config safety_hook_registry[] = { {SAFETY_SILENT, &nooutput_hooks}, - {SAFETY_HONDA, &honda_hooks}, + {SAFETY_HONDA_NIDEC, &honda_nidec_hooks}, {SAFETY_TOYOTA, &toyota_hooks}, {SAFETY_ELM327, &elm327_hooks}, {SAFETY_GM, &gm_hooks}, - {SAFETY_HONDA_BOSCH, &honda_bosch_hooks}, + {SAFETY_HONDA_BOSCH_GIRAFFE, &honda_bosch_giraffe_hooks}, + {SAFETY_HONDA_BOSCH_HARNESS, &honda_bosch_harness_hooks}, {SAFETY_HYUNDAI, &hyundai_hooks}, {SAFETY_CHRYSLER, &chrysler_hooks}, {SAFETY_SUBARU, &subaru_hooks}, @@ -113,12 +215,6 @@ int set_safety_hooks(uint16_t mode, int16_t param) { return set_status; } -// compute the time elapsed (in microseconds) from 2 counter samples -// case where ts < ts_last is ok: overflow is properly re-casted into uint32_t -uint32_t get_ts_elapsed(uint32_t ts, uint32_t ts_last) { - return ts - ts_last; -} - // convert a trimmed integer to signed 32 bit int int to_signed(int d, int bits) { int d_signed = d; diff --git a/panda/board/safety/safety_cadillac.h b/panda/board/safety/safety_cadillac.h index ccfa78d3f7..0f500a8cd1 100644 --- a/panda/board/safety/safety_cadillac.h +++ b/panda/board/safety/safety_cadillac.h @@ -23,7 +23,7 @@ int cadillac_get_torque_idx(int addr, int array_size) { return MIN(MAX(addr - 0x151, 0), array_size); // 0x151 is id 0, 0x152 is id 1 and so on... } -static void cadillac_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { +static int cadillac_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { int bus = GET_BUS(to_push); int addr = GET_ADDR(to_push); @@ -51,6 +51,7 @@ static void cadillac_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { if ((addr == 0x152) || (addr == 0x154)) { cadillac_supercruise_on = (GET_BYTE(to_push, 4) & 0x10) != 0; } + return 1; } static int cadillac_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { @@ -58,7 +59,7 @@ static int cadillac_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int addr = GET_ADDR(to_send); int bus = GET_BUS(to_send); - if (!addr_allowed(addr, bus, CADILLAC_TX_MSGS, sizeof(CADILLAC_TX_MSGS) / sizeof(CADILLAC_TX_MSGS[0]))) { + if (!msg_allowed(addr, bus, CADILLAC_TX_MSGS, sizeof(CADILLAC_TX_MSGS) / sizeof(CADILLAC_TX_MSGS[0]))) { tx = 0; } diff --git a/panda/board/safety/safety_chrysler.h b/panda/board/safety/safety_chrysler.h index ce9f65f2af..8c201a3bb4 100644 --- a/panda/board/safety/safety_chrysler.h +++ b/panda/board/safety/safety_chrysler.h @@ -6,13 +6,20 @@ const int CHRYSLER_MAX_RATE_DOWN = 3; const int CHRYSLER_MAX_TORQUE_ERROR = 80; // max torque cmd in excess of torque motor const AddrBus CHRYSLER_TX_MSGS[] = {{571, 0}, {658, 0}, {678, 0}}; +// TODO: do checksum and counter checks +AddrCheckStruct chrysler_rx_checks[] = { + {.addr = {544}, .bus = 0, .expected_timestep = 10000U}, + {.addr = {500}, .bus = 0, .expected_timestep = 20000U}, +}; +const int CHRYSLER_RX_CHECK_LEN = sizeof(chrysler_rx_checks) / sizeof(chrysler_rx_checks[0]); + int chrysler_rt_torque_last = 0; int chrysler_desired_torque_last = 0; int chrysler_cruise_engaged_last = 0; uint32_t chrysler_ts_last = 0; struct sample_t chrysler_torque_meas; // last few torques measured -static void chrysler_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { +static int chrysler_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { int bus = GET_BUS(to_push); int addr = GET_ADDR(to_push); @@ -36,10 +43,13 @@ static void chrysler_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { chrysler_cruise_engaged_last = cruise_engaged; } + // TODO: add gas pressed check + // check if stock camera ECU is on bus 0 if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == 0x292)) { relay_malfunction = true; } + return 1; } static int chrysler_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { @@ -48,7 +58,7 @@ static int chrysler_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int addr = GET_ADDR(to_send); int bus = GET_BUS(to_send); - if (!addr_allowed(addr, bus, CHRYSLER_TX_MSGS, sizeof(CHRYSLER_TX_MSGS) / sizeof(CHRYSLER_TX_MSGS[0]))) { + if (!msg_allowed(addr, bus, CHRYSLER_TX_MSGS, sizeof(CHRYSLER_TX_MSGS) / sizeof(CHRYSLER_TX_MSGS[0]))) { tx = 0; } @@ -137,4 +147,6 @@ const safety_hooks chrysler_hooks = { .tx = chrysler_tx_hook, .tx_lin = nooutput_tx_lin_hook, .fwd = chrysler_fwd_hook, + .addr_check = chrysler_rx_checks, + .addr_check_len = sizeof(chrysler_rx_checks) / sizeof(chrysler_rx_checks[0]), }; diff --git a/panda/board/safety/safety_defaults.h b/panda/board/safety/safety_defaults.h index 4733438c9c..ba96b7dd99 100644 --- a/panda/board/safety/safety_defaults.h +++ b/panda/board/safety/safety_defaults.h @@ -1,5 +1,6 @@ -void default_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { +int default_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { UNUSED(to_push); + return true; } // *** no output safety mode *** diff --git a/panda/board/safety/safety_elm327.h b/panda/board/safety/safety_elm327.h index df515b05d6..a39c4125ce 100644 --- a/panda/board/safety/safety_elm327.h +++ b/panda/board/safety/safety_elm327.h @@ -12,7 +12,7 @@ static int elm327_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { //Check valid 29 bit send addresses for ISO 15765-4 //Check valid 11 bit send addresses for ISO 15765-4 if ((addr != 0x18DB33F1) && ((addr & 0x1FFF00FF) != 0x18DA00F1) && - ((addr != 0x7DF) && ((addr & 0x1FFFFFF8) != 0x7E0))) { + ((addr & 0x1FFFFF00) != 0x700)) { tx = 0; } return tx; diff --git a/panda/board/safety/safety_ford.h b/panda/board/safety/safety_ford.h index 47c7342a44..97e0f57a2c 100644 --- a/panda/board/safety/safety_ford.h +++ b/panda/board/safety/safety_ford.h @@ -11,7 +11,7 @@ int ford_brake_prev = 0; int ford_gas_prev = 0; bool ford_moving = false; -static void ford_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { +static int ford_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { int addr = GET_ADDR(to_push); int bus = GET_BUS(to_push); @@ -58,6 +58,7 @@ static void ford_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == 0x3CA)) { relay_malfunction = true; } + return 1; } // all commands: just steering diff --git a/panda/board/safety/safety_gm.h b/panda/board/safety/safety_gm.h index 92c32ad808..5356a113f6 100644 --- a/panda/board/safety/safety_gm.h +++ b/panda/board/safety/safety_gm.h @@ -23,6 +23,16 @@ const AddrBus GM_TX_MSGS[] = {{384, 0}, {1033, 0}, {1034, 0}, {715, 0}, {880, 0} {789, 2}, // ch bus {0x104c006c, 3}, {0x10400060, 3}}; // gmlan +// TODO: do checksum and counter checks. Add correct timestep, 0.1s for now. +AddrCheckStruct gm_rx_checks[] = { + {.addr = {388}, .bus = 0, .expected_timestep = 100000U}, + {.addr = {842}, .bus = 0, .expected_timestep = 100000U}, + {.addr = {481}, .bus = 0, .expected_timestep = 100000U}, + {.addr = {241}, .bus = 0, .expected_timestep = 100000U}, + {.addr = {417}, .bus = 0, .expected_timestep = 100000U}, +}; +const int GM_RX_CHECK_LEN = sizeof(gm_rx_checks) / sizeof(gm_rx_checks[0]); + int gm_brake_prev = 0; int gm_gas_prev = 0; bool gm_moving = false; @@ -31,7 +41,7 @@ int gm_desired_torque_last = 0; uint32_t gm_ts_last = 0; struct sample_t gm_torque_driver; // last few driver torques measured -static void gm_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { +static int gm_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { int bus = GET_BUS(to_push); int addr = GET_ADDR(to_push); @@ -82,7 +92,7 @@ static void gm_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { // exit controls on rising edge of gas press if (addr == 417) { int gas = GET_BYTE(to_push, 6); - if (gas && !gm_gas_prev && long_controls_allowed) { + if (gas && !gm_gas_prev) { controls_allowed = 0; } gm_gas_prev = gas; @@ -103,6 +113,7 @@ static void gm_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && ((addr == 384) || (addr == 715))) { relay_malfunction = true; } + return 1; } // all commands: gas/regen, friction brake and steering @@ -117,7 +128,7 @@ static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int addr = GET_ADDR(to_send); int bus = GET_BUS(to_send); - if (!addr_allowed(addr, bus, GM_TX_MSGS, sizeof(GM_TX_MSGS)/sizeof(GM_TX_MSGS[0]))) { + if (!msg_allowed(addr, bus, GM_TX_MSGS, sizeof(GM_TX_MSGS)/sizeof(GM_TX_MSGS[0]))) { tx = 0; } @@ -134,7 +145,7 @@ static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { if (addr == 789) { int brake = ((GET_BYTE(to_send, 0) & 0xFU) << 8) + GET_BYTE(to_send, 1); brake = (0x1000 - brake) & 0xFFF; - if (!current_controls_allowed || !long_controls_allowed) { + if (!current_controls_allowed) { if (brake != 0) { tx = 0; } @@ -197,7 +208,7 @@ static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int gas_regen = ((GET_BYTE(to_send, 2) & 0x7FU) << 5) + ((GET_BYTE(to_send, 3) & 0xF8U) >> 3); // Disabled message is !engaged with gas // value that corresponds to max regen. - if (!current_controls_allowed || !long_controls_allowed) { + if (!current_controls_allowed) { bool apply = GET_BYTE(to_send, 0) & 1U; if (apply || (gas_regen != GM_MAX_REGEN)) { tx = 0; @@ -219,4 +230,6 @@ const safety_hooks gm_hooks = { .tx = gm_tx_hook, .tx_lin = nooutput_tx_lin_hook, .fwd = default_fwd_hook, + .addr_check = gm_rx_checks, + .addr_check_len = sizeof(gm_rx_checks) / sizeof(gm_rx_checks[0]), }; diff --git a/panda/board/safety/safety_gm_ascm.h b/panda/board/safety/safety_gm_ascm.h index 36fd1d8f2a..e7eddf454a 100644 --- a/panda/board/safety/safety_gm_ascm.h +++ b/panda/board/safety/safety_gm_ascm.h @@ -41,4 +41,3 @@ const safety_hooks gm_ascm_hooks = { .tx_lin = nooutput_tx_lin_hook, .fwd = gm_ascm_fwd_hook, }; - diff --git a/panda/board/safety/safety_honda.h b/panda/board/safety/safety_honda.h index ab8ceb5290..b49c929363 100644 --- a/panda/board/safety/safety_honda.h +++ b/panda/board/safety/safety_honda.h @@ -7,109 +7,165 @@ // brake rising edge // brake > 0mph const AddrBus HONDA_N_TX_MSGS[] = {{0xE4, 0}, {0x194, 0}, {0x1FA, 0}, {0x200, 0}, {0x30C, 0}, {0x33D, 0}}; -const AddrBus HONDA_BH_TX_MSGS[] = {{0xE4, 0}, {0x296, 1}, {0x33D, 0}}; // Bosch Harness const AddrBus HONDA_BG_TX_MSGS[] = {{0xE4, 2}, {0x296, 0}, {0x33D, 2}}; // Bosch Giraffe +const AddrBus HONDA_BH_TX_MSGS[] = {{0xE4, 0}, {0x296, 1}, {0x33D, 0}}; // Bosch Harness const int HONDA_GAS_INTERCEPTOR_THRESHOLD = 328; // ratio between offset and gain from dbc file + +// Nidec and Bosch giraffe have pt on bus 0 +AddrCheckStruct honda_rx_checks[] = { + {.addr = {0x1A6, 0x296}, .bus = 0, .check_checksum = true, .max_counter = 3U, .expected_timestep = 40000U}, + {.addr = { 0x158}, .bus = 0, .check_checksum = true, .max_counter = 3U, .expected_timestep = 10000U}, + {.addr = { 0x17C}, .bus = 0, .check_checksum = true, .max_counter = 3U, .expected_timestep = 10000U}, +}; +const int HONDA_RX_CHECKS_LEN = sizeof(honda_rx_checks) / sizeof(honda_rx_checks[0]); + +// Bosch harness has pt on bus 1 +AddrCheckStruct honda_bh_rx_checks[] = { + {.addr = {0x296}, .bus = 1, .check_checksum = true, .max_counter = 3U, .expected_timestep = 40000U}, + {.addr = {0x158}, .bus = 1, .check_checksum = true, .max_counter = 3U, .expected_timestep = 10000U}, + {.addr = {0x17C}, .bus = 1, .check_checksum = true, .max_counter = 3U, .expected_timestep = 10000U}, +}; +const int HONDA_BH_RX_CHECKS_LEN = sizeof(honda_bh_rx_checks) / sizeof(honda_bh_rx_checks[0]); + int honda_brake = 0; int honda_gas_prev = 0; bool honda_brake_pressed_prev = false; bool honda_moving = false; -bool honda_bosch_hardware = false; bool honda_alt_brake_msg = false; bool honda_fwd_brake = false; +enum {HONDA_N_HW, HONDA_BG_HW, HONDA_BH_HW} honda_hw = HONDA_N_HW; -static void honda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int addr = GET_ADDR(to_push); +static uint8_t honda_get_checksum(CAN_FIFOMailBox_TypeDef *to_push) { + int checksum_byte = GET_LEN(to_push) - 1; + return (uint8_t)(GET_BYTE(to_push, checksum_byte)) & 0xFU; +} + +static uint8_t honda_compute_checksum(CAN_FIFOMailBox_TypeDef *to_push) { int len = GET_LEN(to_push); - int bus = GET_BUS(to_push); + uint8_t checksum = 0U; + unsigned int addr = GET_ADDR(to_push); + while (addr > 0U) { + checksum += (addr & 0xFU); addr >>= 4; + } + for (int j = 0; (j < len); j++) { + uint8_t byte = GET_BYTE(to_push, j); + checksum += (byte & 0xFU) + (byte >> 4U); + if (j == (len - 1)) { + checksum -= (byte & 0xFU); // remove checksum in message + } + } + return (8U - checksum) & 0xFU; +} - // sample speed - if (addr == 0x158) { - // first 2 bytes - honda_moving = GET_BYTE(to_push, 0) | GET_BYTE(to_push, 1); +static uint8_t honda_get_counter(CAN_FIFOMailBox_TypeDef *to_push) { + int counter_byte = GET_LEN(to_push) - 1; + return ((uint8_t)(GET_BYTE(to_push, counter_byte)) >> 4U) & 0x3U; +} + +static int honda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { + + bool valid; + if (honda_hw == HONDA_BH_HW) { + valid = addr_safety_check(to_push, honda_bh_rx_checks, HONDA_BH_RX_CHECKS_LEN, + honda_get_checksum, honda_compute_checksum, honda_get_counter); + } else { + valid = addr_safety_check(to_push, honda_rx_checks, HONDA_RX_CHECKS_LEN, + honda_get_checksum, honda_compute_checksum, honda_get_counter); } - // state machine to enter and exit controls - // 0x1A6 for the ILX, 0x296 for the Civic Touring - if ((addr == 0x1A6) || (addr == 0x296)) { - int button = (GET_BYTE(to_push, 0) & 0xE0) >> 5; - switch (button) { - case 2: // cancel - controls_allowed = 0; - break; - case 3: // set - case 4: // resume - controls_allowed = 1; - break; - default: - break; // any other button is irrelevant + if (valid) { + int addr = GET_ADDR(to_push); + int len = GET_LEN(to_push); + int bus = GET_BUS(to_push); + + // sample speed + if (addr == 0x158) { + // first 2 bytes + honda_moving = GET_BYTE(to_push, 0) | GET_BYTE(to_push, 1); } - } - // user brake signal on 0x17C reports applied brake from computer brake on accord - // and crv, which prevents the usual brake safety from working correctly. these - // cars have a signal on 0x1BE which only detects user's brake being applied so - // in these cases, this is used instead. - // most hondas: 0x17C bit 53 - // accord, crv: 0x1BE bit 4 - // exit controls on rising edge of brake press or on brake press when speed > 0 - bool is_user_brake_msg = honda_alt_brake_msg ? ((addr) == 0x1BE) : ((addr) == 0x17C); - if (is_user_brake_msg) { - bool brake_pressed = honda_alt_brake_msg ? (GET_BYTE((to_push), 0) & 0x10) : (GET_BYTE((to_push), 6) & 0x20); - if (brake_pressed && (!(honda_brake_pressed_prev) || honda_moving)) { - controls_allowed = 0; + // state machine to enter and exit controls + // 0x1A6 for the ILX, 0x296 for the Civic Touring + if ((addr == 0x1A6) || (addr == 0x296)) { + int button = (GET_BYTE(to_push, 0) & 0xE0) >> 5; + switch (button) { + case 2: // cancel + controls_allowed = 0; + break; + case 3: // set + case 4: // resume + controls_allowed = 1; + break; + default: + break; // any other button is irrelevant + } } - honda_brake_pressed_prev = brake_pressed; - } - // exit controls on rising edge of gas press if interceptor (0x201 w/ len = 6) - // length check because bosch hardware also uses this id (0x201 w/ len = 8) - if ((addr == 0x201) && (len == 6)) { - gas_interceptor_detected = 1; - int gas_interceptor = GET_INTERCEPTOR(to_push); - if ((gas_interceptor > HONDA_GAS_INTERCEPTOR_THRESHOLD) && - (gas_interceptor_prev <= HONDA_GAS_INTERCEPTOR_THRESHOLD) && - long_controls_allowed) { - controls_allowed = 0; + // user brake signal on 0x17C reports applied brake from computer brake on accord + // and crv, which prevents the usual brake safety from working correctly. these + // cars have a signal on 0x1BE which only detects user's brake being applied so + // in these cases, this is used instead. + // most hondas: 0x17C bit 53 + // accord, crv: 0x1BE bit 4 + // exit controls on rising edge of brake press or on brake press when speed > 0 + bool is_user_brake_msg = honda_alt_brake_msg ? ((addr) == 0x1BE) : ((addr) == 0x17C); + if (is_user_brake_msg) { + bool brake_pressed = honda_alt_brake_msg ? (GET_BYTE((to_push), 0) & 0x10) : (GET_BYTE((to_push), 6) & 0x20); + if (brake_pressed && (!(honda_brake_pressed_prev) || honda_moving)) { + controls_allowed = 0; + } + honda_brake_pressed_prev = brake_pressed; } - gas_interceptor_prev = gas_interceptor; - } - // exit controls on rising edge of gas press if no interceptor - if (!gas_interceptor_detected) { - if (addr == 0x17C) { - int gas = GET_BYTE(to_push, 0); - if (gas && !(honda_gas_prev) && long_controls_allowed) { + // exit controls on rising edge of gas press if interceptor (0x201 w/ len = 6) + // length check because bosch hardware also uses this id (0x201 w/ len = 8) + if ((addr == 0x201) && (len == 6)) { + gas_interceptor_detected = 1; + int gas_interceptor = GET_INTERCEPTOR(to_push); + if ((gas_interceptor > HONDA_GAS_INTERCEPTOR_THRESHOLD) && + (gas_interceptor_prev <= HONDA_GAS_INTERCEPTOR_THRESHOLD)) { controls_allowed = 0; } - honda_gas_prev = gas; + gas_interceptor_prev = gas_interceptor; } - } - if ((bus == 2) && (addr == 0x1FA)) { - bool honda_stock_aeb = GET_BYTE(to_push, 3) & 0x20; - int honda_stock_brake = (GET_BYTE(to_push, 0) << 2) + ((GET_BYTE(to_push, 1) >> 6) & 0x3); - - // Forward AEB when stock braking is higher than openpilot braking - // only stop forwarding when AEB event is over - if (!honda_stock_aeb) { - honda_fwd_brake = false; - } else if (honda_stock_brake >= honda_brake) { - honda_fwd_brake = true; - } else { - // Leave Honda forward brake as is + + // exit controls on rising edge of gas press if no interceptor + if (!gas_interceptor_detected) { + if (addr == 0x17C) { + int gas = GET_BYTE(to_push, 0); + if (gas && !honda_gas_prev) { + controls_allowed = 0; + } + honda_gas_prev = gas; + } } - } + if ((bus == 2) && (addr == 0x1FA)) { + bool honda_stock_aeb = GET_BYTE(to_push, 3) & 0x20; + int honda_stock_brake = (GET_BYTE(to_push, 0) << 2) + ((GET_BYTE(to_push, 1) >> 6) & 0x3); - // if steering controls messages are received on the destination bus, it's an indication - // that the relay might be malfunctioning - int bus_rdr_car = (board_has_relay()) ? 0 : 2; // radar bus, car side - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && ((addr == 0xE4) || (addr == 0x194))) { - if ((honda_bosch_hardware && (bus == bus_rdr_car)) || - (!honda_bosch_hardware && (bus == 0))) { - relay_malfunction = true; + // Forward AEB when stock braking is higher than openpilot braking + // only stop forwarding when AEB event is over + if (!honda_stock_aeb) { + honda_fwd_brake = false; + } else if (honda_stock_brake >= honda_brake) { + honda_fwd_brake = true; + } else { + // Leave Honda forward brake as is + } + } + + // if steering controls messages are received on the destination bus, it's an indication + // that the relay might be malfunctioning + int bus_rdr_car = (honda_hw == HONDA_BH_HW) ? 0 : 2; // radar bus, car side + if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && ((addr == 0xE4) || (addr == 0x194))) { + if (((honda_hw != HONDA_N_HW) && (bus == bus_rdr_car)) || + ((honda_hw == HONDA_N_HW) && (bus == 0))) { + relay_malfunction = true; + } } } + return valid; } // all commands: gas, brake and steering @@ -124,16 +180,12 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int addr = GET_ADDR(to_send); int bus = GET_BUS(to_send); - if (honda_bosch_hardware) { - if (board_has_relay() && !addr_allowed(addr, bus, HONDA_BH_TX_MSGS, sizeof(HONDA_BH_TX_MSGS)/sizeof(HONDA_BH_TX_MSGS[0]))) { - tx = 0; - } - if (!board_has_relay() && !addr_allowed(addr, bus, HONDA_BG_TX_MSGS, sizeof(HONDA_BG_TX_MSGS)/sizeof(HONDA_BG_TX_MSGS[0]))) { - tx = 0; - } - } - if (!honda_bosch_hardware && !addr_allowed(addr, bus, HONDA_N_TX_MSGS, sizeof(HONDA_N_TX_MSGS)/sizeof(HONDA_N_TX_MSGS[0]))) { - tx = 0; + if (honda_hw == HONDA_BG_HW) { + tx = msg_allowed(addr, bus, HONDA_BG_TX_MSGS, sizeof(HONDA_BG_TX_MSGS)/sizeof(HONDA_BG_TX_MSGS[0])); + } else if (honda_hw == HONDA_BH_HW) { + tx = msg_allowed(addr, bus, HONDA_BH_TX_MSGS, sizeof(HONDA_BH_TX_MSGS)/sizeof(HONDA_BH_TX_MSGS[0])); + } else { + tx = msg_allowed(addr, bus, HONDA_N_TX_MSGS, sizeof(HONDA_N_TX_MSGS)/sizeof(HONDA_N_TX_MSGS[0])); } if (relay_malfunction) { @@ -149,7 +201,7 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { // BRAKE: safety check if ((addr == 0x1FA) && (bus == 0)) { honda_brake = (GET_BYTE(to_send, 0) << 2) + ((GET_BYTE(to_send, 1) >> 6) & 0x3); - if (!current_controls_allowed || !long_controls_allowed) { + if (!current_controls_allowed) { if (honda_brake != 0) { tx = 0; } @@ -174,7 +226,7 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { // GAS: safety check if (addr == 0x200) { - if (!current_controls_allowed || !long_controls_allowed) { + if (!current_controls_allowed) { if (GET_BYTE(to_send, 0) || GET_BYTE(to_send, 1)) { tx = 0; } @@ -184,9 +236,8 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { // FORCE CANCEL: safety check only relevant when spamming the cancel button in Bosch HW // ensuring that only the cancel button press is sent (VAL 2) when controls are off. // This avoids unintended engagements while still allowing resume spam - int bus_pt = ((board_has_relay()) && honda_bosch_hardware)? 1 : 0; - if ((addr == 0x296) && honda_bosch_hardware && - !current_controls_allowed && (bus == bus_pt)) { + int bus_pt = (honda_hw == HONDA_BH_HW)? 1 : 0; + if ((addr == 0x296) && !current_controls_allowed && (bus == bus_pt)) { if (((GET_BYTE(to_send, 0) >> 5) & 0x7) != 2) { tx = 0; } @@ -196,23 +247,31 @@ static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { return tx; } -static void honda_init(int16_t param) { +static void honda_nidec_init(int16_t param) { UNUSED(param); controls_allowed = false; relay_malfunction = false; - honda_bosch_hardware = false; + honda_hw = HONDA_N_HW; honda_alt_brake_msg = false; } -static void honda_bosch_init(int16_t param) { +static void honda_bosch_giraffe_init(int16_t param) { + controls_allowed = false; + relay_malfunction = false; + honda_hw = HONDA_BG_HW; + // Checking for alternate brake override from safety parameter + honda_alt_brake_msg = (param == 1) ? true : false; +} + +static void honda_bosch_harness_init(int16_t param) { controls_allowed = false; relay_malfunction = false; - honda_bosch_hardware = true; + honda_hw = HONDA_BH_HW; // Checking for alternate brake override from safety parameter honda_alt_brake_msg = (param == 1) ? true : false; } -static int honda_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { +static int honda_nidec_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { // fwd from car to camera. also fwd certain msgs from camera to car // 0xE4 is steering on all cars except CRV and RDX, 0x194 for CRV and RDX, // 0x1FA is brake control, 0x30C is acc hud, 0x33D is lkas hud, @@ -228,9 +287,7 @@ static int honda_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { bool is_lkas_msg = (addr == 0xE4) || (addr == 0x194) || (addr == 0x33D); bool is_acc_hud_msg = addr == 0x30C; bool is_brake_msg = addr == 0x1FA; - bool block_fwd = is_lkas_msg || - (is_acc_hud_msg && long_controls_allowed) || - (is_brake_msg && long_controls_allowed && !honda_fwd_brake); + bool block_fwd = is_lkas_msg || is_acc_hud_msg || (is_brake_msg && !honda_fwd_brake); if (!block_fwd) { bus_fwd = 0; } @@ -241,8 +298,8 @@ static int honda_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { static int honda_bosch_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { int bus_fwd = -1; - int bus_rdr_cam = (board_has_relay()) ? 2 : 1; // radar bus, camera side - int bus_rdr_car = (board_has_relay()) ? 0 : 2; // radar bus, car side + int bus_rdr_cam = (honda_hw == HONDA_BH_HW) ? 2 : 1; // radar bus, camera side + int bus_rdr_car = (honda_hw == HONDA_BH_HW) ? 0 : 2; // radar bus, car side if (!relay_malfunction) { if (bus_num == bus_rdr_car) { @@ -259,18 +316,32 @@ static int honda_bosch_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { return bus_fwd; } -const safety_hooks honda_hooks = { - .init = honda_init, +const safety_hooks honda_nidec_hooks = { + .init = honda_nidec_init, .rx = honda_rx_hook, .tx = honda_tx_hook, .tx_lin = nooutput_tx_lin_hook, - .fwd = honda_fwd_hook, + .fwd = honda_nidec_fwd_hook, + .addr_check = honda_rx_checks, + .addr_check_len = sizeof(honda_rx_checks) / sizeof(honda_rx_checks[0]), +}; + +const safety_hooks honda_bosch_giraffe_hooks = { + .init = honda_bosch_giraffe_init, + .rx = honda_rx_hook, + .tx = honda_tx_hook, + .tx_lin = nooutput_tx_lin_hook, + .fwd = honda_bosch_fwd_hook, + .addr_check = honda_rx_checks, + .addr_check_len = sizeof(honda_rx_checks) / sizeof(honda_rx_checks[0]), }; -const safety_hooks honda_bosch_hooks = { - .init = honda_bosch_init, +const safety_hooks honda_bosch_harness_hooks = { + .init = honda_bosch_harness_init, .rx = honda_rx_hook, .tx = honda_tx_hook, .tx_lin = nooutput_tx_lin_hook, .fwd = honda_bosch_fwd_hook, + .addr_check = honda_bh_rx_checks, + .addr_check_len = sizeof(honda_bh_rx_checks) / sizeof(honda_bh_rx_checks[0]), }; diff --git a/panda/board/safety/safety_hyundai.h b/panda/board/safety/safety_hyundai.h index b2d215f687..fcf112a964 100644 --- a/panda/board/safety/safety_hyundai.h +++ b/panda/board/safety/safety_hyundai.h @@ -5,16 +5,22 @@ const int HYUNDAI_MAX_RATE_UP = 3; const int HYUNDAI_MAX_RATE_DOWN = 7; const int HYUNDAI_DRIVER_TORQUE_ALLOWANCE = 50; const int HYUNDAI_DRIVER_TORQUE_FACTOR = 2; - const AddrBus HYUNDAI_TX_MSGS[] = {{832, 0}, {1265, 0}}; +// TODO: do checksum and counter checks +AddrCheckStruct hyundai_rx_checks[] = { + {.addr = {897}, .bus = 0, .expected_timestep = 10000U}, + {.addr = {1057}, .bus = 0, .expected_timestep = 20000U}, +}; +const int HYUNDAI_RX_CHECK_LEN = sizeof(hyundai_rx_checks) / sizeof(hyundai_rx_checks[0]); + int hyundai_rt_torque_last = 0; int hyundai_desired_torque_last = 0; int hyundai_cruise_engaged_last = 0; uint32_t hyundai_ts_last = 0; struct sample_t hyundai_torque_driver; // last few driver torques measured -static void hyundai_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { +static int hyundai_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { int bus = GET_BUS(to_push); int addr = GET_ADDR(to_push); @@ -24,11 +30,6 @@ static void hyundai_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { update_sample(&hyundai_torque_driver, torque_driver_new); } - // check if stock camera ECU is on bus 0 - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == 832)) { - relay_malfunction = true; - } - // enter controls on rising edge of ACC, exit controls on ACC off if (addr == 1057) { // 2 bits: 13-14 @@ -41,6 +42,14 @@ static void hyundai_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { } hyundai_cruise_engaged_last = cruise_engaged; } + + // TODO: check gas pressed + + // check if stock camera ECU is on bus 0 + if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == 832)) { + relay_malfunction = true; + } + return 1; } static int hyundai_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { @@ -49,7 +58,7 @@ static int hyundai_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int addr = GET_ADDR(to_send); int bus = GET_BUS(to_send); - if (!addr_allowed(addr, bus, HYUNDAI_TX_MSGS, sizeof(HYUNDAI_TX_MSGS)/sizeof(HYUNDAI_TX_MSGS[0]))) { + if (!msg_allowed(addr, bus, HYUNDAI_TX_MSGS, sizeof(HYUNDAI_TX_MSGS)/sizeof(HYUNDAI_TX_MSGS[0]))) { tx = 0; } @@ -140,4 +149,6 @@ const safety_hooks hyundai_hooks = { .tx = hyundai_tx_hook, .tx_lin = nooutput_tx_lin_hook, .fwd = hyundai_fwd_hook, + .addr_check = hyundai_rx_checks, + .addr_check_len = sizeof(hyundai_rx_checks) / sizeof(hyundai_rx_checks[0]), }; diff --git a/panda/board/safety/safety_mazda.h b/panda/board/safety/safety_mazda.h index f1215f23da..f6b19c1a2f 100644 --- a/panda/board/safety/safety_mazda.h +++ b/panda/board/safety/safety_mazda.h @@ -22,7 +22,6 @@ #define MAZDA_DRIVER_TORQUE_ALLOWANCE 15 #define MAZDA_DRIVER_TORQUE_FACTOR 1 - int mazda_cruise_engaged_last = 0; int mazda_rt_torque_last = 0; int mazda_desired_torque_last = 0; @@ -30,7 +29,7 @@ uint32_t mazda_ts_last = 0; struct sample_t mazda_torque_driver; // last few driver torques measured // track msgs coming from OP so that we know what CAM msgs to drop and what to forward -void mazda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { +static int mazda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { int bus = GET_BUS(to_push); int addr = GET_ADDR(to_push); @@ -58,6 +57,7 @@ void mazda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == MAZDA_CAM) && (addr == MAZDA_WHEEL_SPEED)) { relay_malfunction = true; } + return 1; } static int mazda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { @@ -146,4 +146,5 @@ const safety_hooks mazda_hooks = { .tx = mazda_tx_hook, .tx_lin = nooutput_tx_lin_hook, .fwd = mazda_fwd_hook, + // TODO: add addr safety checks }; diff --git a/panda/board/safety/safety_subaru.h b/panda/board/safety/safety_subaru.h index 66e5947f85..b4ff5f29d9 100644 --- a/panda/board/safety/safety_subaru.h +++ b/panda/board/safety/safety_subaru.h @@ -10,13 +10,20 @@ const int SUBARU_DRIVER_TORQUE_FACTOR = 10; const AddrBus SUBARU_TX_MSGS[] = {{0x122, 0}, {0x164, 0}, {0x221, 0}, {0x322, 0}}; +// TODO: do checksum and counter checks after adding the signals to the outback dbc file +AddrCheckStruct subaru_rx_checks[] = { + {.addr = {0x119, 0x371}, .bus = 0, .expected_timestep = 20000U}, + {.addr = {0x240, 0x144}, .bus = 0, .expected_timestep = 50000U}, +}; +const int SUBARU_RX_CHECK_LEN = sizeof(subaru_rx_checks) / sizeof(subaru_rx_checks[0]); + int subaru_cruise_engaged_last = 0; int subaru_rt_torque_last = 0; int subaru_desired_torque_last = 0; uint32_t subaru_ts_last = 0; struct sample_t subaru_torque_driver; // last few driver torques measured -static void subaru_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { +static int subaru_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { int bus = GET_BUS(to_push); int addr = GET_ADDR(to_push); @@ -41,9 +48,12 @@ static void subaru_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { subaru_cruise_engaged_last = cruise_engaged; } + // TODO: enforce cancellation on gas pressed + if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && ((addr == 0x122) || (addr == 0x164))) { relay_malfunction = true; } + return 1; } static int subaru_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { @@ -51,7 +61,7 @@ static int subaru_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int addr = GET_ADDR(to_send); int bus = GET_BUS(to_send); - if (!addr_allowed(addr, bus, SUBARU_TX_MSGS, sizeof(SUBARU_TX_MSGS) / sizeof(SUBARU_TX_MSGS[0]))) { + if (!msg_allowed(addr, bus, SUBARU_TX_MSGS, sizeof(SUBARU_TX_MSGS) / sizeof(SUBARU_TX_MSGS[0]))) { tx = 0; } @@ -141,4 +151,6 @@ const safety_hooks subaru_hooks = { .tx = subaru_tx_hook, .tx_lin = nooutput_tx_lin_hook, .fwd = subaru_fwd_hook, + .addr_check = subaru_rx_checks, + .addr_check_len = sizeof(subaru_rx_checks) / sizeof(subaru_rx_checks[0]), }; diff --git a/panda/board/safety/safety_tesla.h b/panda/board/safety/safety_tesla.h index 2e5d20c622..fbb464dcde 100644 --- a/panda/board/safety/safety_tesla.h +++ b/panda/board/safety/safety_tesla.h @@ -44,7 +44,7 @@ void reset_gmlan_switch_timeout(void); void gmlan_switch_init(int timeout_enable); -static void tesla_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { +static int tesla_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { set_gmlan_digital_output(0); // #define GMLAN_HIGH 0 reset_gmlan_switch_timeout(); //we're still in tesla safety mode, reset the timeout counter and make sure our output is enabled @@ -120,6 +120,7 @@ static void tesla_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { tesla_controls_allowed_last = controls_allowed; } + return 1; } // all commands: gas/regen, friction brake and steering diff --git a/panda/board/safety/safety_toyota.h b/panda/board/safety/safety_toyota.h index 0576a46381..844e387fef 100644 --- a/panda/board/safety/safety_toyota.h +++ b/panda/board/safety/safety_toyota.h @@ -18,11 +18,16 @@ const int TOYOTA_MIN_ACCEL = -3000; // 3.0 m/s2 const int TOYOTA_GAS_INTERCEPTOR_THRESHOLD = 475; // ratio between offset and gain from dbc file -// allowed DSU messages on bus 0 and 1 const AddrBus TOYOTA_TX_MSGS[] = {{0x283, 0}, {0x2E6, 0}, {0x2E7, 0}, {0x33E, 0}, {0x344, 0}, {0x365, 0}, {0x366, 0}, {0x4CB, 0}, // DSU bus 0 - {0x128, 1}, {0x141, 1}, {0x160, 1}, {0x161, 1}, {0x470, 1}, // DSU bus 1 - {0x2E4, 0}, {0x411, 0}, {0x412, 0}, {0x343, 0}, {0x1D2, 0}, // LKAS + ACC - {0x200, 0}}; // interceptor + {0x128, 1}, {0x141, 1}, {0x160, 1}, {0x161, 1}, {0x470, 1}, // DSU bus 1 + {0x2E4, 0}, {0x411, 0}, {0x412, 0}, {0x343, 0}, {0x1D2, 0}, // LKAS + ACC + {0x200, 0}}; // interceptor + +AddrCheckStruct toyota_rx_checks[] = { + {.addr = {0x260}, .bus = 0, .check_checksum = true, .max_counter = 0U, .expected_timestep = 20000U}, + {.addr = {0x1D2}, .bus = 0, .check_checksum = true, .max_counter = 0U, .expected_timestep = 30000U}, +}; +const int TOYOTA_RX_CHECKS_LEN = sizeof(toyota_rx_checks) / sizeof(toyota_rx_checks[0]); // global actuation limit states int toyota_dbc_eps_torque_factor = 100; // conversion factor for STEER_TORQUE_EPS in %: see dbc file @@ -36,65 +41,84 @@ int toyota_gas_prev = 0; struct sample_t toyota_torque_meas; // last 3 motor torques produced by the eps -static void toyota_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - - int bus = GET_BUS(to_push); +static uint8_t toyota_compute_checksum(CAN_FIFOMailBox_TypeDef *to_push) { int addr = GET_ADDR(to_push); + int len = GET_LEN(to_push); + uint8_t checksum = (uint8_t)(addr) + (uint8_t)((unsigned int)(addr) >> 8U) + (uint8_t)(len); + for (int i = 0; i < (len - 1); i++) { + checksum += (uint8_t)GET_BYTE(to_push, i); + } + return checksum; +} - // get eps motor torque (0.66 factor in dbc) - if (addr == 0x260) { - int torque_meas_new = (GET_BYTE(to_push, 5) << 8) | GET_BYTE(to_push, 6); - torque_meas_new = to_signed(torque_meas_new, 16); +static uint8_t toyota_get_checksum(CAN_FIFOMailBox_TypeDef *to_push) { + int checksum_byte = GET_LEN(to_push) - 1; + return (uint8_t)(GET_BYTE(to_push, checksum_byte)); +} - // scale by dbc_factor - torque_meas_new = (torque_meas_new * toyota_dbc_eps_torque_factor) / 100; +static int toyota_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - // update array of sample - update_sample(&toyota_torque_meas, torque_meas_new); + bool valid = addr_safety_check(to_push, toyota_rx_checks, TOYOTA_RX_CHECKS_LEN, + toyota_get_checksum, toyota_compute_checksum, NULL); + if (valid) { + int bus = GET_BUS(to_push); + int addr = GET_ADDR(to_push); - // increase torque_meas by 1 to be conservative on rounding - toyota_torque_meas.min--; - toyota_torque_meas.max++; - } + // get eps motor torque (0.66 factor in dbc) + if (addr == 0x260) { + int torque_meas_new = (GET_BYTE(to_push, 5) << 8) | GET_BYTE(to_push, 6); + torque_meas_new = to_signed(torque_meas_new, 16); + + // scale by dbc_factor + torque_meas_new = (torque_meas_new * toyota_dbc_eps_torque_factor) / 100; + + // update array of sample + update_sample(&toyota_torque_meas, torque_meas_new); - // enter controls on rising edge of ACC, exit controls on ACC off - if (addr == 0x1D2) { - // 5th bit is CRUISE_ACTIVE - int cruise_engaged = GET_BYTE(to_push, 0) & 0x20; - if (!cruise_engaged) { - controls_allowed = 0; + // increase torque_meas by 1 to be conservative on rounding + toyota_torque_meas.min--; + toyota_torque_meas.max++; } - if (cruise_engaged && !toyota_cruise_engaged_last) { - controls_allowed = 1; + + // enter controls on rising edge of ACC, exit controls on ACC off + if (addr == 0x1D2) { + // 5th bit is CRUISE_ACTIVE + int cruise_engaged = GET_BYTE(to_push, 0) & 0x20; + if (!cruise_engaged) { + controls_allowed = 0; + } + if (cruise_engaged && !toyota_cruise_engaged_last) { + controls_allowed = 1; + } + toyota_cruise_engaged_last = cruise_engaged; } - toyota_cruise_engaged_last = cruise_engaged; - } - // exit controls on rising edge of interceptor gas press - if (addr == 0x201) { - gas_interceptor_detected = 1; - int gas_interceptor = GET_INTERCEPTOR(to_push); - if ((gas_interceptor > TOYOTA_GAS_INTERCEPTOR_THRESHOLD) && - (gas_interceptor_prev <= TOYOTA_GAS_INTERCEPTOR_THRESHOLD) && - long_controls_allowed) { - controls_allowed = 0; + // exit controls on rising edge of interceptor gas press + if (addr == 0x201) { + gas_interceptor_detected = 1; + int gas_interceptor = GET_INTERCEPTOR(to_push); + if ((gas_interceptor > TOYOTA_GAS_INTERCEPTOR_THRESHOLD) && + (gas_interceptor_prev <= TOYOTA_GAS_INTERCEPTOR_THRESHOLD)) { + controls_allowed = 0; + } + gas_interceptor_prev = gas_interceptor; } - gas_interceptor_prev = gas_interceptor; - } - // exit controls on rising edge of gas press - if (addr == 0x2C1) { - int gas = GET_BYTE(to_push, 6) & 0xFF; - if ((gas > 0) && (toyota_gas_prev == 0) && !gas_interceptor_detected && long_controls_allowed) { - controls_allowed = 0; + // exit controls on rising edge of gas press + if (addr == 0x2C1) { + int gas = GET_BYTE(to_push, 6) & 0xFF; + if ((gas > 0) && (toyota_gas_prev == 0) && !gas_interceptor_detected) { + controls_allowed = 0; + } + toyota_gas_prev = gas; } - toyota_gas_prev = gas; - } - // 0x2E4 is lkas cmd. If it is on bus 0, then relay is unexpectedly closed - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (addr == 0x2E4) && (bus == 0)) { - relay_malfunction = true; + // 0x2E4 is lkas cmd. If it is on bus 0, then relay is unexpectedly closed + if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (addr == 0x2E4) && (bus == 0)) { + relay_malfunction = true; + } } + return valid; } static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { @@ -103,7 +127,7 @@ static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int addr = GET_ADDR(to_send); int bus = GET_BUS(to_send); - if (!addr_allowed(addr, bus, TOYOTA_TX_MSGS, sizeof(TOYOTA_TX_MSGS)/sizeof(TOYOTA_TX_MSGS[0]))) { + if (!msg_allowed(addr, bus, TOYOTA_TX_MSGS, sizeof(TOYOTA_TX_MSGS)/sizeof(TOYOTA_TX_MSGS[0]))) { tx = 0; } @@ -116,7 +140,7 @@ static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { // GAS PEDAL: safety check if (addr == 0x200) { - if (!controls_allowed || !long_controls_allowed) { + if (!controls_allowed) { if (GET_BYTE(to_send, 0) || GET_BYTE(to_send, 1)) { tx = 0; } @@ -127,7 +151,7 @@ static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { if (addr == 0x343) { int desired_accel = (GET_BYTE(to_send, 0) << 8) | GET_BYTE(to_send, 1); desired_accel = to_signed(desired_accel, 16); - if (!controls_allowed || !long_controls_allowed) { + if (!controls_allowed) { if (desired_accel != 0) { tx = 0; } @@ -210,7 +234,7 @@ static int toyota_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { int is_lkas_msg = ((addr == 0x2E4) || (addr == 0x412) || (addr == 0x191)); // in TSS2 the camera does ACC as well, so filter 0x343 int is_acc_msg = (addr == 0x343); - int block_msg = is_lkas_msg || (is_acc_msg && long_controls_allowed); + int block_msg = is_lkas_msg || is_acc_msg; if (!block_msg) { bus_fwd = 0; } @@ -225,4 +249,6 @@ const safety_hooks toyota_hooks = { .tx = toyota_tx_hook, .tx_lin = nooutput_tx_lin_hook, .fwd = toyota_fwd_hook, + .addr_check = toyota_rx_checks, + .addr_check_len = sizeof(toyota_rx_checks)/sizeof(toyota_rx_checks[0]), }; diff --git a/panda/board/safety/safety_toyota_ipas.h b/panda/board/safety/safety_toyota_ipas.h index d5833e45db..e9515658cd 100644 --- a/panda/board/safety/safety_toyota_ipas.h +++ b/panda/board/safety/safety_toyota_ipas.h @@ -31,9 +31,9 @@ uint32_t ts_angle_last = 0; int controls_allowed_last = 0; -static void toyota_ipas_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { +static int toyota_ipas_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { // check standard toyota stuff as well - toyota_rx_hook(to_push); + bool valid = toyota_rx_hook(to_push); int addr = GET_ADDR(to_push); @@ -95,6 +95,7 @@ static void toyota_ipas_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { (ipas_state==5))) { controls_allowed = 0; } + return valid; } static int toyota_ipas_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { diff --git a/panda/board/safety/safety_volkswagen.h b/panda/board/safety/safety_volkswagen.h index c16e559ce1..4b01fd4bcd 100644 --- a/panda/board/safety/safety_volkswagen.h +++ b/panda/board/safety/safety_volkswagen.h @@ -17,13 +17,22 @@ const int VOLKSWAGEN_DRIVER_TORQUE_FACTOR = 3; // MSG_GRA_ACC_01 is allowed on bus 0 and 2 to keep compatibility with gateway and camera integration const AddrBus VOLKSWAGEN_TX_MSGS[] = {{MSG_HCA_01, 0}, {MSG_GRA_ACC_01, 0}, {MSG_GRA_ACC_01, 2}, {MSG_LDW_02, 0}}; -struct sample_t volkswagen_torque_driver; // last few driver torques measured +// TODO: do checksum and counter checks +AddrCheckStruct volkswagen_rx_checks[] = { + {.addr = {MSG_EPS_01}, .bus = 0, .expected_timestep = 10000U}, + {.addr = {MSG_ACC_06}, .bus = 0, .expected_timestep = 20000U}, + {.addr = {MSG_MOTOR_20}, .bus = 0, .expected_timestep = 20000U}, +}; + +const int VOLKSWAGEN_RX_CHECK_LEN = sizeof(volkswagen_rx_checks) / sizeof(volkswagen_rx_checks[0]); + +struct sample_t volkswagen_torque_driver; // last few driver torques measured int volkswagen_rt_torque_last = 0; int volkswagen_desired_torque_last = 0; uint32_t volkswagen_ts_last = 0; int volkswagen_gas_prev = 0; -static void volkswagen_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { +static int volkswagen_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { int bus = GET_BUS(to_push); int addr = GET_ADDR(to_push); @@ -50,7 +59,7 @@ static void volkswagen_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { // exit controls on rising edge of gas press. Bits [12-20) if (addr == MSG_MOTOR_20) { int gas = (GET_BYTES_04(to_push) >> 12) & 0xFF; - if ((gas > 0) && (volkswagen_gas_prev == 0) && long_controls_allowed) { + if ((gas > 0) && (volkswagen_gas_prev == 0)) { controls_allowed = 0; } volkswagen_gas_prev = gas; @@ -59,6 +68,7 @@ static void volkswagen_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == MSG_HCA_01)) { relay_malfunction = true; } + return 1; } static int volkswagen_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { @@ -66,7 +76,7 @@ static int volkswagen_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { int bus = GET_BUS(to_send); int tx = 1; - if (!addr_allowed(addr, bus, VOLKSWAGEN_TX_MSGS, sizeof(VOLKSWAGEN_TX_MSGS)/sizeof(VOLKSWAGEN_TX_MSGS[0]))) { + if (!msg_allowed(addr, bus, VOLKSWAGEN_TX_MSGS, sizeof(VOLKSWAGEN_TX_MSGS)/sizeof(VOLKSWAGEN_TX_MSGS[0]))) { tx = 0; } @@ -174,4 +184,6 @@ const safety_hooks volkswagen_hooks = { .tx = volkswagen_tx_hook, .tx_lin = nooutput_tx_lin_hook, .fwd = volkswagen_fwd_hook, + .addr_check = volkswagen_rx_checks, + .addr_check_len = sizeof(volkswagen_rx_checks) / sizeof(volkswagen_rx_checks[0]), }; diff --git a/panda/board/safety_declarations.h b/panda/board/safety_declarations.h index e192d74fb7..1a6a8dd21a 100644 --- a/panda/board/safety_declarations.h +++ b/panda/board/safety_declarations.h @@ -1,3 +1,6 @@ +const int MAX_WRONG_COUNTERS = 5; +const uint8_t MAX_MISSED_MSGS = 10U; + // sample struct that keeps 3 samples in memory struct sample_t { int values[6]; @@ -16,7 +19,23 @@ typedef struct { int bus; } AddrBus; -void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push); +// params and flags about checksum, counter and frequency checks for each monitored address +typedef struct { + // const params + const int addr[3]; // check either messages (e.g. honda steer). Array MUST terminate with a zero to know its length. + const int bus; // bus where to expect the addr. Temp hack: -1 means skip the bus check + const bool check_checksum; // true is checksum check is performed + const uint8_t max_counter; // maximum value of the counter. 0 means that the counter check is skipped + const uint32_t expected_timestep; // expected time between message updates [us] + // dynamic flags + bool valid_checksum; // true if and only if checksum check is passed + int wrong_counters; // counter of wrong counters, saturated between 0 and MAX_WRONG_COUNTERS + uint8_t last_counter; // last counter value + uint32_t last_timestamp; // micro-s + bool lagging; // true if and only if the time between updates is excessive +} AddrCheckStruct; + +int safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push); int safety_tx_hook(CAN_FIFOMailBox_TypeDef *to_send); int safety_tx_lin_hook(int lin_num, uint8_t *data, int len); uint32_t get_ts_elapsed(uint32_t ts, uint32_t ts_last); @@ -30,10 +49,20 @@ bool driver_limit_check(int val, int val_last, struct sample_t *val_driver, const int MAX_ALLOWANCE, const int DRIVER_FACTOR); bool rt_rate_limit_check(int val, int val_last, const int MAX_RT_DELTA); float interpolate(struct lookup_t xy, float x); -bool addr_allowed(int addr, int bus, const AddrBus addr_list[], int len); +bool msg_allowed(int addr, int bus, const AddrBus addr_list[], int len); +int get_addr_check_index(CAN_FIFOMailBox_TypeDef *to_push, AddrCheckStruct addr_list[], const int len); +void update_counter(AddrCheckStruct addr_list[], int index, uint8_t counter); +void update_addr_timestamp(AddrCheckStruct addr_list[], int index); +bool is_msg_valid(AddrCheckStruct addr_list[], int index); +bool addr_safety_check(CAN_FIFOMailBox_TypeDef *to_push, + AddrCheckStruct *addr_check, + const int addr_check_len, + uint8_t (*get_checksum)(CAN_FIFOMailBox_TypeDef *to_push), + uint8_t (*compute_checksum)(CAN_FIFOMailBox_TypeDef *to_push), + uint8_t (*get_counter)(CAN_FIFOMailBox_TypeDef *to_push)); typedef void (*safety_hook_init)(int16_t param); -typedef void (*rx_hook)(CAN_FIFOMailBox_TypeDef *to_push); +typedef int (*rx_hook)(CAN_FIFOMailBox_TypeDef *to_push); typedef int (*tx_hook)(CAN_FIFOMailBox_TypeDef *to_send); typedef int (*tx_lin_hook)(int lin_num, uint8_t *data, int len); typedef int (*fwd_hook)(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd); @@ -44,17 +73,18 @@ typedef struct { tx_hook tx; tx_lin_hook tx_lin; fwd_hook fwd; + AddrCheckStruct *addr_check; + const int addr_check_len; } safety_hooks; +void safety_tick(const safety_hooks *hooks); + // This can be set by the safety hooks bool controls_allowed = false; bool relay_malfunction = false; bool gas_interceptor_detected = false; int gas_interceptor_prev = 0; -// This is set by USB command 0xdf -bool long_controls_allowed = true; - // time since safety mode has been changed uint32_t safety_mode_cnt = 0U; // allow 1s of transition timeout after relay changes state before assessing malfunctioning diff --git a/panda/board/spi_flasher.h b/panda/board/spi_flasher.h index fbdbab8a61..1c703516ac 100644 --- a/panda/board/spi_flasher.h +++ b/panda/board/spi_flasher.h @@ -65,11 +65,13 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) // so it's blocked over wifi switch (setup->b.wValue.w) { case 0: - #ifdef ALLOW_DEBUG + // TODO: put this back when it's no longer a "devkit" + //#ifdef ALLOW_DEBUG + #if 1 if (hardwired) { #else - // no more bootstub on UNO - if (hardwired && hw_type != HW_TYPE_UNO) { + // no more bootstub on UNO once OTP block is flashed + if (hardwired && ((hw_type != HW_TYPE_UNO) || (!is_provisioned()))) { #endif puts("-> entering bootloader\n"); enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; diff --git a/panda/drivers/windows/ECUsim CLI/ECUsim CLI.vcxproj b/panda/drivers/windows/ECUsim CLI/ECUsim CLI.vcxproj index 4b9de8c442..b77937ce7c 100644 --- a/panda/drivers/windows/ECUsim CLI/ECUsim CLI.vcxproj +++ b/panda/drivers/windows/ECUsim CLI/ECUsim CLI.vcxproj @@ -22,32 +22,32 @@ {D99E2FCD-21A4-4065-949A-31E34E0E69D1} Win32Proj ECUsimCLI - 10.0.16299.0 + 10.0 Application true - v141 + v142 Unicode Application false - v141 + v142 true Unicode Application true - v141 + v142 Unicode Application false - v141 + v142 true Unicode diff --git a/panda/drivers/windows/ECUsim DLL/ECUsim DLL.vcxproj b/panda/drivers/windows/ECUsim DLL/ECUsim DLL.vcxproj index 93d75c14be..b9a085a6c0 100644 --- a/panda/drivers/windows/ECUsim DLL/ECUsim DLL.vcxproj +++ b/panda/drivers/windows/ECUsim DLL/ECUsim DLL.vcxproj @@ -22,32 +22,32 @@ {96E0E646-EE76-444D-9A77-A0CD7F781DEB} Win32Proj ECUsimDLL - 10.0.16299.0 + 10.0 DynamicLibrary true - v141 + v142 Unicode DynamicLibrary false - v141 + v142 true Unicode DynamicLibrary true - v141 + v142 Unicode DynamicLibrary false - v141 + v142 true Unicode diff --git a/panda/drivers/windows/README.md b/panda/drivers/windows/README.md index 06c7a51101..786a3187f1 100644 --- a/panda/drivers/windows/README.md +++ b/panda/drivers/windows/README.md @@ -20,7 +20,7 @@ ______/\\\\\\\\\\\____/\\\\\\\\\_______/\\\\\\\\\\\\\\\______/\\\\\\\\\\________ # Installing J2534 driver: -[Download](https://github.com/commaai/panda/files/1742802/panda.J2534.driver.install.zip) +[Download](https://github.com/commaai/panda/files/4017364/panda.J2534.driver.install.zip) Depending on what version of windows you are on, you may need to separately install the WinUSB driver (see next section). diff --git a/panda/drivers/windows/panda/panda.vcxproj b/panda/drivers/windows/panda/panda.vcxproj index 22879c7cae..ccda7a6b23 100644 --- a/panda/drivers/windows/panda/panda.vcxproj +++ b/panda/drivers/windows/panda/panda.vcxproj @@ -22,32 +22,32 @@ {5528AEFB-638D-49AF-B9D4-965154E7D531} Win32Proj panda - 10.0.16299.0 + 10.0 DynamicLibrary true - v141 + v142 Unicode DynamicLibrary false - v141 + v142 true Unicode DynamicLibrary true - v141 + v142 Unicode DynamicLibrary false - v141 + v142 true Unicode diff --git a/panda/drivers/windows/pandaJ2534DLL Test/pandaJ2534DLL Test.vcxproj b/panda/drivers/windows/pandaJ2534DLL Test/pandaJ2534DLL Test.vcxproj index f19c743461..bab867ab49 100644 --- a/panda/drivers/windows/pandaJ2534DLL Test/pandaJ2534DLL Test.vcxproj +++ b/panda/drivers/windows/pandaJ2534DLL Test/pandaJ2534DLL Test.vcxproj @@ -14,21 +14,21 @@ {7912F978-B48C-4C5D-8BFD-5D1E22158E47} Win32Proj pandaJ2534DLLTest - 10.0.16299.0 + 10.0 Tests DynamicLibrary true - v141 + v142 Unicode false DynamicLibrary false - v141 + v142 true Unicode false diff --git a/panda/drivers/windows/pandaJ2534DLL/MessageRx.h b/panda/drivers/windows/pandaJ2534DLL/MessageRx.h index 2af24364ff..e22278d4d0 100644 --- a/panda/drivers/windows/pandaJ2534DLL/MessageRx.h +++ b/panda/drivers/windows/pandaJ2534DLL/MessageRx.h @@ -21,7 +21,7 @@ public: } this->next_part = (this->next_part + 1) % 0x10; - unsigned int payload_len = MIN(expected_size - msg.size(), max_packet_size); + unsigned int payload_len = min(expected_size - msg.size(), max_packet_size); if (piece.size() < payload_len) { //A frame was received that could have held more data. //No examples of this protocol show that happening, so diff --git a/panda/drivers/windows/pandaJ2534DLL/PandaJ2534Device.cpp b/panda/drivers/windows/pandaJ2534DLL/PandaJ2534Device.cpp index 19ae43b0d7..e250ded7b4 100644 --- a/panda/drivers/windows/pandaJ2534DLL/PandaJ2534Device.cpp +++ b/panda/drivers/windows/pandaJ2534DLL/PandaJ2534Device.cpp @@ -170,7 +170,7 @@ DWORD PandaJ2534Device::msg_tx_thread() { } else { //Ran out of things that need to be sent now. Sleep! auto time_diff = std::chrono::duration_cast (this->task_queue.front()->expire - std::chrono::steady_clock::now()); - sleepDuration = MAX(1, time_diff.count()); + sleepDuration = max(1, time_diff.count()); goto break_flow_ctrl_loop; } } diff --git a/panda/drivers/windows/pandaJ2534DLL/pandaJ2534DLL.vcxproj b/panda/drivers/windows/pandaJ2534DLL/pandaJ2534DLL.vcxproj index fd5eac56dd..bc9d145e0f 100644 --- a/panda/drivers/windows/pandaJ2534DLL/pandaJ2534DLL.vcxproj +++ b/panda/drivers/windows/pandaJ2534DLL/pandaJ2534DLL.vcxproj @@ -14,19 +14,19 @@ {A2BB18A5-F26B-48D6-BBB5-B83D64473C77} Win32Proj pandaJ2534DLL - 10.0.16299.0 + 10.0 DynamicLibrary true - v141 + v142 Unicode DynamicLibrary false - v141 + v142 true Unicode diff --git a/panda/drivers/windows/panda_playground/panda_playground.vcxproj b/panda/drivers/windows/panda_playground/panda_playground.vcxproj index 2b5f3120c3..9174d7e36d 100644 --- a/panda/drivers/windows/panda_playground/panda_playground.vcxproj +++ b/panda/drivers/windows/panda_playground/panda_playground.vcxproj @@ -22,32 +22,32 @@ {691DB635-C272-4B98-897E-0505B970DCA9} Win32Proj panda_playground - 10.0.16299.0 + 10.0 Application true - v141 + v142 Unicode Application false - v141 + v142 true Unicode Application true - v141 + v142 Unicode Application false - v141 + v142 true Unicode diff --git a/panda/drivers/windows/panda_shared/panda.h b/panda/drivers/windows/panda_shared/panda.h index 117fc92760..541d30584f 100644 --- a/panda/drivers/windows/panda_shared/panda.h +++ b/panda/drivers/windows/panda_shared/panda.h @@ -39,7 +39,7 @@ namespace panda { typedef enum _PANDA_SAFETY_MODE : uint16_t { SAFETY_SILENT = 0, - SAFETY_HONDA = 1, + SAFETY_HONDA_NIDEC = 1, SAFETY_ALLOUTPUT = 17, } PANDA_SAFETY_MODE; @@ -78,13 +78,23 @@ namespace panda { #pragma pack(1) typedef struct _PANDA_HEALTH { + uint32_t uptime; uint32_t voltage; uint32_t current; - uint8_t started; + uint32_t can_rx_errs; + uint32_t can_send_errs; + uint32_t can_fwd_errs; + uint32_t gmlan_send_errs; + uint32_t faults; + uint8_t ignition_line; + uint8_t ignition_can; uint8_t controls_allowed; uint8_t gas_interceptor_detected; - uint8_t started_signal_detected; - uint8_t started_alt; + uint8_t car_harness_status; + uint8_t usb_power_mode; + uint8_t safety_mode; + uint8_t fault_status; + uint8_t power_save_enabled; } PANDA_HEALTH, *PPANDA_HEALTH; typedef struct _PANDA_CAN_MSG { diff --git a/panda/drivers/windows/redist/vscruntimeinfo.nsh.sample b/panda/drivers/windows/redist/vscruntimeinfo.nsh.sample index 3e74ab1d9c..f23968d744 100644 --- a/panda/drivers/windows/redist/vscruntimeinfo.nsh.sample +++ b/panda/drivers/windows/redist/vscruntimeinfo.nsh.sample @@ -7,7 +7,7 @@ ;An list of the registry keys has been maintained here: https://stackoverflow.com/a/34209692/627525 -;Microsoft Visual C++ 2015 Redistributable (x86) - 14.0.24123 -!define VCRuntimeRegKey "SOFTWARE\Classes\Installer\Dependencies\{206898cc-4b41-4d98-ac28-9f9ae57f91fe}" +;Microsoft Visual C++ 2015-2019 Redistributable (x86) - 14.24.28127 +!define VCRuntimeRegKey "Installer\Dependencies\VC,redist.x86,x86,14.24,bundle" !define VCRuntimeSetupPath "redist\" !define VCRuntimeSetupFile "vc_redist.x86.exe" \ No newline at end of file diff --git a/panda/python/__init__.py b/panda/python/__init__.py index 8f4ae29181..ea8dea13d9 100644 --- a/panda/python/__init__.py +++ b/panda/python/__init__.py @@ -23,14 +23,14 @@ BASEDIR = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../") DEBUG = os.getenv("PANDADEBUG") is not None # *** wifi mode *** -def build_st(target, mkfile="Makefile"): +def build_st(target, mkfile="Makefile", clean=True): from panda import BASEDIR - cmd = 'cd %s && make -f %s clean && make -f %s %s >/dev/null' % (os.path.join(BASEDIR, "board"), mkfile, mkfile, target) + + clean_cmd = "make -f %s clean" % mkfile if clean else ":" + cmd = 'cd %s && %s && make -f %s %s' % (os.path.join(BASEDIR, "board"), clean_cmd, mkfile, target) try: _ = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) except subprocess.CalledProcessError: - #output = exception.output - #returncode = exception.returncode raise def parse_can_buffer(dat): @@ -111,11 +111,11 @@ class Panda(object): # matches cereal.car.CarParams.SafetyModel SAFETY_SILENT = 0 - SAFETY_HONDA = 1 + SAFETY_HONDA_NIDEC = 1 SAFETY_TOYOTA = 2 SAFETY_ELM327 = 3 SAFETY_GM = 4 - SAFETY_HONDA_BOSCH = 5 + SAFETY_HONDA_BOSCH_GIRAFFE = 5 SAFETY_FORD = 6 SAFETY_CADILLAC = 7 SAFETY_HYUNDAI = 8 @@ -128,6 +128,7 @@ class Panda(object): SAFETY_ALLOUTPUT = 17 SAFETY_GM_ASCM = 18 SAFETY_NOOUTPUT = 19 + SAFETY_HONDA_BOSCH_HARNESS = 20 SERIAL_DEBUG = 0 SERIAL_ESP = 1 @@ -346,25 +347,26 @@ class Panda(object): # ******************* health ******************* def health(self): - dat = self._handle.controlRead(Panda.REQUEST_IN, 0xd2, 0, 0, 37) - a = struct.unpack("IIIIIIIBBBBBBBBB", dat) + dat = self._handle.controlRead(Panda.REQUEST_IN, 0xd2, 0, 0, 41) + a = struct.unpack("IIIIIIIIBBBBBBBBB", dat) return { "uptime": a[0], "voltage": a[1], "current": a[2], - "can_send_errs": a[3], - "can_fwd_errs": a[4], - "gmlan_send_errs": a[5], - "faults": a[6], - "ignition_line": a[7], - "ignition_can": a[8], - "controls_allowed": a[9], - "gas_interceptor_detected": a[10], - "car_harness_status": a[11], - "usb_power_mode": a[12], - "safety_mode": a[13], - "fault_status": a[14], - "power_save_enabled": a[15] + "can_rx_errs": a[3], + "can_send_errs": a[4], + "can_fwd_errs": a[5], + "gmlan_send_errs": a[6], + "faults": a[7], + "ignition_line": a[8], + "ignition_can": a[9], + "controls_allowed": a[10], + "gas_interceptor_detected": a[11], + "car_harness_status": a[12], + "usb_power_mode": a[13], + "safety_mode": a[14], + "fault_status": a[15], + "power_save_enabled": a[16] } # ******************* control ******************* @@ -388,7 +390,7 @@ class Panda(object): def get_signature(self): part_1 = self._handle.controlRead(Panda.REQUEST_IN, 0xd3, 0, 0, 0x40) part_2 = self._handle.controlRead(Panda.REQUEST_IN, 0xd4, 0, 0, 0x40) - return part_1 + part_2 + return bytes(part_1 + part_2) def get_type(self): return self._handle.controlRead(Panda.REQUEST_IN, 0xc1, 0, 0, 0x40) diff --git a/panda/python/uds.py b/panda/python/uds.py index ee9e9ea667..96d07e1a72 100644 --- a/panda/python/uds.py +++ b/panda/python/uds.py @@ -268,17 +268,19 @@ _negative_response_codes = { 0x93: 'voltage too low', } + class CanClient(): - def __init__(self, can_send: Callable[[Tuple[int, bytes, int]], None], can_recv: Callable[[], List[Tuple[int, int, bytes, int]]], tx_addr: int, rx_addr: int, bus: int, debug: bool=False): + def __init__(self, can_send: Callable[[Tuple[int, bytes, int]], None], can_recv: Callable[[], List[Tuple[int, int, bytes, int]]], tx_addr: int, rx_addr: int, bus: int, sub_addr: int=None, debug: bool=False): self.tx = can_send self.rx = can_recv self.tx_addr = tx_addr self.rx_addr = rx_addr + self.sub_addr = sub_addr self.bus = bus self.debug = debug def _recv_filter(self, bus, addr): - # handle functionl addresses (switch to first addr to respond) + # handle functional addresses (switch to first addr to respond) if self.tx_addr == 0x7DF: is_response = addr >= 0x7E8 and addr <= 0x7EF if is_response: @@ -303,8 +305,14 @@ class CanClient(): else: for rx_addr, rx_ts, rx_data, rx_bus in msgs or []: if self._recv_filter(rx_bus, rx_addr) and len(rx_data) > 0: - rx_data = bytes(rx_data) # convert bytearray to bytes + rx_data = bytes(rx_data) # convert bytearray to bytes + if self.debug: print(f"CAN-RX: {hex(rx_addr)} - 0x{bytes.hex(rx_data)}") + + # Cut off sub addr in first byte + if self.sub_addr is not None: + rx_data = rx_data[1:] + msg_array.append(rx_data) # break when non-full buffer is processed if len(msgs) < 254: @@ -316,15 +324,23 @@ class CanClient(): if delay and not first: if self.debug: print(f"CAN-TX: delay - {delay}") time.sleep(delay) + + if self.sub_addr is not None: + msg = bytes([self.sub_addr]) + msg + if self.debug: print(f"CAN-TX: {hex(self.tx_addr)} - 0x{bytes.hex(msg)}") + assert len(msg) <= 8 + self.tx(self.tx_addr, msg, self.bus) first = False + class IsoTpMessage(): - def __init__(self, can_client: CanClient, timeout: float=1, debug: bool=False): + def __init__(self, can_client: CanClient, timeout: float=1, debug: bool=False, max_len: int=8): self._can_client = can_client self.timeout = timeout self.debug = debug + self.max_len = max_len def send(self, dat: bytes) -> None: # throw away any stale data @@ -347,12 +363,12 @@ class IsoTpMessage(): if self.tx_len < 8: # single frame (send all bytes) if self.debug: print("ISO-TP: TX - single frame") - msg = (bytes([self.tx_len]) + self.tx_dat).ljust(8, b"\x00") + msg = (bytes([self.tx_len]) + self.tx_dat).ljust(self.max_len, b"\x00") self.tx_done = True else: # first frame (send first 6 bytes) if self.debug: print("ISO-TP: TX - first frame") - msg = (struct.pack("!H", 0x1000 | self.tx_len) + self.tx_dat[:6]).ljust(8, b"\x00") + msg = (struct.pack("!H", 0x1000 | self.tx_len) + self.tx_dat[:6]).ljust(self.max_len, b"\x00") self._can_client.send([msg]) def recv(self) -> bytes: @@ -390,7 +406,7 @@ class IsoTpMessage(): if self.debug: print(f"ISO-TP: RX - first frame - idx={self.rx_idx} done={self.rx_done}") if self.debug: print(f"ISO-TP: TX - flow control continue") # send flow control message (send all bytes) - msg = b"\x30\x00\x00".ljust(8, b"\x00") + msg = b"\x30\x00\x00".ljust(self.max_len, b"\x00") self._can_client.send([msg]) return @@ -400,7 +416,7 @@ class IsoTpMessage(): self.rx_idx += 1 assert self.rx_idx & 0xF == rx_data[0] & 0xF, "isotp - rx: invalid consecutive frame index" rx_size = self.rx_len - len(self.rx_dat) - self.rx_dat += rx_data[1:1+min(rx_size, 7)] + self.rx_dat += rx_data[1:1+rx_size] if self.rx_len == len(self.rx_dat): self.rx_done = True if self.debug: print(f"ISO-TP: RX - consecutive frame - idx={self.rx_idx} done={self.rx_done}") @@ -417,15 +433,17 @@ class IsoTpMessage(): # scale is 1 milliseconds if first bit == 0, 100 micro seconds if first bit == 1 delay_div = 1000. if rx_data[2] & 0x80 == 0 else 10000. delay_sec = delay_ts / delay_div + # first frame = 6 bytes, each consecutive frame = 7 bytes - start = 6 + self.tx_idx * 7 + num_bytes = self.max_len - 1 + start = 6 + self.tx_idx * num_bytes count = rx_data[1] - end = start + count * 7 if count > 0 else self.tx_len + end = start + count * num_bytes if count > 0 else self.tx_len tx_msgs = [] - for i in range(start, end, 7): + for i in range(start, end, num_bytes): self.tx_idx += 1 # consecutive tx messages - msg = (bytes([0x20 | (self.tx_idx & 0xF)]) + self.tx_dat[i:i+7]).ljust(8, b"\x00") + msg = (bytes([0x20 | (self.tx_idx & 0xF)]) + self.tx_dat[i:i+num_bytes]).ljust(self.max_len, b"\x00") tx_msgs.append(msg) # send consecutive tx messages self._can_client.send(tx_msgs, delay=delay_sec) @@ -445,13 +463,14 @@ def get_rx_addr_for_tx_addr(tx_addr): if tx_addr < 0xFFF8: # standard 11 bit response addr (add 8) return tx_addr + 8 - + if tx_addr > 0x10000000 and tx_addr < 0xFFFFFFFF: # standard 29 bit response addr (flip last two bytes) return (tx_addr & 0xFFFF0000) + (tx_addr<<8 & 0xFF00) + (tx_addr>>8 & 0xFF) raise ValueError("invalid tx_addr: {}".format(tx_addr)) + class UdsClient(): def __init__(self, panda, tx_addr: int, rx_addr: int=None, bus: int=0, timeout: float=1, debug: bool=False): self.bus = bus @@ -714,7 +733,7 @@ class UdsClient(): if dtc_report_type == DTC_REPORT_TYPE.NUMBER_OF_DTC_BY_SEVERITY_MASK_RECORD or \ dtc_report_type == DTC_REPORT_TYPE.DTC_BY_SEVERITY_MASK_RECORD: data += bytes([dtc_severity_mask_type, dtc_status_mask_type]) - + resp = self._uds_request(SERVICE_TYPE.READ_DTC_INFORMATION, subfunction=dtc_report_type, data=data) # TODO: parse response diff --git a/panda/tests/automated/8_gps.py b/panda/tests/automated/8_gps.py new file mode 100644 index 0000000000..fc387c9969 --- /dev/null +++ b/panda/tests/automated/8_gps.py @@ -0,0 +1,23 @@ +import time +from panda import PandaSerial +from .helpers import reset_pandas, test_all_gps_pandas, panda_connect_and_init + +# Reset the pandas before running tests +def aaaa_reset_before_tests(): + reset_pandas() + +@test_all_gps_pandas +@panda_connect_and_init +def test_gps_version(p): + serial = PandaSerial(p, 1, 9600) + # Reset and check twice to make sure the enabling works + for i in range(2): + # Reset GPS + p.set_esp_power(0) + time.sleep(0.5) + p.set_esp_power(1) + time.sleep(1) + + # Read startup message and check if version is contained + dat = serial.read(0x1000) # Read one full panda DMA buffer. This should include the startup message + assert b'HPG 1.40ROV' in dat \ No newline at end of file diff --git a/panda/tests/automated/helpers.py b/panda/tests/automated/helpers.py index 78a9287c10..6b963e954f 100644 --- a/panda/tests/automated/helpers.py +++ b/panda/tests/automated/helpers.py @@ -1,9 +1,5 @@ -import os -import sys import time import random -import subprocess -import requests import _thread import faulthandler from functools import wraps @@ -19,6 +15,7 @@ SPEED_GMLAN = 33.3 BUS_SPEEDS = [(0, SPEED_NORMAL), (1, SPEED_NORMAL), (2, SPEED_NORMAL), (3, SPEED_GMLAN)] TIMEOUT = 30 GEN2_HW_TYPES = [Panda.HW_TYPE_BLACK_PANDA, Panda.HW_TYPE_UNO] +GPS_HW_TYPES = [Panda.HW_TYPE_GREY_PANDA, Panda.HW_TYPE_BLACK_PANDA, Panda.HW_TYPE_UNO] # Enable fault debug faulthandler.enable(all_threads=False) @@ -52,6 +49,9 @@ test_all_pandas = parameterized( test_all_gen2_pandas = parameterized( list(map(lambda x: x[0], filter(lambda x: x[1] in GEN2_HW_TYPES, _panda_serials))) ) +test_all_gps_pandas = parameterized( + list(map(lambda x: x[0], filter(lambda x: x[1] in GPS_HW_TYPES, _panda_serials))) + ) test_white_and_grey = parameterized([ param(panda_type=Panda.HW_TYPE_WHITE_PANDA), param(panda_type=Panda.HW_TYPE_GREY_PANDA) diff --git a/panda/tests/automated/wifi_helpers.py b/panda/tests/automated/wifi_helpers.py index de9b224a1a..d3be8ff867 100644 --- a/panda/tests/automated/wifi_helpers.py +++ b/panda/tests/automated/wifi_helpers.py @@ -1,4 +1,9 @@ import os +import sys +import time +import subprocess +import requests +from panda import Panda FNULL = open(os.devnull, 'w') def _connect_wifi(dongle_id, pw, insecure_okay=False): ssid = "panda-" + dongle_id diff --git a/panda/tests/misra/suppressions.txt b/panda/tests/misra/suppressions.txt index e0a270831a..0a479bc586 100644 --- a/panda/tests/misra/suppressions.txt +++ b/panda/tests/misra/suppressions.txt @@ -1,8 +1,10 @@ -# Advisory: union types can be used -misra.19.2 # Advisory: casting from void pointer to type pointer is ok. Done by STM libraries as well misra.11.4 # Advisory: casting from void pointer to type pointer is ok. Done by STM libraries as well misra.11.5 +# Advisory: as stated in the Misra document, use of goto statements in accordance to 15.2 and 15.3 is ok +misra.15.1 +# Advisory: union types can be used +misra.19.2 # Required: it's ok re-defining potentially reserved Macro names. Not likely to cause confusion misra.21.1 diff --git a/panda/tests/safety/common.py b/panda/tests/safety/common.py index 99f7237921..63408ce430 100644 --- a/panda/tests/safety/common.py +++ b/panda/tests/safety/common.py @@ -1,5 +1,7 @@ from panda.tests.safety import libpandasafety_py +MAX_WRONG_COUNTERS = 5 + def make_msg(bus, addr, length=8): to_send = libpandasafety_py.ffi.new('CAN_FIFOMailBox_TypeDef *') if addr >= 0x800: diff --git a/panda/tests/safety/libpandasafety_py.py b/panda/tests/safety/libpandasafety_py.py index 5b1bd28c9a..77131c1a3c 100644 --- a/panda/tests/safety/libpandasafety_py.py +++ b/panda/tests/safety/libpandasafety_py.py @@ -30,14 +30,10 @@ typedef struct uint32_t CNT; } TIM_TypeDef; -bool board_has_relay(void); - void set_controls_allowed(bool c); bool get_controls_allowed(void); void set_relay_malfunction(bool c); bool get_relay_malfunction(void); -void set_long_controls_allowed(bool c); -bool get_long_controls_allowed(void); void set_gas_interceptor_detected(bool c); bool get_gas_interceptor_detetcted(void); int get_gas_interceptor_prev(void); @@ -45,7 +41,7 @@ int get_hw_type(void); void set_timer(uint32_t t); void reset_angle_control(void); -void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_send); +int safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_send); int safety_tx_hook(CAN_FIFOMailBox_TypeDef *to_push); int safety_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd); int set_safety_hooks(uint16_t mode, int16_t param); @@ -64,8 +60,8 @@ bool get_honda_brake_pressed_prev(void); int get_honda_gas_prev(void); void set_honda_fwd_brake(bool); void set_honda_alt_brake_msg(bool); -void set_honda_bosch_hardware(bool); -int get_honda_bosch_hardware(void); +void set_honda_hw(int); +int get_honda_hw(void); void init_tests_cadillac(void); void set_cadillac_desired_torque_last(int t); diff --git a/panda/tests/safety/test.c b/panda/tests/safety/test.c index de12a4d046..59611d3131 100644 --- a/panda/tests/safety/test.c +++ b/panda/tests/safety/test.c @@ -47,11 +47,6 @@ TIM_TypeDef *TIM2 = &timer; // from main_declarations.h uint8_t hw_type = HW_TYPE_UNKNOWN; -// from board.h -bool board_has_relay(void) { - return hw_type == HW_TYPE_BLACK_PANDA || hw_type == HW_TYPE_UNO; -} - // from config.h #define MIN(a,b) \ ({ __typeof__ (a) _a = (a); \ @@ -86,10 +81,6 @@ void set_relay_malfunction(bool c){ relay_malfunction = c; } -void set_long_controls_allowed(bool c){ - long_controls_allowed = c; -} - void set_gas_interceptor_detected(bool c){ gas_interceptor_detected = c; } @@ -106,10 +97,6 @@ bool get_relay_malfunction(void){ return relay_malfunction; } -bool get_long_controls_allowed(void){ - return long_controls_allowed; -} - bool get_gas_interceptor_detected(void){ return gas_interceptor_detected; } @@ -257,12 +244,12 @@ void set_honda_alt_brake_msg(bool c){ honda_alt_brake_msg = c; } -void set_honda_bosch_hardware(bool c){ - honda_bosch_hardware = c; +void set_honda_hw(int c){ + honda_hw = c; } -int get_honda_bosch_hardware(void) { - return honda_bosch_hardware; +int get_honda_hw(void) { + return honda_hw; } void set_honda_fwd_brake(bool c){ diff --git a/panda/tests/safety/test_gm.py b/panda/tests/safety/test_gm.py index 99c15750c4..06872dede5 100644 --- a/panda/tests/safety/test_gm.py +++ b/panda/tests/safety/test_gm.py @@ -141,15 +141,10 @@ class TestGmSafety(unittest.TestCase): self.safety.safety_rx_hook(self._brake_msg(False)) def test_disengage_on_gas(self): - for long_controls_allowed in [0, 1]: - self.safety.set_long_controls_allowed(long_controls_allowed) - self.safety.set_controls_allowed(1) - self.safety.safety_rx_hook(self._gas_msg(True)) - if long_controls_allowed: - self.assertFalse(self.safety.get_controls_allowed()) - else: - self.assertTrue(self.safety.get_controls_allowed()) - self.safety.safety_rx_hook(self._gas_msg(False)) + self.safety.set_controls_allowed(1) + self.safety.safety_rx_hook(self._gas_msg(True)) + self.assertFalse(self.safety.get_controls_allowed()) + self.safety.safety_rx_hook(self._gas_msg(False)) def test_allow_engage_with_gas_pressed(self): self.safety.safety_rx_hook(self._gas_msg(True)) @@ -159,28 +154,22 @@ class TestGmSafety(unittest.TestCase): self.safety.safety_rx_hook(self._gas_msg(False)) def test_brake_safety_check(self): - for long_controls_allowed in [0, 1]: - self.safety.set_long_controls_allowed(long_controls_allowed) - for enabled in [0, 1]: - for b in range(0, 500): - self.safety.set_controls_allowed(enabled) - if abs(b) > MAX_BRAKE or ((not enabled or not long_controls_allowed) and b != 0): - self.assertFalse(self.safety.safety_tx_hook(self._send_brake_msg(b))) - else: - self.assertTrue(self.safety.safety_tx_hook(self._send_brake_msg(b))) - self.safety.set_long_controls_allowed(True) + for enabled in [0, 1]: + for b in range(0, 500): + self.safety.set_controls_allowed(enabled) + if abs(b) > MAX_BRAKE or (not enabled and b != 0): + self.assertFalse(self.safety.safety_tx_hook(self._send_brake_msg(b))) + else: + self.assertTrue(self.safety.safety_tx_hook(self._send_brake_msg(b))) def test_gas_safety_check(self): - for long_controls_allowed in [0, 1]: - self.safety.set_long_controls_allowed(long_controls_allowed) - for enabled in [0, 1]: - for g in range(0, 2**12-1): - self.safety.set_controls_allowed(enabled) - if abs(g) > MAX_GAS or ((not enabled or not long_controls_allowed) and g != MAX_REGEN): - self.assertFalse(self.safety.safety_tx_hook(self._send_gas_msg(g))) - else: - self.assertTrue(self.safety.safety_tx_hook(self._send_gas_msg(g))) - self.safety.set_long_controls_allowed(True) + for enabled in [0, 1]: + for g in range(0, 2**12-1): + self.safety.set_controls_allowed(enabled) + if abs(g) > MAX_GAS or (not enabled and g != MAX_REGEN): + self.assertFalse(self.safety.safety_tx_hook(self._send_gas_msg(g))) + else: + self.assertTrue(self.safety.safety_tx_hook(self._send_gas_msg(g))) def test_steer_safety_check(self): for enabled in [0, 1]: diff --git a/panda/tests/safety/test_honda.py b/panda/tests/safety/test_honda.py index f89e7a593f..87f7089304 100755 --- a/panda/tests/safety/test_honda.py +++ b/panda/tests/safety/test_honda.py @@ -3,36 +3,66 @@ import unittest import numpy as np from panda import Panda from panda.tests.safety import libpandasafety_py -from panda.tests.safety.common import test_relay_malfunction, make_msg, test_manually_enable_controls_allowed, test_spam_can_buses +from panda.tests.safety.common import test_relay_malfunction, make_msg, \ + test_manually_enable_controls_allowed, \ + test_spam_can_buses, MAX_WRONG_COUNTERS MAX_BRAKE = 255 INTERCEPTOR_THRESHOLD = 328 TX_MSGS = [[0xE4, 0], [0x194, 0], [0x1FA, 0], [0x200, 0], [0x30C, 0], [0x33D, 0]] +HONDA_N_HW = 0 +HONDA_BG_HW = 1 +HONDA_BH_HW = 2 + +def honda_checksum(msg, addr, len_msg): + checksum = 0 + while addr > 0: + checksum += addr + addr >>= 4 + for i in range (0, 2*len_msg): + if i < 8: + checksum += (msg.RDLR >> (4 * i)) + else: + checksum += (msg.RDHR >> (4 * (i - 8))) + return (8 - checksum) & 0xF + + class TestHondaSafety(unittest.TestCase): @classmethod def setUp(cls): cls.safety = libpandasafety_py.libpandasafety - cls.safety.set_safety_hooks(Panda.SAFETY_HONDA, 0) + cls.safety.set_safety_hooks(Panda.SAFETY_HONDA_NIDEC, 0) cls.safety.init_tests_honda() + cls.cnt_speed = 0 + cls.cnt_gas = 0 + cls.cnt_button = 0 def _speed_msg(self, speed): to_send = make_msg(0, 0x158) to_send[0].RDLR = speed + to_send[0].RDHR |= (self.cnt_speed % 4) << 28 + to_send[0].RDHR |= honda_checksum(to_send[0], 0x158, 8) << 24 + self.cnt_speed += 1 return to_send - def _button_msg(self, buttons, msg): - has_relay = self.safety.board_has_relay() - honda_bosch_hardware = self.safety.get_honda_bosch_hardware() - bus = 1 if has_relay and honda_bosch_hardware else 0 - to_send = make_msg(bus, msg) + def _button_msg(self, buttons, addr): + honda_hw = self.safety.get_honda_hw() + bus = 1 if honda_hw == HONDA_BH_HW else 0 + to_send = make_msg(bus, addr) to_send[0].RDLR = buttons << 5 + to_send[0].RDHR |= (self.cnt_button % 4) << 28 + to_send[0].RDHR |= honda_checksum(to_send[0], addr, 8) << 24 + self.cnt_button += 1 return to_send def _brake_msg(self, brake): to_send = make_msg(0, 0x17C) to_send[0].RDHR = 0x200000 if brake else 0 + to_send[0].RDHR |= (self.cnt_gas % 4) << 28 + to_send[0].RDHR |= honda_checksum(to_send[0], 0x17C, 8) << 24 + self.cnt_gas += 1 return to_send def _alt_brake_msg(self, brake): @@ -43,6 +73,9 @@ class TestHondaSafety(unittest.TestCase): def _gas_msg(self, gas): to_send = make_msg(0, 0x17C) to_send[0].RDLR = 1 if gas else 0 + to_send[0].RDHR |= (self.cnt_gas % 4) << 28 + to_send[0].RDHR |= honda_checksum(to_send[0], 0x17C, 8) << 24 + self.cnt_gas += 1 return to_send def _send_brake_msg(self, brake): @@ -63,6 +96,7 @@ class TestHondaSafety(unittest.TestCase): return to_send def test_spam_can_buses(self): + self.safety.set_honda_hw(HONDA_N_HW) test_spam_can_buses(self, TX_MSGS) def test_relay_malfunction(self): @@ -151,16 +185,10 @@ class TestHondaSafety(unittest.TestCase): self.safety.set_gas_interceptor_detected(False) def test_disengage_on_gas(self): - for long_controls_allowed in [0, 1]: - self.safety.set_long_controls_allowed(long_controls_allowed) - self.safety.safety_rx_hook(self._gas_msg(0)) - self.safety.set_controls_allowed(1) - self.safety.safety_rx_hook(self._gas_msg(1)) - if long_controls_allowed: - self.assertFalse(self.safety.get_controls_allowed()) - else: - self.assertTrue(self.safety.get_controls_allowed()) - self.safety.set_long_controls_allowed(True) + self.safety.safety_rx_hook(self._gas_msg(0)) + self.safety.set_controls_allowed(1) + self.safety.safety_rx_hook(self._gas_msg(1)) + self.assertFalse(self.safety.get_controls_allowed()) def test_allow_engage_with_gas_pressed(self): self.safety.safety_rx_hook(self._gas_msg(1)) @@ -169,17 +197,14 @@ class TestHondaSafety(unittest.TestCase): self.assertTrue(self.safety.get_controls_allowed()) def test_disengage_on_gas_interceptor(self): - for long_controls_allowed in [0, 1]: - for g in range(0, 0x1000): - self.safety.set_long_controls_allowed(long_controls_allowed) - self.safety.safety_rx_hook(self._send_interceptor_msg(0, 0x201)) - self.safety.set_controls_allowed(True) - self.safety.safety_rx_hook(self._send_interceptor_msg(g, 0x201)) - remain_enabled = (not long_controls_allowed or g <= INTERCEPTOR_THRESHOLD) - self.assertEqual(remain_enabled, self.safety.get_controls_allowed()) - self.safety.safety_rx_hook(self._send_interceptor_msg(0, 0x201)) - self.safety.set_gas_interceptor_detected(False) - self.safety.set_long_controls_allowed(True) + for g in range(0, 0x1000): + self.safety.safety_rx_hook(self._send_interceptor_msg(0, 0x201)) + self.safety.set_controls_allowed(True) + self.safety.safety_rx_hook(self._send_interceptor_msg(g, 0x201)) + remain_enabled = g <= INTERCEPTOR_THRESHOLD + self.assertEqual(remain_enabled, self.safety.get_controls_allowed()) + self.safety.safety_rx_hook(self._send_interceptor_msg(0, 0x201)) + self.safety.set_gas_interceptor_detected(False) def test_allow_engage_with_gas_interceptor_pressed(self): self.safety.safety_rx_hook(self._send_interceptor_msg(0x1000, 0x201)) @@ -192,33 +217,27 @@ class TestHondaSafety(unittest.TestCase): def test_brake_safety_check(self): for fwd_brake in [False, True]: self.safety.set_honda_fwd_brake(fwd_brake) - for long_controls_allowed in [0, 1]: - self.safety.set_long_controls_allowed(long_controls_allowed) - for brake in np.arange(0, MAX_BRAKE + 10, 1): - for controls_allowed in [True, False]: - self.safety.set_controls_allowed(controls_allowed) - if fwd_brake: - send = False # block openpilot brake msg when fwd'ing stock msg - elif controls_allowed and long_controls_allowed: - send = MAX_BRAKE >= brake >= 0 - else: - send = brake == 0 - self.assertEqual(send, self.safety.safety_tx_hook(self._send_brake_msg(brake))) - self.safety.set_long_controls_allowed(True) - self.safety.set_honda_fwd_brake(False) - - def test_gas_interceptor_safety_check(self): - for long_controls_allowed in [0, 1]: - self.safety.set_long_controls_allowed(long_controls_allowed) - for gas in np.arange(0, 4000, 100): + for brake in np.arange(0, MAX_BRAKE + 10, 1): for controls_allowed in [True, False]: self.safety.set_controls_allowed(controls_allowed) - if controls_allowed and long_controls_allowed: - send = True + if fwd_brake: + send = False # block openpilot brake msg when fwd'ing stock msg + elif controls_allowed: + send = MAX_BRAKE >= brake >= 0 else: - send = gas == 0 - self.assertEqual(send, self.safety.safety_tx_hook(self._send_interceptor_msg(gas, 0x200))) - self.safety.set_long_controls_allowed(True) + send = brake == 0 + self.assertEqual(send, self.safety.safety_tx_hook(self._send_brake_msg(brake))) + self.safety.set_honda_fwd_brake(False) + + def test_gas_interceptor_safety_check(self): + for gas in np.arange(0, 4000, 100): + for controls_allowed in [True, False]: + self.safety.set_controls_allowed(controls_allowed) + if controls_allowed: + send = True + else: + send = gas == 0 + self.assertEqual(send, self.safety.safety_tx_hook(self._send_interceptor_msg(gas, 0x200))) def test_steer_safety_check(self): self.safety.set_controls_allowed(0) @@ -230,47 +249,87 @@ class TestHondaSafety(unittest.TestCase): SET_BTN = 3 CANCEL_BTN = 2 BUTTON_MSG = 0x296 - self.safety.set_honda_bosch_hardware(1) - self.safety.set_controls_allowed(0) - self.assertTrue(self.safety.safety_tx_hook(self._button_msg(CANCEL_BTN, BUTTON_MSG))) - self.assertFalse(self.safety.safety_tx_hook(self._button_msg(RESUME_BTN, BUTTON_MSG))) - self.assertFalse(self.safety.safety_tx_hook(self._button_msg(SET_BTN, BUTTON_MSG))) - # do not block resume if we are engaged already - self.safety.set_controls_allowed(1) - self.assertTrue(self.safety.safety_tx_hook(self._button_msg(RESUME_BTN, BUTTON_MSG))) + for hw in [HONDA_BG_HW, HONDA_BH_HW]: + self.safety.set_honda_hw(hw) + self.safety.set_controls_allowed(0) + self.assertTrue(self.safety.safety_tx_hook(self._button_msg(CANCEL_BTN, BUTTON_MSG))) + self.assertFalse(self.safety.safety_tx_hook(self._button_msg(RESUME_BTN, BUTTON_MSG))) + self.assertFalse(self.safety.safety_tx_hook(self._button_msg(SET_BTN, BUTTON_MSG))) + # do not block resume if we are engaged already + self.safety.set_controls_allowed(1) + self.assertTrue(self.safety.safety_tx_hook(self._button_msg(RESUME_BTN, BUTTON_MSG))) + + def test_rx_hook(self): + # checksum checks + SET_BTN = 3 + for msg in ["btn1", "btn2", "gas", "speed"]: + self.safety.set_controls_allowed(1) + if msg == "btn1": + to_push = self._button_msg(SET_BTN, 0x1A6) + if msg == "btn2": + to_push = self._button_msg(SET_BTN, 0x296) + if msg == "gas": + to_push = self._gas_msg(0) + if msg == "speed": + to_push = self._speed_msg(0) + self.assertTrue(self.safety.safety_rx_hook(to_push)) + to_push[0].RDHR = 0 + self.assertFalse(self.safety.safety_rx_hook(to_push)) + self.assertFalse(self.safety.get_controls_allowed()) + + # counter + # reset wrong_counters to zero by sending valid messages + for i in range(MAX_WRONG_COUNTERS + 1): + self.cnt_speed = 0 + self.cnt_gas = 0 + self.cnt_button = 0 + if i < MAX_WRONG_COUNTERS: + self.safety.set_controls_allowed(1) + self.safety.safety_rx_hook(self._button_msg(SET_BTN, 0x1A6)) + self.safety.safety_rx_hook(self._speed_msg(0)) + self.safety.safety_rx_hook(self._gas_msg(0)) + else: + self.assertFalse(self.safety.safety_rx_hook(self._button_msg(SET_BTN, 0x1A6))) + self.assertFalse(self.safety.safety_rx_hook(self._speed_msg(0))) + self.assertFalse(self.safety.safety_rx_hook(self._gas_msg(0))) + self.assertFalse(self.safety.get_controls_allowed()) + + # restore counters for future tests with a couple of good messages + for i in range(2): + self.safety.set_controls_allowed(1) + self.safety.safety_rx_hook(self._button_msg(SET_BTN, 0x1A6)) + self.safety.safety_rx_hook(self._speed_msg(0)) + self.safety.safety_rx_hook(self._gas_msg(0)) + self.safety.safety_rx_hook(self._button_msg(SET_BTN, 0x1A6)) + self.assertTrue(self.safety.get_controls_allowed()) + def test_fwd_hook(self): buss = list(range(0x0, 0x3)) msgs = list(range(0x1, 0x800)) - long_controls_allowed = [0, 1] fwd_brake = [False, True] - self.safety.set_honda_bosch_hardware(0) + self.safety.set_honda_hw(HONDA_N_HW) for f in fwd_brake: self.safety.set_honda_fwd_brake(f) - for l in long_controls_allowed: - self.safety.set_long_controls_allowed(l) - blocked_msgs = [0xE4, 0x194, 0x33D] - if l: - blocked_msgs += [0x30C] - if not f: - blocked_msgs += [0x1FA] - for b in buss: - for m in msgs: - if b == 0: - fwd_bus = 2 - elif b == 1: - fwd_bus = -1 - elif b == 2: - fwd_bus = -1 if m in blocked_msgs else 0 - - # assume len 8 - self.assertEqual(fwd_bus, self.safety.safety_fwd_hook(b, make_msg(b, m, 8))) - - self.safety.set_long_controls_allowed(True) - self.safety.set_honda_fwd_brake(False) + blocked_msgs = [0xE4, 0x194, 0x33D] + blocked_msgs += [0x30C] + if not f: + blocked_msgs += [0x1FA] + for b in buss: + for m in msgs: + if b == 0: + fwd_bus = 2 + elif b == 1: + fwd_bus = -1 + elif b == 2: + fwd_bus = -1 if m in blocked_msgs else 0 + + # assume len 8 + self.assertEqual(fwd_bus, self.safety.safety_fwd_hook(b, make_msg(b, m, 8))) + self.safety.set_honda_fwd_brake(False) if __name__ == "__main__": diff --git a/panda/tests/safety/test_honda_bosch.py b/panda/tests/safety/test_honda_bosch.py index eed3622bcd..99c8d35464 100755 --- a/panda/tests/safety/test_honda_bosch.py +++ b/panda/tests/safety/test_honda_bosch.py @@ -3,6 +3,7 @@ import unittest from panda import Panda from panda.tests.safety import libpandasafety_py from panda.tests.safety.common import make_msg, test_spam_can_buses +from panda.tests.safety.test_honda import HONDA_BG_HW, HONDA_BH_HW MAX_BRAKE = 255 @@ -14,35 +15,35 @@ class TestHondaSafety(unittest.TestCase): @classmethod def setUp(cls): cls.safety = libpandasafety_py.libpandasafety - cls.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH, 0) + cls.safety.set_safety_hooks(Panda.SAFETY_HONDA_BOSCH_GIRAFFE, 0) cls.safety.init_tests_honda() def test_spam_can_buses(self): - if self.safety.board_has_relay(): - test_spam_can_buses(self, H_TX_MSGS) - else: - test_spam_can_buses(self, G_TX_MSGS) + for hw in [HONDA_BG_HW, HONDA_BH_HW]: + self.safety.set_honda_hw(hw) + test_spam_can_buses(self, H_TX_MSGS if hw == HONDA_BH_HW else G_TX_MSGS) def test_fwd_hook(self): buss = range(0x0, 0x3) msgs = range(0x1, 0x800) - has_relay = self.safety.board_has_relay() - bus_rdr_cam = 2 if has_relay else 1 - bus_rdr_car = 0 if has_relay else 2 - bus_pt = 1 if has_relay else 0 - - blocked_msgs = [0xE4, 0x33D] - for b in buss: - for m in msgs: - if b == bus_pt: - fwd_bus = -1 - elif b == bus_rdr_cam: - fwd_bus = -1 if m in blocked_msgs else bus_rdr_car - elif b == bus_rdr_car: - fwd_bus = bus_rdr_cam - - # assume len 8 - self.assertEqual(fwd_bus, self.safety.safety_fwd_hook(b, make_msg(b, m, 8))) + for hw in [HONDA_BG_HW, HONDA_BH_HW]: + self.safety.set_honda_hw(hw) + bus_rdr_cam = 2 if hw == HONDA_BH_HW else 1 + bus_rdr_car = 0 if hw == HONDA_BH_HW else 2 + bus_pt = 1 if hw == HONDA_BH_HW else 0 + + blocked_msgs = [0xE4, 0x33D] + for b in buss: + for m in msgs: + if b == bus_pt: + fwd_bus = -1 + elif b == bus_rdr_cam: + fwd_bus = -1 if m in blocked_msgs else bus_rdr_car + elif b == bus_rdr_car: + fwd_bus = bus_rdr_cam + + # assume len 8 + self.assertEqual(fwd_bus, self.safety.safety_fwd_hook(b, make_msg(b, m, 8))) if __name__ == "__main__": diff --git a/panda/tests/safety/test_toyota.py b/panda/tests/safety/test_toyota.py index 58e32f036e..1018162454 100644 --- a/panda/tests/safety/test_toyota.py +++ b/panda/tests/safety/test_toyota.py @@ -36,6 +36,16 @@ def sign(a): else: return -1 +def toyota_checksum(msg, addr, len_msg): + checksum = (len_msg + addr + (addr >> 8)) + for i in range(len_msg): + if i < 4: + checksum += (msg.RDLR >> (8 * i)) + else: + checksum += (msg.RDHR >> (8 * (i - 4))) + return checksum & 0xff + + class TestToyotaSafety(unittest.TestCase): @classmethod def setUp(cls): @@ -51,7 +61,8 @@ class TestToyotaSafety(unittest.TestCase): def _torque_meas_msg(self, torque): t = twos_comp(torque, 16) to_send = make_msg(0, 0x260) - to_send[0].RDHR = t | ((t & 0xFF) << 16) + to_send[0].RDHR = (t & 0xff00) | ((t & 0xFF) << 16) + to_send[0].RDHR = to_send[0].RDHR | (toyota_checksum(to_send[0], 0x260, 8) << 24) return to_send def _torque_msg(self, torque): @@ -81,6 +92,7 @@ class TestToyotaSafety(unittest.TestCase): def _pcm_cruise_msg(self, cruise_on): to_send = make_msg(0, 0x1D2) to_send[0].RDLR = cruise_on << 5 + to_send[0].RDHR = to_send[0].RDHR | (toyota_checksum(to_send[0], 0x1D2, 8) << 24) return to_send def test_spam_can_buses(self): @@ -120,16 +132,10 @@ class TestToyotaSafety(unittest.TestCase): self.safety.set_gas_interceptor_detected(False) def test_disengage_on_gas(self): - for long_controls_allowed in [0, 1]: - self.safety.set_long_controls_allowed(long_controls_allowed) - self.safety.safety_rx_hook(self._send_gas_msg(0)) - self.safety.set_controls_allowed(True) - self.safety.safety_rx_hook(self._send_gas_msg(1)) - if long_controls_allowed: - self.assertFalse(self.safety.get_controls_allowed()) - else: - self.assertTrue(self.safety.get_controls_allowed()) - self.safety.set_long_controls_allowed(True) + self.safety.safety_rx_hook(self._send_gas_msg(0)) + self.safety.set_controls_allowed(True) + self.safety.safety_rx_hook(self._send_gas_msg(1)) + self.assertFalse(self.safety.get_controls_allowed()) def test_allow_engage_with_gas_pressed(self): self.safety.safety_rx_hook(self._send_gas_msg(1)) @@ -140,17 +146,14 @@ class TestToyotaSafety(unittest.TestCase): self.assertTrue(self.safety.get_controls_allowed()) def test_disengage_on_gas_interceptor(self): - for long_controls_allowed in [0, 1]: - for g in range(0, 0x1000): - self.safety.set_long_controls_allowed(long_controls_allowed) - self.safety.safety_rx_hook(self._send_interceptor_msg(0, 0x201)) - self.safety.set_controls_allowed(True) - self.safety.safety_rx_hook(self._send_interceptor_msg(g, 0x201)) - remain_enabled = (not long_controls_allowed or g <= INTERCEPTOR_THRESHOLD) - self.assertEqual(remain_enabled, self.safety.get_controls_allowed()) - self.safety.safety_rx_hook(self._send_interceptor_msg(0, 0x201)) - self.safety.set_gas_interceptor_detected(False) - self.safety.set_long_controls_allowed(True) + for g in range(0, 0x1000): + self.safety.safety_rx_hook(self._send_interceptor_msg(0, 0x201)) + self.safety.set_controls_allowed(True) + self.safety.safety_rx_hook(self._send_interceptor_msg(g, 0x201)) + remain_enabled = g <= INTERCEPTOR_THRESHOLD + self.assertEqual(remain_enabled, self.safety.get_controls_allowed()) + self.safety.safety_rx_hook(self._send_interceptor_msg(0, 0x201)) + self.safety.set_gas_interceptor_detected(False) def test_allow_engage_with_gas_interceptor_pressed(self): self.safety.safety_rx_hook(self._send_interceptor_msg(0x1000, 0x201)) @@ -161,17 +164,14 @@ class TestToyotaSafety(unittest.TestCase): self.safety.set_gas_interceptor_detected(False) def test_accel_actuation_limits(self): - for long_controls_allowed in [0, 1]: - self.safety.set_long_controls_allowed(long_controls_allowed) - for accel in np.arange(MIN_ACCEL - 1000, MAX_ACCEL + 1000, 100): - for controls_allowed in [True, False]: - self.safety.set_controls_allowed(controls_allowed) - if controls_allowed and long_controls_allowed: - send = MIN_ACCEL <= accel <= MAX_ACCEL - else: - send = accel == 0 - self.assertEqual(send, self.safety.safety_tx_hook(self._accel_msg(accel))) - self.safety.set_long_controls_allowed(True) + for accel in np.arange(MIN_ACCEL - 1000, MAX_ACCEL + 1000, 100): + for controls_allowed in [True, False]: + self.safety.set_controls_allowed(controls_allowed) + if controls_allowed: + send = MIN_ACCEL <= accel <= MAX_ACCEL + else: + send = accel == 0 + self.assertEqual(send, self.safety.safety_tx_hook(self._accel_msg(accel))) def test_torque_absolute_limits(self): for controls_allowed in [True, False]: @@ -271,30 +271,38 @@ class TestToyotaSafety(unittest.TestCase): self.safety.set_controls_allowed(1) self.assertTrue(self.safety.safety_tx_hook(self._send_interceptor_msg(0x1000, 0x200))) + def test_rx_hook(self): + # checksum checks + for msg in ["trq", "pcm"]: + self.safety.set_controls_allowed(1) + if msg == "trq": + to_push = self._torque_meas_msg(0) + if msg == "pcm": + to_push = self._pcm_cruise_msg(1) + self.assertTrue(self.safety.safety_rx_hook(to_push)) + to_push[0].RDHR = 0 + self.assertFalse(self.safety.safety_rx_hook(to_push)) + self.assertFalse(self.safety.get_controls_allowed()) + def test_fwd_hook(self): buss = list(range(0x0, 0x3)) msgs = list(range(0x1, 0x800)) - long_controls_allowed = [0, 1] - - for lca in long_controls_allowed: - self.safety.set_long_controls_allowed(lca) - blocked_msgs = [0x2E4, 0x412, 0x191] - if lca: - blocked_msgs += [0x343] - for b in buss: - for m in msgs: - if b == 0: - fwd_bus = 2 - elif b == 1: - fwd_bus = -1 - elif b == 2: - fwd_bus = -1 if m in blocked_msgs else 0 - - # assume len 8 - self.assertEqual(fwd_bus, self.safety.safety_fwd_hook(b, make_msg(b, m, 8))) - - self.safety.set_long_controls_allowed(True) + + blocked_msgs = [0x2E4, 0x412, 0x191] + blocked_msgs += [0x343] + for b in buss: + for m in msgs: + if b == 0: + fwd_bus = 2 + elif b == 1: + fwd_bus = -1 + elif b == 2: + fwd_bus = -1 if m in blocked_msgs else 0 + + # assume len 8 + self.assertEqual(fwd_bus, self.safety.safety_fwd_hook(b, make_msg(b, m, 8))) + if __name__ == "__main__": diff --git a/panda/tests/safety/test_toyota_ipas.py b/panda/tests/safety/test_toyota_ipas.py index 680fc149b7..3fcca95f1c 100644 --- a/panda/tests/safety/test_toyota_ipas.py +++ b/panda/tests/safety/test_toyota_ipas.py @@ -3,7 +3,8 @@ import unittest import numpy as np from panda import Panda from panda.tests.safety import libpandasafety_py -from panda.tests. safety.common import make_msg +from panda.tests.safety.common import make_msg +from panda.tests.safety.test_toyota import toyota_checksum IPAS_OVERRIDE_THRESHOLD = 200 @@ -23,6 +24,7 @@ def sign(a): else: return -1 + class TestToyotaSafety(unittest.TestCase): @classmethod def setUp(cls): @@ -34,6 +36,7 @@ class TestToyotaSafety(unittest.TestCase): to_send = make_msg(0, 0x260) t = twos_comp(torque, 16) to_send[0].RDLR = t | ((t & 0xFF) << 16) + to_send[0].RDHR = to_send[0].RDHR | (toyota_checksum(to_send[0], 0x260, 8) << 24) return to_send def _torque_driver_msg_array(self, torque): diff --git a/panda/tests/safety/test_volkswagen.py b/panda/tests/safety/test_volkswagen.py index 99d0916e46..db58cdc581 100644 --- a/panda/tests/safety/test_volkswagen.py +++ b/panda/tests/safety/test_volkswagen.py @@ -87,16 +87,10 @@ class TestVolkswagenSafety(unittest.TestCase): self.assertFalse(self.safety.get_controls_allowed()) def test_disengage_on_gas(self): - for long_controls_allowed in [0, 1]: - self.safety.set_long_controls_allowed(long_controls_allowed) - self.safety.safety_rx_hook(self._gas_msg(0)) - self.safety.set_controls_allowed(True) - self.safety.safety_rx_hook(self._gas_msg(1)) - if long_controls_allowed: - self.assertFalse(self.safety.get_controls_allowed()) - else: - self.assertTrue(self.safety.get_controls_allowed()) - self.safety.set_long_controls_allowed(True) + self.safety.safety_rx_hook(self._gas_msg(0)) + self.safety.set_controls_allowed(True) + self.safety.safety_rx_hook(self._gas_msg(1)) + self.assertFalse(self.safety.get_controls_allowed()) def test_allow_engage_with_gas_pressed(self): self.safety.safety_rx_hook(self._gas_msg(1)) diff --git a/panda/tests/safety_replay/helpers.py b/panda/tests/safety_replay/helpers.py index 8fa1d3a1e9..b5fe1a09a0 100644 --- a/panda/tests/safety_replay/helpers.py +++ b/panda/tests/safety_replay/helpers.py @@ -11,7 +11,7 @@ def to_signed(d, bits): def is_steering_msg(mode, addr): ret = False - if mode == Panda.SAFETY_HONDA or mode == Panda.SAFETY_HONDA_BOSCH: + if mode in [Panda.SAFETY_HONDA_NIDEC, Panda.SAFETY_HONDA_BOSCH_GIRAFFE, Panda.SAFETY_HONDA_BOSCH_HARNESS]: ret = (addr == 0xE4) or (addr == 0x194) or (addr == 0x33D) elif mode == Panda.SAFETY_TOYOTA: ret = addr == 0x2E4 @@ -27,7 +27,7 @@ def is_steering_msg(mode, addr): def get_steer_torque(mode, to_send): ret = 0 - if mode == Panda.SAFETY_HONDA or mode == Panda.SAFETY_HONDA_BOSCH: + if mode in [Panda.SAFETY_HONDA_NIDEC, Panda.SAFETY_HONDA_BOSCH_GIRAFFE, Panda.SAFETY_HONDA_BOSCH_HARNESS]: ret = to_send.RDLR & 0xFFFF0000 elif mode == Panda.SAFETY_TOYOTA: ret = (to_send.RDLR & 0xFF00) | ((to_send.RDLR >> 16) & 0xFF) @@ -45,7 +45,7 @@ def get_steer_torque(mode, to_send): return ret def set_desired_torque_last(safety, mode, torque): - if mode == Panda.SAFETY_HONDA or mode == Panda.SAFETY_HONDA_BOSCH: + if mode in [Panda.SAFETY_HONDA_NIDEC, Panda.SAFETY_HONDA_BOSCH_GIRAFFE, Panda.SAFETY_HONDA_BOSCH_HARNESS]: pass # honda safety mode doesn't enforce a rate on steering msgs elif mode == Panda.SAFETY_TOYOTA: safety.set_toyota_desired_torque_last(torque) diff --git a/panda/tests/safety_replay/replay_drive.py b/panda/tests/safety_replay/replay_drive.py index 09c677cacb..456723cb2b 100755 --- a/panda/tests/safety_replay/replay_drive.py +++ b/panda/tests/safety_replay/replay_drive.py @@ -16,8 +16,9 @@ def replay_drive(lr, safety_mode, param): if "SEGMENT" in os.environ: init_segment(safety, lr, mode) - tx_tot, tx_blocked, tx_controls, tx_controls_blocked = 0, 0, 0, 0 + rx_tot, rx_invalid, tx_tot, tx_blocked, tx_controls, tx_controls_blocked = 0, 0, 0, 0, 0, 0 blocked_addrs = set() + invalid_addrs = set() start_t = None for msg in lr: @@ -44,15 +45,24 @@ def replay_drive(lr, safety_mode, param): if canmsg.src >= 128: continue to_push = package_can_msg(canmsg) - safety.safety_rx_hook(to_push) + recv = safety.safety_rx_hook(to_push) + if not recv: + rx_invalid += 1 + invalid_addrs.add(canmsg.address) + rx_tot += 1 + print("\nRX") + print("total rx msgs:", rx_tot) + print("invalid rx msgs:", rx_invalid) + print("invalid addrs:", invalid_addrs) + print("\nTX") print("total openpilot msgs:", tx_tot) print("total msgs with controls allowed:", tx_controls) print("blocked msgs:", tx_blocked) print("blocked with controls allowed:", tx_controls_blocked) print("blocked addrs:", blocked_addrs) - return tx_controls_blocked == 0 + return tx_controls_blocked == 0 and rx_invalid == 0 if __name__ == "__main__": mode = int(sys.argv[2]) diff --git a/panda/tests/safety_replay/test_safety_replay.py b/panda/tests/safety_replay/test_safety_replay.py index 4b2f5372df..fd36b248e3 100755 --- a/panda/tests/safety_replay/test_safety_replay.py +++ b/panda/tests/safety_replay/test_safety_replay.py @@ -14,7 +14,7 @@ logs = [ ("2425568437959f9d|2019-12-22--16-24-37.bz2", Panda.SAFETY_HONDA_NIDEC, 0), # HONDA.CIVIC (fcw presents: 0x1FA blocked as expected) ("38bfd238edecbcd7|2019-06-07--10-15-25.bz2", Panda.SAFETY_TOYOTA, 66), # TOYOTA.PRIUS ("f89c604cf653e2bf|2018-09-29--13-46-50.bz2", Panda.SAFETY_GM, 0), # GM.VOLT - ("0375fdf7b1ce594d|2019-05-21--20-10-33.bz2", Panda.SAFETY_HONDA_BOSCH, 1), # HONDA.ACCORD + ("0375fdf7b1ce594d|2019-05-21--20-10-33.bz2", Panda.SAFETY_HONDA_BOSCH_GIRAFFE, 1), # HONDA.ACCORD ("02ec6bea180a4d36|2019-04-17--11-21-35.bz2", Panda.SAFETY_HYUNDAI, 0), # HYUNDAI.SANTA_FE ("6fb4948a7ebe670e|2019-11-12--00-35-53.bz2", Panda.SAFETY_CHRYSLER, 0), # CHRYSLER.PACIFICA_2018_HYBRID ("791340bc01ed993d|2019-04-08--10-26-00.bz2", Panda.SAFETY_SUBARU, 0), # SUBARU.IMPREZA diff --git a/scripts/stop_updater.sh b/scripts/stop_updater.sh new file mode 100755 index 0000000000..4243d30e9f --- /dev/null +++ b/scripts/stop_updater.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env sh + +# Stop updater +pkill -2 -f selfdrive.updated + +# Remove pending update +rm -f /data/safe_staging/finalized/.overlay_consistent diff --git a/scripts/update_now.sh b/scripts/update_now.sh new file mode 100755 index 0000000000..3f0193f081 --- /dev/null +++ b/scripts/update_now.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env sh + +# Send SIGHUP to updater +pkill -1 -f selfdrive.updated diff --git a/selfdrive/athena/test.py b/selfdrive/athena/test.py index 99226176bc..0bedfdeb72 100755 --- a/selfdrive/athena/test.py +++ b/selfdrive/athena/test.py @@ -32,10 +32,8 @@ class TestAthenadMethods(unittest.TestCase): assert dispatcher["echo"]("bob") == "bob" def test_getMessage(self): - try: + with self.assertRaises(TimeoutError) as _: dispatcher["getMessage"]("controlsState") - except TimeoutError: - pass def send_thermal(): messaging.context = messaging.Context() @@ -50,6 +48,7 @@ class TestAthenadMethods(unittest.TestCase): p = Process(target=send_thermal) p.start() + time.sleep(0.1) try: thermal = dispatcher["getMessage"]("thermal") assert thermal['thermal'] @@ -60,7 +59,7 @@ class TestAthenadMethods(unittest.TestCase): print(dispatcher["listDataDirectory"]()) @with_http_server - def test_do_upload(self): + def test_do_upload(self, host): fn = os.path.join(athenad.ROOT, 'qlog.bz2') Path(fn).touch() @@ -71,14 +70,14 @@ class TestAthenadMethods(unittest.TestCase): except requests.exceptions.ConnectionError: pass - item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='') + item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='') resp = athenad._do_upload(item) self.assertEqual(resp.status_code, 201) finally: os.unlink(fn) @with_http_server - def test_uploadFileToUrl(self): + def test_uploadFileToUrl(self, host): not_exists_resp = dispatcher["uploadFileToUrl"]("does_not_exist.bz2", "http://localhost:1238", {}) self.assertEqual(not_exists_resp, 404) @@ -86,9 +85,9 @@ class TestAthenadMethods(unittest.TestCase): Path(fn).touch() try: - resp = dispatcher["uploadFileToUrl"]("qlog.bz2", "http://localhost:44444/qlog.bz2", {}) + resp = dispatcher["uploadFileToUrl"]("qlog.bz2", f"{host}/qlog.bz2", {}) self.assertEqual(resp['enqueued'], 1) - self.assertDictContainsSubset({"path": fn, "url": "http://localhost:44444/qlog.bz2", "headers": {}}, resp['item']) + self.assertDictContainsSubset({"path": fn, "url": f"{host}/qlog.bz2", "headers": {}}, resp['item']) self.assertIsNotNone(resp['item'].get('id')) self.assertEqual(athenad.upload_queue.qsize(), 1) finally: @@ -96,10 +95,10 @@ class TestAthenadMethods(unittest.TestCase): os.unlink(fn) @with_http_server - def test_upload_handler(self): + def test_upload_handler(self, host): fn = os.path.join(athenad.ROOT, 'qlog.bz2') Path(fn).touch() - item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='') + item = athenad.UploadItem(path=fn, url=f"{host}/qlog.bz2", headers={}, created_at=int(time.time()*1000), id='') end_event = threading.Event() thread = threading.Thread(target=athenad.upload_handler, args=(end_event,)) diff --git a/selfdrive/athena/test_helpers.py b/selfdrive/athena/test_helpers.py index a6b2d48978..2335ce89c5 100644 --- a/selfdrive/athena/test_helpers.py +++ b/selfdrive/athena/test_helpers.py @@ -1,4 +1,7 @@ import http.server +import multiprocessing +import queue +import random import requests import socket import time @@ -70,27 +73,41 @@ class HTTPRequestHandler(http.server.SimpleHTTPRequestHandler): self.send_response(201, "Created") self.end_headers() +def http_server(port_queue, **kwargs): + while 1: + try: + port = random.randrange(40000, 50000) + port_queue.put(port) + http.server.test(**kwargs, port=port) + except OSError as e: + if e.errno == 98: + continue + def with_http_server(func): @wraps(func) def inner(*args, **kwargs): - p = Process(target=http.server.test, + port_queue = multiprocessing.Queue() + host = '127.0.0.1' + p = Process(target=http_server, + args=(port_queue,), kwargs={ 'HandlerClass': HTTPRequestHandler, - 'port': 44444, - 'bind': '127.0.0.1'}) + 'bind': host}) p.start() now = time.time() + port = None while 1: if time.time() - now > 5: raise Exception('HTTP Server did not start') try: - requests.put('http://localhost:44444/qlog.bz2', data='') + port = port_queue.get(timeout=0.1) + requests.put(f'http://{host}:{port}/qlog.bz2', data='') break - except requests.exceptions.ConnectionError: + except (requests.exceptions.ConnectionError, queue.Empty): time.sleep(0.1) try: - return func(*args, **kwargs) + return func(*args, f'http://{host}:{port}', **kwargs) finally: p.terminate() diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index e8a313d904..37ee22e700 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -21,6 +21,7 @@ #include "cereal/gen/cpp/log.capnp.h" #include "cereal/gen/cpp/car.capnp.h" +#include "common/util.h" #include "common/messaging.h" #include "common/params.h" #include "common/swaglog.h" @@ -35,8 +36,10 @@ #define MAX_IR_POWER 0.5f #define MIN_IR_POWER 0.0f -#define CUTOFF_GAIN 0.015625f // iso400 -#define SATURATE_GAIN 0.0625f // iso1600 +#define CUTOFF_GAIN 0.015625f // iso400 +#define SATURATE_GAIN 0.0625f // iso1600 +#define NIBBLE_TO_HEX(n) ((n) < 10 ? (n) + '0' : ((n) - 10) + 'a') +#define VOLTAGE_K 0.091 // LPF gain for 5s tau (dt/tau / (dt/tau + 1)) namespace { @@ -62,14 +65,19 @@ bool loopback_can = false; cereal::HealthData::HwType hw_type = cereal::HealthData::HwType::UNKNOWN; bool is_pigeon = false; const uint32_t NO_IGNITION_CNT_MAX = 2 * 60 * 60 * 30; // turn off charge after 30 hrs -const uint32_t VBATT_START_CHARGING = 11500; -const uint32_t VBATT_PAUSE_CHARGING = 10500; +const float VBATT_START_CHARGING = 11.5; +const float VBATT_PAUSE_CHARGING = 11.0; +float voltage_f = 12.5; // filtered voltage uint32_t no_ignition_cnt = 0; bool connected_once = false; bool ignition_last = false; -pthread_t safety_setter_thread_handle = -1; -pthread_t pigeon_thread_handle = -1; +bool safety_setter_thread_initialized = false; +pthread_t safety_setter_thread_handle; + +bool pigeon_thread_initialized = false; +pthread_t pigeon_thread_handle; + bool pigeon_needs_init; void pigeon_init(); @@ -130,10 +138,7 @@ void *safety_setter_thread(void *s) { pthread_mutex_lock(&usb_lock); // set in the mutex to avoid race - safety_setter_thread_handle = -1; - - // set if long_control is allowed by openpilot. Hardcoded to True for now - libusb_control_transfer(dev_handle, 0x40, 0xdf, 1, 0, NULL, 0, TIMEOUT); + safety_setter_thread_initialized = false; libusb_control_transfer(dev_handle, 0x40, 0xdc, safety_model, safety_param, NULL, 0, TIMEOUT); @@ -144,13 +149,12 @@ void *safety_setter_thread(void *s) { // must be called before threads or with mutex bool usb_connect() { - int err; + int err, err2; unsigned char hw_query[1] = {0}; - unsigned char fw_ver_buf[64]; + unsigned char fw_sig_buf[128]; + unsigned char fw_sig_hex_buf[16]; unsigned char serial_buf[16]; - const char *fw_ver; const char *serial; - int fw_ver_sz = 0; int serial_sz = 0; ignition_last = false; @@ -169,12 +173,17 @@ bool usb_connect() { } // get panda fw - err = libusb_control_transfer(dev_handle, 0xc0, 0xd6, 0, 0, fw_ver_buf, 64, TIMEOUT); - if (err > 0) { - fw_ver = (const char *)fw_ver_buf; - fw_ver_sz = err; - write_db_value(NULL, "PandaFirmware", fw_ver, fw_ver_sz); - printf("panda fw: %.*s\n", fw_ver_sz, fw_ver); + err = libusb_control_transfer(dev_handle, 0xc0, 0xd3, 0, 0, fw_sig_buf, 64, TIMEOUT); + err2 = libusb_control_transfer(dev_handle, 0xc0, 0xd4, 0, 0, fw_sig_buf + 64, 64, TIMEOUT); + if ((err == 64) && (err2 == 64)) { + printf("FW signature read\n"); + write_db_value(NULL, "PandaFirmware", (const char *)fw_sig_buf, 128); + + for (size_t i = 0; i < 8; i++){ + fw_sig_hex_buf[2*i] = NIBBLE_TO_HEX(fw_sig_buf[i] >> 4); + fw_sig_hex_buf[2*i+1] = NIBBLE_TO_HEX(fw_sig_buf[i] & 0xF); + } + write_db_value(NULL, "PandaFirmwareHex", (const char *)fw_sig_hex_buf, 16); } else { goto fail; } @@ -206,9 +215,10 @@ bool usb_connect() { if (is_pigeon) { LOGW("panda with gps detected"); pigeon_needs_init = true; - if (pigeon_thread_handle == -1) { + if (!pigeon_thread_initialized) { err = pthread_create(&pigeon_thread_handle, NULL, pigeon_thread, NULL); assert(err == 0); + pigeon_thread_initialized = true; } } @@ -289,6 +299,8 @@ void can_recv(PubSocket *publisher) { // return if length is 0 if (recv <= 0) { return; + } else if (recv == RECV_SIZE) { + LOGW("Receive buffer full"); } // create message @@ -296,7 +308,6 @@ void can_recv(PubSocket *publisher) { cereal::Event::Builder event = msg.initRoot(); event.setLogMonoTime(start_time); size_t num_msg = recv / 0x10; - auto canData = event.initCan(num_msg); // populate message @@ -330,6 +341,7 @@ void can_health(PubSocket *publisher) { uint32_t uptime; uint32_t voltage; uint32_t current; + uint32_t can_rx_errs; uint32_t can_send_errs; uint32_t can_fwd_errs; uint32_t gmlan_send_errs; @@ -355,6 +367,12 @@ void can_health(PubSocket *publisher) { } while(cnt != sizeof(health)); pthread_mutex_unlock(&usb_lock); + if (spoofing_started) { + health.ignition_line = 1; + } + + voltage_f = VOLTAGE_K * (health.voltage / 1000.0) + (1.0 - VOLTAGE_K) * voltage_f; // LPF + // Make sure CAN buses are live: safety_setter_thread does not work if Panda CAN are silent and there is only one other CAN node if (health.safety_model == (uint8_t)(cereal::CarParams::SafetyModel::SILENT)) { pthread_mutex_lock(&usb_lock); @@ -373,13 +391,15 @@ void can_health(PubSocket *publisher) { #ifndef __x86_64__ bool cdp_mode = health.usb_power_mode == (uint8_t)(cereal::HealthData::UsbPowerMode::CDP); bool no_ignition_exp = no_ignition_cnt > NO_IGNITION_CNT_MAX; - if ((no_ignition_exp || (health.voltage < VBATT_PAUSE_CHARGING)) && cdp_mode && !ignition) { + if ((no_ignition_exp || (voltage_f < VBATT_PAUSE_CHARGING)) && cdp_mode && !ignition) { printf("TURN OFF CHARGING!\n"); pthread_mutex_lock(&usb_lock); libusb_control_transfer(dev_handle, 0xc0, 0xe6, (uint16_t)(cereal::HealthData::UsbPowerMode::CLIENT), 0, NULL, 0, TIMEOUT); pthread_mutex_unlock(&usb_lock); + printf("POWER DOWN DEVICE\n"); + system("service call power 17 i32 0 i32 1"); } - if (!no_ignition_exp && (health.voltage > VBATT_START_CHARGING) && !cdp_mode) { + if (!no_ignition_exp && (voltage_f > VBATT_START_CHARGING) && !cdp_mode) { printf("TURN ON CHARGING!\n"); pthread_mutex_lock(&usb_lock); libusb_control_transfer(dev_handle, 0xc0, 0xe6, (uint16_t)(cereal::HealthData::UsbPowerMode::CDP), 0, NULL, 0, TIMEOUT); @@ -406,15 +426,15 @@ void can_health(PubSocket *publisher) { // clear VIN, CarParams, and set new safety on car start if (ignition && !ignition_last) { - int result = delete_db_value(NULL, "CarVin"); assert((result == 0) || (result == ERR_NO_VALUE)); result = delete_db_value(NULL, "CarParams"); assert((result == 0) || (result == ERR_NO_VALUE)); - if (safety_setter_thread_handle == -1) { + if (!safety_setter_thread_initialized) { err = pthread_create(&safety_setter_thread_handle, NULL, safety_setter_thread, NULL); assert(err == 0); + safety_setter_thread_initialized = true; } } @@ -459,15 +479,12 @@ void can_health(PubSocket *publisher) { healthData.setUptime(health.uptime); healthData.setVoltage(health.voltage); healthData.setCurrent(health.current); - if (spoofing_started) { - healthData.setIgnitionLine(true); - } else { - healthData.setIgnitionLine(health.ignition_line); - } + healthData.setIgnitionLine(health.ignition_line); healthData.setIgnitionCan(health.ignition_can); healthData.setControlsAllowed(health.controls_allowed); healthData.setGasInterceptorDetected(health.gas_interceptor_detected); healthData.setHasGps(is_pigeon); + healthData.setCanRxErrs(health.can_rx_errs); healthData.setCanSendErrs(health.can_send_errs); healthData.setCanFwdErrs(health.can_fwd_errs); healthData.setGmlanSendErrs(health.gmlan_send_errs); @@ -842,14 +859,6 @@ void *pigeon_thread(void *crap) { return NULL; } -int set_realtime_priority(int level) { - // should match python using chrt - struct sched_param sa; - memset(&sa, 0, sizeof(sa)); - sa.sched_priority = level; - return sched_setscheduler(getpid(), SCHED_FIFO, &sa); -} - } int main() { diff --git a/selfdrive/camerad/main.cc b/selfdrive/camerad/main.cc index 7679a5248d..896a4cac67 100644 --- a/selfdrive/camerad/main.cc +++ b/selfdrive/camerad/main.cc @@ -680,14 +680,6 @@ void* visionserver_client_thread(void* arg) { } else { assert(false); } - - if (stream_type == VISION_STREAM_RGB_BACK || - stream_type == VISION_STREAM_RGB_FRONT) { - /*stream_bufs->buf_info.ui_info = (VisionUIInfo){ - .transformed_width = s->model.in.transformed_width, - .transformed_height = s->model.in.transformed_height, - };*/ - } vipc_send(fd, &rep); streams[stream_type].subscribed = true; } else if (p.type == VIPC_STREAM_RELEASE) { diff --git a/selfdrive/car/car_helpers.py b/selfdrive/car/car_helpers.py index e3a96617be..4467788611 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -3,6 +3,7 @@ from common.params import Params from common.basedir import BASEDIR from selfdrive.car.fingerprints import eliminate_incompatible_cars, all_known_cars from selfdrive.car.vin import get_vin, VIN_UNKNOWN +from selfdrive.car.fw_versions import get_fw_versions from selfdrive.swaglog import cloudlog import cereal.messaging as messaging from selfdrive.car import gen_empty_fingerprint @@ -56,12 +57,14 @@ def only_toyota_left(candidate_cars): # BOUNTY: every added fingerprint in selfdrive/car/*/values.py is a $100 coupon code on shop.comma.ai # **** for use live only **** def fingerprint(logcan, sendcan, has_relay): - if has_relay: # Vin query only reliably works thorugh OBDII - vin = get_vin(logcan, sendcan, 1) + bus = 1 + addr, vin = get_vin(logcan, sendcan, bus) + _, car_fw = get_fw_versions(logcan, sendcan, bus) else: vin = VIN_UNKNOWN + _, car_fw = set(), [] cloudlog.warning("VIN %s", vin) Params().put("CarVin", vin) @@ -108,18 +111,19 @@ def fingerprint(logcan, sendcan, has_relay): frame += 1 cloudlog.warning("fingerprinted %s", car_fingerprint) - return car_fingerprint, finger, vin + return car_fingerprint, finger, vin, car_fw def get_car(logcan, sendcan, has_relay=False): - - candidate, fingerprints, vin = fingerprint(logcan, sendcan, has_relay) + candidate, fingerprints, vin, car_fw = fingerprint(logcan, sendcan, has_relay) if candidate is None: cloudlog.warning("car doesn't match any fingerprints: %r", fingerprints) candidate = "mock" CarInterface, CarController = interfaces[candidate] - car_params = CarInterface.get_params(candidate, fingerprints, vin, has_relay) + car_params = CarInterface.get_params(candidate, fingerprints, has_relay, car_fw) + car_params.carVin = vin + car_params.carFw = car_fw return CarInterface(car_params, CarController), car_params diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index 2a6422ecbf..f96d95ae98 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -35,13 +35,12 @@ class CarInterface(CarInterfaceBase): return float(accel) / 3.0 @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): ret = car.CarParams.new_message() ret.carName = "chrysler" ret.carFingerprint = candidate - ret.carVin = vin ret.isPandaBlack = has_relay ret.safetyModel = car.CarParams.SafetyModel.chrysler diff --git a/selfdrive/car/fingerprints.py b/selfdrive/car/fingerprints.py index 0e29e6c1e7..4ca9fa0931 100644 --- a/selfdrive/car/fingerprints.py +++ b/selfdrive/car/fingerprints.py @@ -1,27 +1,43 @@ import os from common.basedir import BASEDIR -def get_fingerprint_list(): +def get_attr_from_cars(attr): # read all the folders in selfdrive/car and return a dict where: - # - keys are all the car models for which we have a fingerprint - # - values are lists dicts of messages that constitute the unique - # CAN fingerprint of each car model and all its variants - fingerprints = {} + # - keys are all the car models + # - values are attr values from all car folders + result = {} + for car_folder in [x[0] for x in os.walk(BASEDIR + '/selfdrive/car')]: try: car_name = car_folder.split('/')[-1] - values = __import__('selfdrive.car.%s.values' % car_name, fromlist=['FINGERPRINTS']) - if hasattr(values, 'FINGERPRINTS'): - car_fingerprints = values.FINGERPRINTS + values = __import__('selfdrive.car.%s.values' % car_name, fromlist=[attr]) + if hasattr(values, attr): + attr_values = getattr(values, attr) else: continue - for f, v in car_fingerprints.items(): - fingerprints[f] = v + + for f, v in attr_values.items(): + result[f] = v + except (ImportError, IOError): pass - return fingerprints + + return result + + +def get_fw_versions_list(): + return get_attr_from_cars('FW_VERSIONS') + + +def get_fingerprint_list(): + # read all the folders in selfdrive/car and return a dict where: + # - keys are all the car models for which we have a fingerprint + # - values are lists dicts of messages that constitute the unique + # CAN fingerprint of each car model and all its variants + return get_attr_from_cars('FINGERPRINTS') +FW_VERSIONS = get_fw_versions_list() _FINGERPRINTS = get_fingerprint_list() _DEBUG_ADDRESS = {1880: 8} # reserved for debug purposes diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 5b2deed550..70df1cf954 100755 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -34,13 +34,12 @@ class CarInterface(CarInterfaceBase): return float(accel) / 3.0 @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): ret = car.CarParams.new_message() ret.carName = "ford" ret.carFingerprint = candidate - ret.carVin = vin ret.isPandaBlack = has_relay ret.safetyModel = car.CarParams.SafetyModel.ford diff --git a/selfdrive/car/fw_versions.py b/selfdrive/car/fw_versions.py new file mode 100755 index 0000000000..1175c59784 --- /dev/null +++ b/selfdrive/car/fw_versions.py @@ -0,0 +1,192 @@ +#!/usr/bin/env python3 +import traceback +import struct +from tqdm import tqdm + +from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery +from selfdrive.swaglog import cloudlog +from selfdrive.car.fingerprints import FW_VERSIONS +import panda.python.uds as uds + +from cereal import car +Ecu = car.CarParams.Ecu + +def p16(val): + return struct.pack("!H", val) + +TESTER_PRESENT_REQUEST = bytes([uds.SERVICE_TYPE.TESTER_PRESENT, 0x0]) +TESTER_PRESENT_RESPONSE = bytes([uds.SERVICE_TYPE.TESTER_PRESENT + 0x40, 0x0]) + +SHORT_TESTER_PRESENT_REQUEST = bytes([uds.SERVICE_TYPE.TESTER_PRESENT]) +SHORT_TESTER_PRESENT_RESPONSE = bytes([uds.SERVICE_TYPE.TESTER_PRESENT + 0x40]) + +DEFAULT_DIAGNOSTIC_REQUEST = bytes([uds.SERVICE_TYPE.DIAGNOSTIC_SESSION_CONTROL, + uds.SESSION_TYPE.DEFAULT]) +DEFAULT_DIAGNOSTIC_RESPONSE = bytes([uds.SERVICE_TYPE.DIAGNOSTIC_SESSION_CONTROL + 0x40, + uds.SESSION_TYPE.DEFAULT, 0x0, 0x32, 0x1, 0xf4]) + +EXTENDED_DIAGNOSTIC_REQUEST = bytes([uds.SERVICE_TYPE.DIAGNOSTIC_SESSION_CONTROL, + uds.SESSION_TYPE.EXTENDED_DIAGNOSTIC]) +EXTENDED_DIAGNOSTIC_RESPONSE = bytes([uds.SERVICE_TYPE.DIAGNOSTIC_SESSION_CONTROL + 0x40, + uds.SESSION_TYPE.EXTENDED_DIAGNOSTIC, 0x0, 0x32, 0x1, 0xf4]) + +UDS_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \ + p16(uds.DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_IDENTIFICATION) +UDS_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) + \ + p16(uds.DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_IDENTIFICATION) + +TOYOTA_VERSION_REQUEST = b'\x1a\x88\x01' +TOYOTA_VERSION_RESPONSE = b'\x5a\x88\x01' + +OBD_VERSION_REQUEST = b'\x09\x04' +OBD_VERSION_RESPONSE = b'\x49\x04' + + +REQUESTS = [ + # Honda + ( + [UDS_VERSION_REQUEST], + [UDS_VERSION_RESPONSE] + ), + # Toyota + ( + [SHORT_TESTER_PRESENT_REQUEST, TOYOTA_VERSION_REQUEST], + [SHORT_TESTER_PRESENT_RESPONSE, TOYOTA_VERSION_RESPONSE] + ), + ( + [SHORT_TESTER_PRESENT_REQUEST, OBD_VERSION_REQUEST], + [SHORT_TESTER_PRESENT_RESPONSE, OBD_VERSION_RESPONSE] + ), + ( + [TESTER_PRESENT_REQUEST, DEFAULT_DIAGNOSTIC_REQUEST, EXTENDED_DIAGNOSTIC_REQUEST, UDS_VERSION_REQUEST], + [TESTER_PRESENT_RESPONSE, DEFAULT_DIAGNOSTIC_RESPONSE, EXTENDED_DIAGNOSTIC_RESPONSE, UDS_VERSION_RESPONSE] + ) +] + +def chunks(l, n=128): + for i in range(0, len(l), n): + yield l[i:i + n] + +def match_fw_to_car(fw_versions): + candidates = FW_VERSIONS + invalid = [] + + for candidate, fws in candidates.items(): + for ecu, expected_versions in fws.items(): + ecu_type = ecu[0] + addr = ecu[1:] + + found_version = fw_versions.get(addr, None) + + # Allow DSU not being present + if ecu_type in [Ecu.unknown, Ecu.dsu] and found_version is None: + continue + + if found_version not in expected_versions: + invalid.append(candidate) + break + + return set(candidates.keys()) - set(invalid) + + +def get_fw_versions(logcan, sendcan, bus, extra=None, timeout=0.1, debug=False, progress=False): + ecu_types = {} + + # Extract ECU adresses to query from fingerprints + # ECUs using a subadress need be queried one by one, the rest can be done in parallel + addrs = [] + parallel_addrs = [] + + versions = FW_VERSIONS + if extra is not None: + versions.update(extra) + + for c in versions.values(): + for ecu_type, addr, sub_addr in c.keys(): + a = (addr, sub_addr) + if a not in ecu_types: + ecu_types[a] = ecu_type + + if sub_addr is None: + parallel_addrs.append(a) + else: + addrs.append([a]) + addrs.insert(0, parallel_addrs) + + fw_versions = {} + for i, addr in enumerate(tqdm(addrs, disable=not progress)): + for addr_chunk in chunks(addr): + for request, response in REQUESTS: + try: + query = IsoTpParallelQuery(sendcan, logcan, bus, addr_chunk, request, response, debug=debug) + t = 2 * timeout if i == 0 else timeout + fw_versions.update(query.get_data(t)) + except Exception: + cloudlog.warning(f"FW query exception: {traceback.format_exc()}") + + # Build capnp list to put into CarParams + car_fw = [] + for addr, version in fw_versions.items(): + f = car.CarParams.CarFw.new_message() + + f.ecu = ecu_types[addr] + f.fwVersion = version + f.address = addr[0] + + if addr[1] is not None: + f.subAddress = addr[1] + + car_fw.append(f) + + candidates = match_fw_to_car(fw_versions) + return candidates, car_fw + + +if __name__ == "__main__": + import time + import argparse + import cereal.messaging as messaging + from selfdrive.car.vin import get_vin + + + parser = argparse.ArgumentParser(description='Get firmware version of ECUs') + parser.add_argument('--scan', action='store_true') + parser.add_argument('--debug', action='store_true') + args = parser.parse_args() + + logcan = messaging.sub_sock('can') + sendcan = messaging.pub_sock('sendcan') + + extra = None + if args.scan: + extra = {"DEBUG": {}} + # Honda + for i in range(256): + extra["DEBUG"][(Ecu.unknown, 0x18da00f1 + (i << 8), None)] = [] + extra["DEBUG"][(Ecu.unknown, 0x700 + i, None)] = [] + extra["DEBUG"][(Ecu.unknown, 0x750, i)] = [] + + time.sleep(1.) + + t = time.time() + print("Getting vin...") + addr, vin = get_vin(logcan, sendcan, 1, retry=10, debug=args.debug) + print(f"VIN: {vin}") + print("Getting VIN took %.3f s" % (time.time() - t)) + print() + + t = time.time() + candidates, fw_vers = get_fw_versions(logcan, sendcan, 1, extra=extra, debug=args.debug, progress=True) + + print() + print("Found FW versions") + print("{") + for version in fw_vers: + subaddr = None if version.subAddress == 0 else hex(version.subAddress) + print(f" (Ecu.{version.ecu}, {hex(version.address)}, {subaddr}): [{version.fwVersion}]") + print("}") + + + print() + print("Possible matches:", candidates) + print("Getting fw took %.3f s" % (time.time() - t)) diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index eee03b11d3..b58a1a9979 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -43,12 +43,11 @@ class CarInterface(CarInterfaceBase): return float(accel) / 4.0 @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): ret = car.CarParams.new_message() ret.carName = "gm" ret.carFingerprint = candidate - ret.carVin = vin ret.isPandaBlack = has_relay ret.enableCruise = False diff --git a/selfdrive/car/honda/carcontroller.py b/selfdrive/car/honda/carcontroller.py index 2ba51ce4e6..9b0e0706ce 100644 --- a/selfdrive/car/honda/carcontroller.py +++ b/selfdrive/car/honda/carcontroller.py @@ -1,12 +1,14 @@ from collections import namedtuple +from cereal import car from common.realtime import DT_CTRL from selfdrive.controls.lib.drive_helpers import rate_limit from common.numpy_fast import clip from selfdrive.car import create_gas_command from selfdrive.car.honda import hondacan -from selfdrive.car.honda.values import AH, CruiseButtons, CAR +from selfdrive.car.honda.values import CruiseButtons, CAR, VISUAL_HUD from opendbc.can.packer import CANPacker +VisualAlert = car.CarControl.HUDControl.VisualAlert def actuator_hystereses(brake, braking, brake_steady, v_ego, car_fingerprint): # hyst params @@ -56,25 +58,25 @@ def process_hud_alert(hud_alert): fcw_display = 0 steer_required = 0 acc_alert = 0 - if hud_alert == AH.NONE: # no alert - pass - elif hud_alert == AH.FCW: # FCW - fcw_display = hud_alert[1] - elif hud_alert == AH.STEER: # STEER - steer_required = hud_alert[1] - else: # any other ACC alert - acc_alert = hud_alert[1] + + # priority is: FCW, steer required, all others + if hud_alert == VisualAlert.fcw: + fcw_display = VISUAL_HUD[hud_alert.raw] + elif hud_alert == VisualAlert.steerRequired: + steer_required = VISUAL_HUD[hud_alert.raw] + else: + acc_alert = VISUAL_HUD[hud_alert.raw] return fcw_display, steer_required, acc_alert HUDData = namedtuple("HUDData", - ["pcm_accel", "v_cruise", "mini_car", "car", "X4", - "lanes", "fcw", "acc_alert", "steer_required"]) + ["pcm_accel", "v_cruise", "car", + "lanes", "fcw", "acc_alert", "steer_required"]) class CarController(): - def __init__(self, dbc_name): + def __init__(self, dbc_name, CP): self.braking = False self.brake_steady = 0. self.brake_last = 0. @@ -82,6 +84,11 @@ class CarController(): self.last_pump_ts = 0. self.packer = CANPacker(dbc_name) self.new_radar_config = False + self.eps_modified = False + for fw in CP.carFw: + if fw.ecu == "eps" and b"," in fw.fwVersion: + print("EPS FW MODIFIED!") + self.eps_modified = True def update(self, enabled, CS, frame, actuators, \ pcm_speed, pcm_override, pcm_cancel_cmd, pcm_accel, \ @@ -96,7 +103,7 @@ class CarController(): pcm_cancel_cmd = True # *** rate limit after the enable check *** - self.brake_last = rate_limit(brake, self.brake_last, -2., 1./100) + self.brake_last = rate_limit(brake, self.brake_last, -2., DT_CTRL) # vehicle hud display, wait for one update from 10Hz 0x304 msg if hud_show_lanes: @@ -114,8 +121,8 @@ class CarController(): fcw_display, steer_required, acc_alert = process_hud_alert(hud_alert) - hud = HUDData(int(pcm_accel), int(round(hud_v_cruise)), 1, hud_car, - 0xc1, hud_lanes, fcw_display, acc_alert, steer_required) + hud = HUDData(int(pcm_accel), int(round(hud_v_cruise)), hud_car, + hud_lanes, fcw_display, acc_alert, steer_required) # **** process the car messages **** @@ -124,9 +131,11 @@ class CarController(): if CS.CP.carFingerprint in (CAR.ACURA_ILX): STEER_MAX = 0xF00 elif CS.CP.carFingerprint in (CAR.CRV, CAR.ACURA_RDX): - STEER_MAX = 0x3e8 # CR-V only uses 12-bits and requires a lower value (max value from energee) + STEER_MAX = 0x3e8 # CR-V only uses 12-bits and requires a lower value elif CS.CP.carFingerprint in (CAR.ODYSSEY_CHN): STEER_MAX = 0x7FFF + elif CS.CP.carFingerprint in (CAR.CIVIC) and self.eps_modified: + STEER_MAX = 0x1400 else: STEER_MAX = 0x1000 @@ -135,6 +144,12 @@ class CarController(): apply_brake = int(clip(self.brake_last * BRAKE_MAX, 0, BRAKE_MAX - 1)) apply_steer = int(clip(-actuators.steer * STEER_MAX, -STEER_MAX, STEER_MAX)) + if CS.CP.carFingerprint in (CAR.CIVIC) and self.eps_modified: + if apply_steer > 0xA00: + apply_steer = (apply_steer - 0xA00) / 2 + 0xA00 + elif apply_steer < -0xA00: + apply_steer = (apply_steer + 0xA00) / 2 - 0xA00 + lkas_active = enabled and not CS.steer_not_allowed # Send CAN commands. diff --git a/selfdrive/car/honda/carstate.py b/selfdrive/car/honda/carstate.py index 55f86d25ce..39b91c8664 100644 --- a/selfdrive/car/honda/carstate.py +++ b/selfdrive/car/honda/carstate.py @@ -41,8 +41,8 @@ def get_can_signals(CP): ("WHEEL_SPEED_RR", "WHEEL_SPEEDS", 0), ("STEER_ANGLE", "STEERING_SENSORS", 0), ("STEER_ANGLE_RATE", "STEERING_SENSORS", 0), + ("MOTOR_TORQUE", "STEER_MOTOR_TORQUE", 0), ("STEER_TORQUE_SENSOR", "STEER_STATUS", 0), - ("STEER_TORQUE_MOTOR", "STEER_STATUS", 0), ("LEFT_BLINKER", "SCM_FEEDBACK", 0), ("RIGHT_BLINKER", "SCM_FEEDBACK", 0), ("GEAR", "GEARBOX", 0), @@ -325,7 +325,7 @@ class CarState(): self.car_gas = cp.vl["GAS_PEDAL_2"]['CAR_GAS'] self.steer_torque_driver = cp.vl["STEER_STATUS"]['STEER_TORQUE_SENSOR'] - self.steer_torque_motor = cp.vl["STEER_STATUS"]['STEER_TORQUE_MOTOR'] + self.steer_torque_motor = cp.vl["STEER_MOTOR_TORQUE"]['MOTOR_TORQUE'] self.steer_override = abs(self.steer_torque_driver) > STEER_THRESHOLD[self.CP.carFingerprint] self.brake_switch = cp.vl["POWERTRAIN_DATA"]['BRAKE_SWITCH'] diff --git a/selfdrive/car/honda/hondacan.py b/selfdrive/car/honda/hondacan.py index 411d0c881f..38d099fdce 100644 --- a/selfdrive/car/honda/hondacan.py +++ b/selfdrive/car/honda/hondacan.py @@ -54,7 +54,7 @@ def create_ui_commands(packer, pcm_speed, hud, car_fingerprint, is_metric, idx, 'PCM_SPEED': pcm_speed * CV.MS_TO_KPH, 'PCM_GAS': hud.pcm_accel, 'CRUISE_SPEED': hud.v_cruise, - 'ENABLE_MINI_CAR': hud.mini_car, + 'ENABLE_MINI_CAR': 1, 'HUD_LEAD': hud.car, 'HUD_DISTANCE': 3, # max distance setting on display 'IMPERIAL_UNIT': int(not is_metric), diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 9ffc92e75b..b1abeed3dc 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -8,12 +8,12 @@ from selfdrive.config import Conversions as CV from selfdrive.controls.lib.drive_helpers import create_event, EventTypes as ET, get_events from selfdrive.controls.lib.vehicle_model import VehicleModel from selfdrive.car.honda.carstate import CarState, get_can_parser, get_cam_can_parser -from selfdrive.car.honda.values import CruiseButtons, CAR, HONDA_BOSCH, VISUAL_HUD, ECU, ECU_FINGERPRINT, FINGERPRINTS +from selfdrive.car.honda.values import CruiseButtons, CAR, HONDA_BOSCH, ECU, ECU_FINGERPRINT, FINGERPRINTS from selfdrive.car import STD_CARGO_KG, CivicParams, scale_rot_inertia, scale_tire_stiffness, is_ecu_disconnected, gen_empty_fingerprint -from selfdrive.controls.lib.planner import _A_CRUISE_MAX_V +from selfdrive.controls.lib.planner import _A_CRUISE_MAX_V_FOLLOWING from selfdrive.car.interfaces import CarInterfaceBase -A_ACC_MAX = max(_A_CRUISE_MAX_V) +A_ACC_MAX = max(_A_CRUISE_MAX_V_FOLLOWING) ButtonType = car.CarState.ButtonEvent.Type GearShifter = car.CarState.GearShifter @@ -91,7 +91,7 @@ class CarInterface(CarInterfaceBase): self.CC = None if CarController is not None: - self.CC = CarController(self.cp.dbc_name) + self.CC = CarController(self.cp.dbc_name, CP) if self.CS.CP.carFingerprint == CAR.ACURA_ILX: self.compute_gb = get_compute_gb_acura() @@ -131,22 +131,21 @@ class CarInterface(CarInterfaceBase): return float(max(max_accel, a_target / A_ACC_MAX)) * min(speedLimiter, accelLimiter) @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): ret = car.CarParams.new_message() ret.carName = "honda" ret.carFingerprint = candidate - ret.carVin = vin ret.isPandaBlack = has_relay if candidate in HONDA_BOSCH: - ret.safetyModel = car.CarParams.SafetyModel.hondaBosch + ret.safetyModel = car.CarParams.SafetyModel.hondaBoschHarness if has_relay else car.CarParams.SafetyModel.hondaBoschGiraffe rdr_bus = 0 if has_relay else 2 ret.enableCamera = is_ecu_disconnected(fingerprint[rdr_bus], FINGERPRINTS, ECU_FINGERPRINT, candidate, ECU.CAM) or has_relay ret.radarOffCan = True ret.openpilotLongitudinalControl = False else: - ret.safetyModel = car.CarParams.SafetyModel.honda + ret.safetyModel = car.CarParams.SafetyModel.hondaNidec ret.enableCamera = is_ecu_disconnected(fingerprint[0], FINGERPRINTS, ECU_FINGERPRINT, candidate, ECU.CAM) or has_relay ret.enableGasInterceptor = 0x201 in fingerprint[0] ret.openpilotLongitudinalControl = ret.enableCamera @@ -165,6 +164,11 @@ class CarInterface(CarInterfaceBase): ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]] ret.lateralTuning.pid.kf = 0.00006 # conservative feed-forward + eps_modified = False + for fw in car_fw: + if fw.ecu == "eps" and b"," in fw.fwVersion: + eps_modified = True + if candidate in [CAR.CIVIC, CAR.CIVIC_BOSCH]: stop_and_go = True ret.mass = CivicParams.MASS @@ -173,7 +177,8 @@ class CarInterface(CarInterfaceBase): ret.steerRatio = 15.38 # 10.93 is end-to-end spec tire_stiffness_factor = 1. - ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.4], [0.12]] if eps_modified else [[0.8], [0.24]] + ret.lateralTuning.pid.kf = 0.00006 ret.longitudinalTuning.kpBP = [0., 5., 35.] ret.longitudinalTuning.kpV = [3.6, 2.4, 1.5] ret.longitudinalTuning.kiBP = [0., 35.] @@ -575,8 +580,6 @@ class CarInterface(CarInterfaceBase): else: hud_v_cruise = 255 - hud_alert = VISUAL_HUD[c.hudControl.visualAlert.raw] - pcm_accel = int(clip(c.cruiseControl.accelOverride, 0, 1) * 0xc6) can_sends = self.CC.update(c.enabled, self.CS, self.frame, @@ -588,7 +591,7 @@ class CarInterface(CarInterfaceBase): hud_v_cruise, c.hudControl.lanesVisible, hud_show_car=c.hudControl.leadVisible, - hud_alert=hud_alert) + hud_alert=c.hudControl.visualAlert) self.frame += 1 return can_sends diff --git a/selfdrive/car/honda/values.py b/selfdrive/car/honda/values.py index 90dfd4eab3..4301128bc6 100644 --- a/selfdrive/car/honda/values.py +++ b/selfdrive/car/honda/values.py @@ -1,6 +1,7 @@ from cereal import car from selfdrive.car import dbc_dict +Ecu = car.CarParams.Ecu VisualAlert = car.CarControl.HUDControl.VisualAlert # Car button codes @@ -10,28 +11,18 @@ class CruiseButtons: CANCEL = 2 MAIN = 1 -class AH: - #[alert_idx, value] - # See dbc files for info on values" - NONE = [0, 0] - FCW = [1, 1] - STEER = [2, 1] - BRAKE_PRESSED = [3, 10] - GEAR_NOT_D = [4, 6] - SEATBELT = [5, 5] - SPEED_TOO_HIGH = [6, 8] - +# See dbc files for info on values" VISUAL_HUD = { - VisualAlert.none: AH.NONE, - VisualAlert.fcw: AH.FCW, - VisualAlert.steerRequired: AH.STEER, - VisualAlert.brakePressed: AH.BRAKE_PRESSED, - VisualAlert.wrongGear: AH.GEAR_NOT_D, - VisualAlert.seatbeltUnbuckled: AH.SEATBELT, - VisualAlert.speedTooHigh: AH.SPEED_TOO_HIGH} + VisualAlert.none: 0, + VisualAlert.fcw: 1, + VisualAlert.steerRequired: 1, + VisualAlert.brakePressed: 10, + VisualAlert.wrongGear: 6, + VisualAlert.seatbeltUnbuckled: 5, + VisualAlert.speedTooHigh: 8} class ECU: - CAM = 0 + CAM = Ecu.fwdCamera class CAR: ACCORD = "HONDA ACCORD 2018 SPORT 2T" @@ -81,9 +72,8 @@ FINGERPRINTS = { CAR.CRV: [{ 57: 3, 145: 8, 316: 8, 340: 8, 342: 6, 344: 8, 380: 8, 398: 3, 399: 6, 401: 8, 404: 4, 420: 8, 422: 8, 426: 8, 432: 7, 464: 8, 474: 5, 476: 4, 487: 4, 490: 8, 493: 3, 506: 8, 507: 1, 512: 6, 513: 6, 542: 7, 545: 4, 597: 8, 660: 8, 661: 4, 773: 7, 777: 8, 780: 8, 800: 8, 804: 8, 808: 8, 829: 5, 882: 2, 884: 7, 888: 8, 891: 8, 892: 8, 923: 2, 929: 8, 983: 8, 985: 3, 1024: 5, 1027: 5, 1029: 8, 1033: 5, 1036: 8, 1039: 8, 1057: 5, 1064: 7, 1108: 8, 1125: 8, 1296: 8, 1365: 5, 1424: 5, 1600: 5, 1601: 8, }], - # msg 1115 has seen with len 2 and 4, so ignore it CAR.CRV_5G: [{ - 57: 3, 148: 8, 199: 4, 228: 5, 231: 5, 232: 7, 304: 8, 330: 8, 340: 8, 344: 8, 380: 8, 399: 7, 401: 8, 420: 8, 423: 2, 427: 3, 428: 8, 432: 7, 441: 5, 446: 3, 450: 8, 464: 8, 467: 2, 469: 3, 470: 2, 474: 8, 476: 7, 477: 8, 479: 8, 490: 8, 493: 5, 495: 8, 507: 1, 545: 6, 597: 8, 661: 4, 662: 4, 773: 7, 777: 8, 780: 8, 795: 8, 800: 8, 804: 8, 806: 8, 808: 8, 814: 4, 815: 8, 817: 4, 825: 4, 829: 5, 862: 8, 881: 8, 882: 4, 884: 8, 888: 8, 891: 8, 927: 8, 918: 7, 929: 8, 983: 8, 985: 3, 1024: 5, 1027: 5, 1029: 8, 1036: 8, 1039: 8, 1064: 7, 1108: 8, 1092: 1, 1125: 8, 1127: 2, 1296: 8, 1302: 8, 1322: 5, 1361: 5, 1365: 5, 1424: 5, 1600: 5, 1601: 8, 1618: 5, 1633: 8, 1670: 5 + 57: 3, 148: 8, 199: 4, 228: 5, 231: 5, 232: 7, 304: 8, 330: 8, 340: 8, 344: 8, 380: 8, 399: 7, 401: 8, 420: 8, 423: 2, 427: 3, 428: 8, 432: 7, 441: 5, 446: 3, 450: 8, 464: 8, 467: 2, 469: 3, 470: 2, 474: 8, 476: 7, 477: 8, 479: 8, 490: 8, 493: 5, 495: 8, 507: 1, 545: 6, 597: 8, 661: 4, 662: 4, 773: 7, 777: 8, 780: 8, 795: 8, 800: 8, 804: 8, 806: 8, 808: 8, 814: 4, 815: 8, 817: 4, 825: 4, 829: 5, 862: 8, 881: 8, 882: 4, 884: 8, 888: 8, 891: 8, 927: 8, 918: 7, 929: 8, 983: 8, 985: 3, 1024: 5, 1027: 5, 1029: 8, 1036: 8, 1039: 8, 1064: 7, 1108: 8, 1092: 1, 1115: 2, 1125: 8, 1127: 2, 1296: 8, 1302: 8, 1322: 5, 1361: 5, 1365: 5, 1424: 5, 1600: 5, 1601: 8, 1618: 5, 1633: 8, 1670: 5 }], CAR.CRV_HYBRID: [{ 57: 3, 148: 8, 228: 5, 304: 8, 330: 8, 344: 8, 380: 8, 387: 8, 388: 8, 399: 7, 408: 6, 415: 6, 419: 8, 420: 8, 427: 3, 428: 8, 432: 7, 441: 5, 450: 8, 464: 8, 477: 8, 479: 8, 490: 8, 495: 8, 525: 8, 531: 8, 545: 6, 662: 4, 773: 7, 777: 8, 780: 8, 804: 8, 806: 8, 808: 8, 814: 4, 829: 5, 833: 6, 862: 8, 884: 8, 891: 8, 927: 8, 929: 8, 930: 8, 931: 8, 1302: 8, 1361: 5, 1365: 5, 1600: 5, 1601: 8, 1626: 5, 1627: 5 @@ -130,6 +120,36 @@ for c in FINGERPRINTS: for d in DIAG_MSGS: FINGERPRINTS[c][f][d] = DIAG_MSGS[d] +# TODO: Figure out what is relevant +FW_VERSIONS = { + CAR.CIVIC: { + (Ecu.unknown, 0x18da10f1, None): [b'37805-5AA-L660\x00\x00'], + (Ecu.unknown, 0x18da1ef1, None): [b'28101-5CG-A050\x00\x00'], + (Ecu.unknown, 0x18da28f1, None): [b'57114-TBA-A550\x00\x00'], + (Ecu.eps, 0x18da30f1, None): [b'39990-TBA-A030\x00\x00', b'39990-TBA,A030\x00\x00'], + (Ecu.unknown, 0x18da53f1, None): [b'77959-TBA-A030\x00\x00'], + (Ecu.unknown, 0x18da60f1, None): [b'78109-TBC-A310\x00\x00'], + (Ecu.unknown, 0x18dab0f1, None): [b'36161-TBC-A030\x00\x00'], + (Ecu.unknown, 0x18daeff1, None): [b'38897-TBA-A020\x00\x00'], + + }, + CAR.ACCORD: { + (Ecu.unknown, 0x18da10f1, None): [b'37805-6B2-A650\x00\x00'], + (Ecu.unknown, 0x18da0bf1, None): [b'54008-TVC-A910\x00\x00'], + (Ecu.unknown, 0x18da1ef1, None): [b'28102-6B8-A560\x00\x00'], + (Ecu.unknown, 0x18da2bf1, None): [b'46114-TVA-A060\x00\x00'], + (Ecu.unknown, 0x18da28f1, None): [b'57114-TVA-C050\x00\x00'], + (Ecu.eps, 0x18da30f1, None): [b'39990-TVA-A150\x00\x00'], + (Ecu.unknown, 0x18da3af1, None): [b'39390-TVA-A020\x00\x00'], + (Ecu.unknown, 0x18da53f1, None): [b'77959-TVA-A460\x00\x00'], + (Ecu.unknown, 0x18da60f1, None): [b'78109-TVC-A210\x00\x00'], + (Ecu.unknown, 0x18da61f1, None): [b'78209-TVA-A010\x00\x00'], + (Ecu.unknown, 0x18dab0f1, None): [b'36802-TVA-A160\x00\x00'], + (Ecu.unknown, 0x18dab5f1, None): [b'36161-TVA-A060\x00\x00'], + (Ecu.unknown, 0x18daeff1, None): [b'38897-TVA-A010\x00\x00'], + } +} + DBC = { CAR.ACCORD: dbc_dict('honda_accord_s2t_2018_can_generated', None), CAR.ACCORD_15: dbc_dict('honda_accord_lx15t_2018_can_generated', None), diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 39d04d3bc8..50c31af3d2 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -38,13 +38,12 @@ class CarInterface(CarInterfaceBase): return float(accel) / 3.0 @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): ret = car.CarParams.new_message() ret.carName = "hyundai" ret.carFingerprint = candidate - ret.carVin = vin ret.isPandaBlack = has_relay ret.radarOffCan = True ret.safetyModel = car.CarParams.SafetyModel.hyundai diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index 7a32752781..ca1972a167 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -18,7 +18,7 @@ class CarInterfaceBase(): raise NotImplementedError @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): raise NotImplementedError # returns a car.CarState, pass in car.CarControl diff --git a/selfdrive/car/isotp_parallel_query.py b/selfdrive/car/isotp_parallel_query.py new file mode 100644 index 0000000000..cda36d50fb --- /dev/null +++ b/selfdrive/car/isotp_parallel_query.py @@ -0,0 +1,128 @@ +import time +from collections import defaultdict +from functools import partial + +import cereal.messaging as messaging +from selfdrive.swaglog import cloudlog +from selfdrive.boardd.boardd import can_list_to_can_capnp +from panda.python.uds import CanClient, IsoTpMessage, FUNCTIONAL_ADDRS, get_rx_addr_for_tx_addr + + +class IsoTpParallelQuery(): + def __init__(self, sendcan, logcan, bus, addrs, request, response, functional_addr=False, debug=False): + self.sendcan = sendcan + self.logcan = logcan + self.bus = bus + self.request = request + self.response = response + self.debug = debug + self.functional_addr = functional_addr + + self.real_addrs = [] + for a in addrs: + if isinstance(a, tuple): + self.real_addrs.append(a) + else: + self.real_addrs.append((a, None)) + + self.msg_addrs = {tx_addr: get_rx_addr_for_tx_addr(tx_addr[0]) for tx_addr in self.real_addrs} + self.msg_buffer = defaultdict(list) + + def rx(self): + """Drain can socket and sort messages into buffers based on address""" + can_packets = messaging.drain_sock(self.logcan, wait_for_one=True) + + for packet in can_packets: + for msg in packet.can: + if msg.src == self.bus: + if self.functional_addr: + if (0x7E8 <= msg.address <= 0x7EF) or (0x18DAF100 <= msg.address <= 0x18DAF1FF): + fn_addr = next(a for a in FUNCTIONAL_ADDRS if msg.address - a <= 32) + self.msg_buffer[fn_addr].append((msg.address, msg.busTime, msg.dat, msg.src)) + elif msg.address in self.msg_addrs.values(): + self.msg_buffer[msg.address].append((msg.address, msg.busTime, msg.dat, msg.src)) + + def _can_tx(self, tx_addr, dat, bus): + """Helper function to send single message""" + msg = [tx_addr, 0, dat, bus] + self.sendcan.send(can_list_to_can_capnp([msg], msgtype='sendcan')) + + def _can_rx(self, addr, sub_addr=None): + """Helper function to retrieve message with specified address and subadress from buffer""" + keep_msgs = [] + + if sub_addr is None: + msgs = self.msg_buffer[addr] + else: + # Filter based on subadress + msgs = [] + for m in self.msg_buffer[addr]: + first_byte = m[2][0] + if first_byte == sub_addr: + msgs.append(m) + else: + keep_msgs.append(m) + + self.msg_buffer[addr] = keep_msgs + return msgs + + def _drain_rx(self): + messaging.drain_sock(self.logcan) + self.msg_buffer = defaultdict(list) + + def get_data(self, timeout): + self._drain_rx() + + # Create message objects + msgs = {} + request_counter = {} + request_done = {} + for tx_addr, rx_addr in self.msg_addrs.items(): + # rx_addr not set when using functional tx addr + id_addr = rx_addr or tx_addr[0] + sub_addr = tx_addr[1] + + can_client = CanClient(self._can_tx, partial(self._can_rx, id_addr, sub_addr=sub_addr), tx_addr[0], rx_addr, self.bus, sub_addr=sub_addr, debug=self.debug) + + max_len = 8 if sub_addr is None else 7 + + msg = IsoTpMessage(can_client, timeout=0, max_len=max_len, debug=self.debug) + msg.send(self.request[0]) + + msgs[tx_addr] = msg + request_counter[tx_addr] = 0 + request_done[tx_addr] = False + + results = {} + start_time = time.time() + while True: + self.rx() + + if all(request_done.values()): + break + + for tx_addr, msg in msgs.items(): + dat = msg.recv() + + if not dat: + continue + + counter = request_counter[tx_addr] + expected_response = self.response[counter] + response_valid = dat[:len(expected_response)] == expected_response + + if response_valid: + if counter + 1 < len(self.request): + msg.send(self.request[counter + 1]) + request_counter[tx_addr] += 1 + else: + results[tx_addr] = dat[len(expected_response):] + request_done[tx_addr] = True + else: + request_done[tx_addr] = True + cloudlog.warning(f"iso-tp query bad response: 0x{bytes.hex(dat)}") + + if time.time() - start_time > timeout: + break + + return results diff --git a/selfdrive/car/mock/interface.py b/selfdrive/car/mock/interface.py index 30df9f2fd3..09c5b5c612 100755 --- a/selfdrive/car/mock/interface.py +++ b/selfdrive/car/mock/interface.py @@ -34,7 +34,7 @@ class CarInterface(CarInterfaceBase): return accel @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): ret = car.CarParams.new_message() diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index cd102766df..d4388727bb 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -35,13 +35,12 @@ class CarInterface(CarInterfaceBase): return float(accel) / 4.0 @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): ret = car.CarParams.new_message() ret.carName = "subaru" ret.radarOffCan = True ret.carFingerprint = candidate - ret.carVin = vin ret.isPandaBlack = has_relay ret.safetyModel = car.CarParams.SafetyModel.subaru diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index 3c6772228c..83f499f450 100755 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -37,13 +37,12 @@ class CarInterface(CarInterfaceBase): return float(accel) / 3.0 @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): ret = car.CarParams.new_message() ret.carName = "toyota" ret.carFingerprint = candidate - ret.carVin = vin ret.isPandaBlack = has_relay ret.safetyModel = car.CarParams.SafetyModel.toyota diff --git a/selfdrive/car/toyota/values.py b/selfdrive/car/toyota/values.py index 5c7c49a69b..f8edbf48bc 100644 --- a/selfdrive/car/toyota/values.py +++ b/selfdrive/car/toyota/values.py @@ -1,4 +1,6 @@ from selfdrive.car import dbc_dict +from cereal import car +Ecu = car.CarParams.Ecu # Steer torque limits class SteerLimitParams: @@ -31,9 +33,9 @@ class CAR: class ECU: - CAM = 0 # camera - DSU = 1 # driving support unit - APGS = 2 # advanced parking guidance system + CAM = Ecu.fwdCamera # camera + DSU = Ecu.dsu # driving support unit + APGS = Ecu.apgs # advanced parking guidance system # addr: (ecu, cars, bus, 1/freq*100, vl) @@ -215,6 +217,32 @@ FINGERPRINTS = { }] } +FW_VERSIONS = { + CAR.COROLLA_TSS2: { + (Ecu.engine, 0x700, None): [b'\x01896630ZG5000\x00\x00\x00\x00'], + (Ecu.eps, 0x7a1, None): [b'\x018965B12350\x00\x00\x00\x00\x00\x00'], + (Ecu.esp, 0x7b0, None): [b'\x01F152602280\x00\x00\x00\x00\x00\x00'], + (Ecu.fwdRadar, 0x750, 0xf): [b'\x018821F3301100\x00\x00\x00\x00'], + (Ecu.fwdCamera, 0x750, 0x6d): [b'\x028646F1201200\x00\x00\x00\x008646G26011A0\x00\x00\x00\x00'], + }, + CAR.PRIUS: { + (Ecu.engine, 0x700, None): [b'\x03896634759200\x00\x00\x00\x008966A4703000\x00\x00\x00\x00897CF4701003\x00\x00\x00\x00'], + (Ecu.eps, 0x7a1, None): [b'8965B47023\x00\x00\x00\x00\x00\x00'], + (Ecu.esp, 0x7b0, None): [b'F152647416\x00\x00\x00\x00\x00\x00'], + (Ecu.dsu, 0x791, None): [b'881514703100\x00\x00\x00\x00'], + (Ecu.fwdRadar, 0x750, 0xf): [b'8821F4702100\x00\x00\x00\x00'], + (Ecu.fwdCamera, 0x750, 0x6d): [b'8646F4702100\x00\x00\x00\x00'], + }, + CAR.RAV4: { + (Ecu.engine, 0x7e0, None): [b'\x02342Q2100\x00\x00\x00\x00\x00\x00\x00\x0054213000\x00\x00\x00\x00\x00\x00\x00\x00'], + (Ecu.eps, 0x7a1, None): [b'8965B42083\x00\x00\x00\x00\x00\x00'], + (Ecu.esp, 0x7b0, None): [b'F15260R103\x00\x00\x00\x00\x00\x00'], + (Ecu.dsu, 0x791, None): [b'881514201400\x00\x00\x00\x00'], + (Ecu.fwdRadar, 0x750, 0xf): [b'8821F4702100\x00\x00\x00\x00'], + (Ecu.fwdCamera, 0x750, 0x6d): [b'8646F4202100\x00\x00\x00\x00'], + } +} + STEER_THRESHOLD = 100 DBC = { diff --git a/selfdrive/car/vin.py b/selfdrive/car/vin.py index 605e22d50d..648f416511 100755 --- a/selfdrive/car/vin.py +++ b/selfdrive/car/vin.py @@ -1,104 +1,33 @@ #!/usr/bin/env python3 +import traceback + import cereal.messaging as messaging -from selfdrive.boardd.boardd import can_list_to_can_capnp +from panda.python.uds import FUNCTIONAL_ADDRS +from selfdrive.car.isotp_parallel_query import IsoTpParallelQuery +from selfdrive.swaglog import cloudlog +VIN_REQUEST = b'\x09\x02' +VIN_RESPONSE = b'\x49\x02\x01' VIN_UNKNOWN = "0" * 17 -# sanity checks on response messages from vin query -def is_vin_response_valid(can_dat, step, cnt): - if len(can_dat) != 8: - # ISO-TP meesages are all 8 bytes - return False - - if step == 0: - # VIN does not fit in a single message and it's 20 bytes of data - if can_dat[0] != 0x10 or can_dat[1] != 0x14: - return False - - if step == 1 and cnt == 0: - # first response after a CONTINUE query is sent - if can_dat[0] != 0x21: - return False - - if step == 1 and cnt == 1: - # second response after a CONTINUE query is sent - if can_dat[0] != 0x22: - return False - - return True - - -class VinQuery(): - def __init__(self, bus): - self.bus = bus - # works on standard 11-bit addresses for diagnostic. Tested on Toyota and Subaru; - # Honda uses the extended 29-bit addresses, and unfortunately only works from OBDII - self.query_ext_msgs = [[0x18DB33F1, 0, b'\x02\x09\x02'.ljust(8, b"\x00"), bus], - [0x18DA10f1, 0, b'\x30'.ljust(8, b"\x00"), bus]] - self.query_nor_msgs = [[0x7df, 0, b'\x02\x09\x02'.ljust(8, b"\x00"), bus], - [0x7e0, 0, b'\x30'.ljust(8, b"\x00"), bus]] - - self.cnts = [1, 2] # number of messages to wait for at each iteration - self.step = 0 - self.cnt = 0 - self.responded = False - self.never_responded = True - self.dat = b"" - self.got_vin = False - self.vin = VIN_UNKNOWN - - def check_response(self, msg): - # have we got a VIN query response? - if msg.src == self.bus and msg.address in [0x18daf110, 0x7e8]: - self.never_responded = False - # basic sanity checks on ISO-TP response - if is_vin_response_valid(msg.dat, self.step, self.cnt): - self.dat += bytes(msg.dat[2:]) if self.step == 0 else bytes(msg.dat[1:]) - self.cnt += 1 - if self.cnt == self.cnts[self.step]: - self.responded = True - self.step += 1 - if self.step == len(self.cnts): - self.got_vin = True - def send_query(self, sendcan): - # keep sending VIN query if ECU isn't responsing. - # sendcan is probably not ready due to the zmq slow joiner syndrome - if self.never_responded or (self.responded and not self.got_vin): - sendcan.send(can_list_to_can_capnp([self.query_ext_msgs[self.step]], msgtype='sendcan')) - sendcan.send(can_list_to_can_capnp([self.query_nor_msgs[self.step]], msgtype='sendcan')) - self.responded = False - self.cnt = 0 +def get_vin(logcan, sendcan, bus, timeout=0.1, retry=5, debug=False): + for i in range(retry): + try: + query = IsoTpParallelQuery(sendcan, logcan, bus, FUNCTIONAL_ADDRS, [VIN_REQUEST], [VIN_RESPONSE], functional_addr=True, debug=debug) + for addr, vin in query.get_data(timeout).items(): + return addr[0], vin.decode() + print(f"vin query retry ({i+1}) ...") + except Exception: + cloudlog.warning(f"VIN query exception: {traceback.format_exc()}") - def get_vin(self): - if self.got_vin: - try: - self.vin = self.dat[3:].decode('utf8') - except UnicodeDecodeError: - pass # have seen unexpected non-unicode characters - return self.vin - - -def get_vin(logcan, sendcan, bus, query_time=1.): - vin_query = VinQuery(bus) - frame = 0 - - # 1s max of VIN query time - while frame < query_time * 100 and not vin_query.got_vin: - a = messaging.get_one_can(logcan) - - for can in a.can: - vin_query.check_response(can) - if vin_query.got_vin: - break - - vin_query.send_query(sendcan) - frame += 1 - - return vin_query.get_vin() + return 0, VIN_UNKNOWN if __name__ == "__main__": - logcan = messaging.sub_sock('can') + import time sendcan = messaging.pub_sock('sendcan') - print(get_vin(logcan, sendcan, 0)) + logcan = messaging.sub_sock('can') + time.sleep(1) + addr, vin = get_vin(logcan, sendcan, 1, debug=False) + print(hex(addr), vin) diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index 14c58b3679..0e8b5206d3 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -42,12 +42,11 @@ class CarInterface(CarInterfaceBase): return float(accel) / 4.0 @staticmethod - def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay=False): + def get_params(candidate, fingerprint=gen_empty_fingerprint(), has_relay=False, car_fw=[]): ret = car.CarParams.new_message() ret.carFingerprint = candidate ret.isPandaBlack = has_relay - ret.carVin = vin if candidate == CAR.GOLF: # Set common MQB parameters that will apply globally diff --git a/selfdrive/clocksd/.gitignore b/selfdrive/clocksd/.gitignore new file mode 100644 index 0000000000..a6d841d65e --- /dev/null +++ b/selfdrive/clocksd/.gitignore @@ -0,0 +1 @@ +clocksd diff --git a/selfdrive/clocksd/SConscript b/selfdrive/clocksd/SConscript new file mode 100644 index 0000000000..63c508c4fe --- /dev/null +++ b/selfdrive/clocksd/SConscript @@ -0,0 +1,2 @@ +Import('env', 'common', 'messaging') +env.Program('clocksd.cc', LIBS=['diag', 'time_genoff', common, messaging, 'capnp', 'zmq', 'kj']) \ No newline at end of file diff --git a/selfdrive/clocksd/clocksd.cc b/selfdrive/clocksd/clocksd.cc new file mode 100644 index 0000000000..0dba6259e2 --- /dev/null +++ b/selfdrive/clocksd/clocksd.cc @@ -0,0 +1,72 @@ +#include +#include +#include +#include +#include +#include +#include +#include "messaging.hpp" +#include "common/timing.h" +#include "cereal/gen/cpp/log.capnp.h" + +namespace { + int64_t arm_cntpct() { + int64_t v; + asm volatile("mrs %0, cntpct_el0" : "=r"(v)); + return v; + } +} + +int main() { + setpriority(PRIO_PROCESS, 0, -13); + + int err = 0; + Context *context = Context::create(); + + PubSocket* clock_publisher = PubSocket::create(context, "clocks"); + assert(clock_publisher != NULL); + + int timerfd = timerfd_create(CLOCK_BOOTTIME, 0); + assert(timerfd >= 0); + + struct itimerspec spec = {0}; + spec.it_interval.tv_sec = 1; + spec.it_interval.tv_nsec = 0; + spec.it_value.tv_sec = 1; + spec.it_value.tv_nsec = 0; + + err = timerfd_settime(timerfd, 0, &spec, 0); + assert(err == 0); + + uint64_t expirations = 0; + while ((err = read(timerfd, &expirations, sizeof(expirations)))) { + if (err < 0) break; + + uint64_t boottime = nanos_since_boot(); + uint64_t monotonic = nanos_monotonic(); + uint64_t monotonic_raw = nanos_monotonic_raw(); + uint64_t wall_time = nanos_since_epoch(); + + uint64_t modem_uptime_v = arm_cntpct() / 19200ULL; // 19.2 mhz clock + + capnp::MallocMessageBuilder msg; + cereal::Event::Builder event = msg.initRoot(); + event.setLogMonoTime(boottime); + auto clocks = event.initClocks(); + + clocks.setBootTimeNanos(boottime); + clocks.setMonotonicNanos(monotonic); + clocks.setMonotonicRawNanos(monotonic_raw); + clocks.setWallTimeNanos(wall_time); + clocks.setModemUptimeMillis(modem_uptime_v); + + auto words = capnp::messageToFlatArray(msg); + auto bytes = words.asBytes(); + clock_publisher->send((char*)bytes.begin(), bytes.size()); + } + + close(timerfd); + delete clock_publisher; + + return 0; +} \ No newline at end of file diff --git a/selfdrive/common/framebuffer.cc b/selfdrive/common/framebuffer.cc index 757c2a1ead..788b812997 100644 --- a/selfdrive/common/framebuffer.cc +++ b/selfdrive/common/framebuffer.cc @@ -1,4 +1,3 @@ - #include #include #include @@ -39,7 +38,6 @@ extern "C" void framebuffer_set_power(FramebufferState *s, int mode) { extern "C" FramebufferState* framebuffer_init( const char* name, int32_t layer, int alpha, - EGLDisplay *out_display, EGLSurface *out_surface, int *out_w, int *out_h) { status_t status; int success; @@ -131,11 +129,14 @@ extern "C" FramebufferState* framebuffer_init( const char brightness_level[] = BACKLIGHT_LEVEL; write(brightness_fd, brightness_level, strlen(brightness_level)); - - if (out_display) *out_display = s->display; - if (out_surface) *out_surface = s->surface; if (out_w) *out_w = w; if (out_h) *out_h = h; return s; } + +extern "C" void framebuffer_swap(FramebufferState *s) { + eglSwapBuffers(s->display, s->surface); + assert(glGetError() == GL_NO_ERROR); +} + diff --git a/selfdrive/common/framebuffer.h b/selfdrive/common/framebuffer.h index 6091eebce5..52c60d8ec7 100644 --- a/selfdrive/common/framebuffer.h +++ b/selfdrive/common/framebuffer.h @@ -11,10 +11,10 @@ typedef struct FramebufferState FramebufferState; FramebufferState* framebuffer_init( const char* name, int32_t layer, int alpha, - EGLDisplay *out_display, EGLSurface *out_surface, int *out_w, int *out_h); void framebuffer_set_power(FramebufferState *s, int mode); +void framebuffer_swap(FramebufferState *s); /* Display power modes */ enum { diff --git a/selfdrive/common/params.cc b/selfdrive/common/params.cc index 6e0e8b186f..79bc5d911f 100644 --- a/selfdrive/common/params.cc +++ b/selfdrive/common/params.cc @@ -243,10 +243,6 @@ int read_db_value(const char* params_path, const char* key, char** value, goto cleanup; } - // Remove one for null byte. - if (value_sz != NULL) { - *value_sz -= 1; - } result = 0; cleanup: diff --git a/selfdrive/common/util.c b/selfdrive/common/util.c index 01b8a0b6d9..9bdb23f999 100644 --- a/selfdrive/common/util.c +++ b/selfdrive/common/util.c @@ -19,7 +19,7 @@ void* read_file(const char* path, size_t* out_len) { long f_len = ftell(f); rewind(f); - char* buf = calloc(f_len + 1, 1); + char* buf = (char*)calloc(f_len, 1); assert(buf); size_t num_read = fread(buf, f_len, 1, f); @@ -31,7 +31,7 @@ void* read_file(const char* path, size_t* out_len) { } if (out_len) { - *out_len = f_len + 1; + *out_len = f_len; } return buf; @@ -54,6 +54,8 @@ int set_realtime_priority(int level) { memset(&sa, 0, sizeof(sa)); sa.sched_priority = level; return sched_setscheduler(tid, SCHED_FIFO, &sa); +#else + return -1; #endif } diff --git a/selfdrive/common/version.h b/selfdrive/common/version.h index 6f1cf7ff00..d61e42c497 100644 --- a/selfdrive/common/version.h +++ b/selfdrive/common/version.h @@ -1 +1 @@ -#define COMMA_VERSION "0.7-release" +#define COMMA_VERSION "0.7.1-release" diff --git a/selfdrive/common/visionimg.h b/selfdrive/common/visionimg.h index 74b0f3137d..1cc0cb0ac1 100644 --- a/selfdrive/common/visionimg.h +++ b/selfdrive/common/visionimg.h @@ -1,13 +1,12 @@ #ifndef VISIONIMG_H #define VISIONIMG_H -#ifdef QCOM +#include "common/visionbuf.h" + #include #include #include -#endif - -#include "common/visionbuf.h" +#undef Status #ifdef __cplusplus extern "C" { @@ -26,11 +25,9 @@ typedef struct VisionImg { void visionimg_compute_aligned_width_and_height(int width, int height, int *aligned_w, int *aligned_h); VisionImg visionimg_alloc_rgb24(int width, int height, VisionBuf *out_buf); -#ifdef QCOM EGLClientBuffer visionimg_to_egl(const VisionImg *img, void **pph); GLuint visionimg_to_gl(const VisionImg *img, EGLImageKHR *pkhr, void **pph); void visionimg_destroy_gl(EGLImageKHR khr, void *ph); -#endif #ifdef __cplusplus } // extern "C" diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index ad39b19b87..3cc1de90ef 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -67,7 +67,7 @@ def events_to_bytes(events): return ret -def data_sample(CI, CC, sm, can_sock, driver_status, state, mismatch_counter, params): +def data_sample(CI, CC, sm, can_sock, driver_status, state, mismatch_counter, can_error_counter, params): """Receive data from sockets and create events for battery, temperature and disk space""" # Update carstate from CAN and create events @@ -82,6 +82,7 @@ def data_sample(CI, CC, sm, can_sock, driver_status, state, mismatch_counter, pa # Check for CAN timeout if not can_strs: + can_error_counter += 1 events.append(create_event('canError', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE])) overtemp = sm['thermal'].thermalStatus >= ThermalStatus.red @@ -147,7 +148,7 @@ def data_sample(CI, CC, sm, can_sock, driver_status, state, mismatch_counter, pa if driver_status.terminal_alert_cnt >= MAX_TERMINAL_ALERTS or driver_status.terminal_time >= MAX_TERMINAL_DURATION: events.append(create_event("tooDistracted", [ET.NO_ENTRY])) - return CS, events, cal_perc, mismatch_counter + return CS, events, cal_perc, mismatch_counter, can_error_counter def state_transition(frame, CS, CP, state, events, soft_disable_timer, v_cruise_kph, AM): @@ -319,7 +320,7 @@ def state_control(frame, rcv_frame, plan, path_plan, CS, CP, state, events, v_cr def data_send(sm, pm, CS, CI, CP, VM, state, events, actuators, v_cruise_kph, rk, AM, driver_status, LaC, LoC, read_only, start_time, v_acc, a_acc, lac_log, events_prev, - last_blinker_frame, is_ldw_enabled): + last_blinker_frame, is_ldw_enabled, can_error_counter): """Send actuators and hud commands to the car, send controlsstate and MPC logging""" CC = car.CarControl.new_message() @@ -416,6 +417,7 @@ def data_send(sm, pm, CS, CI, CP, VM, state, events, actuators, v_cruise_kph, rk "startMonoTime": int(start_time * 1e9), "mapValid": sm['plan'].mapValid, "forceDecel": bool(force_decel), + "canErrorCounter": can_error_counter, } if CP.lateralTuning.which() == 'pid': @@ -534,6 +536,7 @@ def controlsd_thread(sm=None, pm=None, can_sock=None): v_cruise_kph = 255 v_cruise_kph_last = 0 mismatch_counter = 0 + can_error_counter = 0 last_blinker_frame = 0 events_prev = [] @@ -557,11 +560,13 @@ def controlsd_thread(sm=None, pm=None, can_sock=None): prof.checkpoint("Ratekeeper", ignore=True) # Sample data and compute car events - CS, events, cal_perc, mismatch_counter = data_sample(CI, CC, sm, can_sock, driver_status, state, mismatch_counter, params) + CS, events, cal_perc, mismatch_counter, can_error_counter = data_sample(CI, CC, sm, can_sock, driver_status, state, mismatch_counter, can_error_counter, params) prof.checkpoint("Sample") # Create alerts - if not sm.all_alive_and_valid(): + if not sm.alive['plan'] and sm.alive['pathPlan']: # only plan not being received: radar not communicating + events.append(create_event('radarCommIssue', [ET.NO_ENTRY, ET.SOFT_DISABLE])) + elif not sm.all_alive_and_valid(): events.append(create_event('commIssue', [ET.NO_ENTRY, ET.SOFT_DISABLE])) if not sm['pathPlan'].mpcSolutionValid: events.append(create_event('plannerError', [ET.NO_ENTRY, ET.IMMEDIATE_DISABLE])) @@ -583,6 +588,8 @@ def controlsd_thread(sm=None, pm=None, can_sock=None): events.append(create_event('internetConnectivityNeeded', [ET.NO_ENTRY, ET.PERMANENT])) if community_feature_disallowed: events.append(create_event('communityFeatureDisallowed', [ET.PERMANENT])) + if read_only and not passive: + events.append(create_event('carUnrecognized', [ET.PERMANENT])) # Only allow engagement with brake pressed when stopped behind another stopped car if CS.brakePressed and sm['plan'].vTargetFuture >= STARTING_TARGET_SPEED and not CP.radarOffCan and CS.vEgo < 0.3: @@ -603,7 +610,8 @@ def controlsd_thread(sm=None, pm=None, can_sock=None): # Publish data CC, events_prev = data_send(sm, pm, CS, CI, CP, VM, state, events, actuators, v_cruise_kph, rk, AM, driver_status, LaC, - LoC, read_only, start_time, v_acc, a_acc, lac_log, events_prev, last_blinker_frame, is_ldw_enabled) + LoC, read_only, start_time, v_acc, a_acc, lac_log, events_prev, last_blinker_frame, + is_ldw_enabled, can_error_counter) prof.checkpoint("Sent") rk.monitor_time() diff --git a/selfdrive/controls/lib/alerts.py b/selfdrive/controls/lib/alerts.py index e9295bfef7..83d430f071 100644 --- a/selfdrive/controls/lib/alerts.py +++ b/selfdrive/controls/lib/alerts.py @@ -410,6 +410,13 @@ ALERTS = [ AlertStatus.critical, AlertSize.full, Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), + Alert( + "radarCommIssue", + "TAKE CONTROL IMMEDIATELY", + "Radar Communication Issue", + AlertStatus.critical, AlertSize.full, + Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, 2., 2.), + Alert( "radarCanError", "TAKE CONTROL IMMEDIATELY", @@ -659,6 +666,13 @@ ALERTS = [ AlertStatus.normal, AlertSize.mid, Priority.LOW, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.), + Alert( + "radarCommIssueNoEntry", + "openpilot Unavailable", + "Radar Communication Issue", + AlertStatus.normal, AlertSize.mid, + Priority.LOW, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.), + Alert( "internetConnectivityNeededNoEntry", "openpilot Unavailable", @@ -739,11 +753,18 @@ ALERTS = [ Alert( "lowMemoryPermanent", - "RAM Memory Critically Low", + "RAM Critically Low", "Reboot your EON", AlertStatus.normal, AlertSize.mid, Priority.LOW_LOWEST, VisualAlert.none, AudibleAlert.none, 0., 0., .2), + Alert( + "carUnrecognizedPermanent", + "Dashcam Mode", + "Car Unrecognized", + AlertStatus.normal, AlertSize.mid, + Priority.LOW_LOWEST, VisualAlert.none, AudibleAlert.none, 0., 0., .2), + Alert( "vehicleModelInvalid", "Vehicle Parameter Identification Failed", diff --git a/selfdrive/controls/lib/driver_monitor.py b/selfdrive/controls/lib/driver_monitor.py index 13a8130b7c..7539559752 100644 --- a/selfdrive/controls/lib/driver_monitor.py +++ b/selfdrive/controls/lib/driver_monitor.py @@ -20,9 +20,9 @@ _PITCH_WEIGHT = 1.35 # 1.5 # pitch matters a lot more _METRIC_THRESHOLD = 0.4 _METRIC_THRESHOLD_SLACK = 0.55 _METRIC_THRESHOLD_STRICT = 0.4 -_PITCH_POS_ALLOWANCE = 0.04 # 0.08 # rad, to not be too sensitive on positive pitch -_PITCH_NATURAL_OFFSET = 0.12 # 0.1 # people don't seem to look straight when they drive relaxed, rather a bit up -_YAW_NATURAL_OFFSET = 0.08 # people don't seem to look straight when they drive relaxed, rather a bit to the right (center of car) +_PITCH_POS_ALLOWANCE = 0.12 # rad, to not be too sensitive on positive pitch +_PITCH_NATURAL_OFFSET = 0.02 # people don't seem to look straight when they drive relaxed, rather a bit up +_YAW_NATURAL_OFFSET = 0.08 # people don't seem to look straight when they drive relaxed, rather a bit to the right (center of car) _DISTRACTED_FILTER_TS = 0.25 # 0.6Hz @@ -138,13 +138,13 @@ class DriverStatus(): if not self.pose_calibrated: pitch_error = pose.pitch - _PITCH_NATURAL_OFFSET yaw_error = pose.yaw - _YAW_NATURAL_OFFSET - # add positive pitch allowance - if pitch_error > 0.: - pitch_error = max(pitch_error - _PITCH_POS_ALLOWANCE, 0.) else: pitch_error = pose.pitch - self.pose.pitch_offseter.filtered_stat.mean() yaw_error = pose.yaw - self.pose.yaw_offseter.filtered_stat.mean() + # positive pitch allowance + if pitch_error > 0.: + pitch_error = max(pitch_error - _PITCH_POS_ALLOWANCE, 0.) pitch_error *= _PITCH_WEIGHT pose_metric = np.sqrt(yaw_error**2 + pitch_error**2) diff --git a/selfdrive/controls/lib/pathplanner.py b/selfdrive/controls/lib/pathplanner.py index 87e3c520fc..8a6e5286f3 100644 --- a/selfdrive/controls/lib/pathplanner.py +++ b/selfdrive/controls/lib/pathplanner.py @@ -14,6 +14,9 @@ LaneChangeDirection = log.PathPlan.LaneChangeDirection LOG_MPC = os.environ.get('LOG_MPC', False) +LANE_CHANGE_SPEED_MIN = 45 * CV.MPH_TO_MS +LANE_CHANGE_TIME_MAX = 10. + DESIRES = { LaneChangeDirection.none: { LaneChangeState.off: log.PathPlan.Desire.none, @@ -88,8 +91,9 @@ class PathPlanner(): # Lane change logic lane_change_direction = LaneChangeDirection.none one_blinker = sm['carState'].leftBlinker != sm['carState'].rightBlinker + below_lane_change_speed = v_ego < LANE_CHANGE_SPEED_MIN - if not active or self.lane_change_timer > 10.0: + if not active or self.lane_change_timer > LANE_CHANGE_TIME_MAX: self.lane_change_state = LaneChangeState.off else: if sm['carState'].leftBlinker: @@ -97,23 +101,23 @@ class PathPlanner(): elif sm['carState'].rightBlinker: lane_change_direction = LaneChangeDirection.right - if lane_change_direction == LaneChangeDirection.left: - torque_applied = sm['carState'].steeringTorque > 0 and sm['carState'].steeringPressed - else: - torque_applied = sm['carState'].steeringTorque < 0 and sm['carState'].steeringPressed + torque_applied = sm['carState'].steeringPressed and \ + ((sm['carState'].steeringTorque > 0 and lane_change_direction == LaneChangeDirection.left) or \ + (sm['carState'].steeringTorque < 0 and lane_change_direction == LaneChangeDirection.right)) lane_change_prob = self.LP.l_lane_change_prob + self.LP.r_lane_change_prob # State transitions # off - if False: # self.lane_change_state == LaneChangeState.off and one_blinker and not self.prev_one_blinker: + if self.lane_change_state == LaneChangeState.off and one_blinker and not self.prev_one_blinker and not below_lane_change_speed: self.lane_change_state = LaneChangeState.preLaneChange # pre - elif self.lane_change_state == LaneChangeState.preLaneChange and not one_blinker: - self.lane_change_state = LaneChangeState.off - elif self.lane_change_state == LaneChangeState.preLaneChange and torque_applied: - self.lane_change_state = LaneChangeState.laneChangeStarting + elif self.lane_change_state == LaneChangeState.preLaneChange: + if not one_blinker or below_lane_change_speed: + self.lane_change_state = LaneChangeState.off + elif torque_applied: + self.lane_change_state = LaneChangeState.laneChangeStarting # starting elif self.lane_change_state == LaneChangeState.laneChangeStarting and lane_change_prob > 0.5: @@ -121,11 +125,10 @@ class PathPlanner(): # finishing elif self.lane_change_state == LaneChangeState.laneChangeFinishing and lane_change_prob < 0.2: - self.lane_change_state = LaneChangeState.preLaneChange - - # Don't allow starting lane change below 45 mph - if (v_ego < 45 * CV.MPH_TO_MS) and (self.lane_change_state == LaneChangeState.preLaneChange): - self.lane_change_state = LaneChangeState.off + if one_blinker: + self.lane_change_state = LaneChangeState.preLaneChange + else: + self.lane_change_state = LaneChangeState.off if self.lane_change_state in [LaneChangeState.off, LaneChangeState.preLaneChange]: self.lane_change_timer = 0.0 diff --git a/selfdrive/controls/lib/planner.py b/selfdrive/controls/lib/planner.py index 6646e13454..1d6140a816 100755 --- a/selfdrive/controls/lib/planner.py +++ b/selfdrive/controls/lib/planner.py @@ -27,7 +27,8 @@ _A_CRUISE_MIN_BP = [ 0., 5., 10., 20., 40.] # need fast accel at very low speed for stop and go # make sure these accelerations are smaller than mpc limits -_A_CRUISE_MAX_V = [1.6, 1.6, 0.65, .4] +_A_CRUISE_MAX_V = [1.2, 1.2, 0.65, .4] +_A_CRUISE_MAX_V_FOLLOWING = [1.6, 1.6, 0.65, .4] _A_CRUISE_MAX_BP = [0., 6.4, 22.5, 40.] # Lookup table for turns @@ -38,9 +39,13 @@ _A_TOTAL_MAX_BP = [20., 40.] SPEED_PERCENTILE_IDX = 7 -def calc_cruise_accel_limits(v_ego): +def calc_cruise_accel_limits(v_ego, following): a_cruise_min = interp(v_ego, _A_CRUISE_MIN_BP, _A_CRUISE_MIN_V) - a_cruise_max = interp(v_ego, _A_CRUISE_MAX_BP, _A_CRUISE_MAX_V) + + if following: + a_cruise_max = interp(v_ego, _A_CRUISE_MAX_BP, _A_CRUISE_MAX_V_FOLLOWING) + else: + a_cruise_max = interp(v_ego, _A_CRUISE_MAX_BP, _A_CRUISE_MAX_V) return np.vstack([a_cruise_min, a_cruise_max]) @@ -80,6 +85,7 @@ class Planner(): self.path_x = np.arange(192) self.params = Params() + self.first_loop = True def choose_solution(self, v_cruise_setpoint, enabled): if enabled: @@ -122,6 +128,7 @@ class Planner(): lead_2 = sm['radarState'].leadTwo enabled = (long_control_state == LongCtrlState.pid) or (long_control_state == LongCtrlState.stopping) + following = lead_1.status and lead_1.dRel < 45.0 and lead_1.vLeadK > v_ego and lead_1.aLeadK > 0.0 if len(sm['model'].path.poly): path = list(sm['model'].path.poly) @@ -142,8 +149,8 @@ class Planner(): model_speed = MAX_SPEED # Calculate speed for normal cruise control - if enabled: - accel_limits = [float(x) for x in calc_cruise_accel_limits(v_ego)] + if enabled and not self.first_loop: + accel_limits = [float(x) for x in calc_cruise_accel_limits(v_ego, following)] jerk_limits = [min(-0.1, accel_limits[0]), max(0.1, accel_limits[1])] # TODO: make a separate lookup for jerk tuning accel_limits_turns = limit_accel_in_turns(v_ego, sm['carState'].steeringAngle, accel_limits, self.CP) @@ -242,3 +249,5 @@ class Planner(): v_acc_sol = self.v_acc_start + CP.radarTimeStep * (a_acc_sol + self.a_acc_start) / 2.0 self.v_acc_start = v_acc_sol self.a_acc_start = a_acc_sol + + self.first_loop = False diff --git a/selfdrive/controls/tests/test_following_distance.py b/selfdrive/controls/tests/test_following_distance.py index cc70bb4d38..63545e6ee4 100644 --- a/selfdrive/controls/tests/test_following_distance.py +++ b/selfdrive/controls/tests/test_following_distance.py @@ -38,7 +38,7 @@ def run_following_distance_simulation(v_lead, t_end=200.0): first = True while t < t_end: # Run cruise control - accel_limits = [float(x) for x in calc_cruise_accel_limits(v_ego)] + accel_limits = [float(x) for x in calc_cruise_accel_limits(v_ego, False)] jerk_limits = [min(-0.1, accel_limits[0]), max(0.1, accel_limits[1])] v_cruise, a_cruise = speed_smoother(v_ego, a_ego, v_cruise_setpoint, accel_limits[1], accel_limits[0], diff --git a/selfdrive/locationd/calibrationd.py b/selfdrive/locationd/calibrationd.py index 3811d24f8c..cd92a5f630 100755 --- a/selfdrive/locationd/calibrationd.py +++ b/selfdrive/locationd/calibrationd.py @@ -10,19 +10,23 @@ from selfdrive.swaglog import cloudlog from common.params import Params, put_nonblocking from common.transformations.model import model_height from common.transformations.camera import view_frame_from_device_frame, get_view_frame_from_road_frame, \ - eon_intrinsics, get_calib_from_vp, H, W + get_calib_from_vp, H, W, FOCAL MPH_TO_MS = 0.44704 MIN_SPEED_FILTER = 15 * MPH_TO_MS +MAX_SPEED_STD = 1.5 MAX_YAW_RATE_FILTER = np.radians(2) # per second -INPUTS_NEEDED = 300 # allow to update VP every so many frames -INPUTS_WANTED = 600 # We want a little bit more than we need for stability -WRITE_CYCLES = 400 # write every 400 cycles + +# This is all 20Hz, blocks needed for efficiency +BLOCK_SIZE = 100 +INPUTS_NEEDED = 5 # allow to update VP every so many frames +INPUTS_WANTED = 20 # We want a little bit more than we need for stability +WRITE_CYCLES = 10 # write every 1000 cycles VP_INIT = np.array([W/2., H/2.]) # These validity corners were chosen by looking at 1000 # and taking most extreme cases with some margin. -VP_VALIDITY_CORNERS = np.array([[W//2 - 150, 280], [W//2 + 150, 540]]) +VP_VALIDITY_CORNERS = np.array([[W//2 - 120, 300], [W//2 + 120, 520]]) DEBUG = os.getenv("DEBUG") is not None @@ -31,13 +35,29 @@ def is_calibration_valid(vp): vp[1] > VP_VALIDITY_CORNERS[0,1] and vp[1] < VP_VALIDITY_CORNERS[1,1] +def sanity_clip(vp): + if np.isnan(vp).any(): + vp = VP_INIT + return [np.clip(vp[0], VP_VALIDITY_CORNERS[0,0] - 20, VP_VALIDITY_CORNERS[1,0] + 20), + np.clip(vp[1], VP_VALIDITY_CORNERS[0,1] - 20, VP_VALIDITY_CORNERS[1,1] + 20)] + + +def intrinsics_from_vp(vp): + return np.array([ + [FOCAL, 0., vp[0]], + [ 0., FOCAL, vp[1]], + [ 0., 0., 1.]]) + + class Calibrator(): def __init__(self, param_put=False): self.param_put = param_put self.vp = copy.copy(VP_INIT) - self.vps = [] + self.vps = np.zeros((INPUTS_WANTED, 2)) + self.idx = 0 + self.block_idx = 0 + self.valid_blocks = 0 self.cal_status = Calibration.UNCALIBRATED - self.write_counter = 0 self.just_calibrated = False # Read calibration @@ -46,14 +66,19 @@ class Calibrator(): try: calibration_params = json.loads(calibration_params) self.vp = np.array(calibration_params["vanishing_point"]) - self.vps = np.tile(self.vp, (calibration_params['valid_points'], 1)).tolist() + if not np.isfinite(self.vp).all(): + self.vp = copy.copy(VP_INIT) + self.vps = np.tile(self.vp, (INPUTS_WANTED, 1)) + self.valid_blocks = calibration_params['valid_blocks'] + if not np.isfinite(self.valid_blocks) or self.valid_blocks < 0: + self.valid_blocks = 0 self.update_status() except Exception: cloudlog.exception("CalibrationParams file found but error encountered") def update_status(self): start_status = self.cal_status - if len(self.vps) < INPUTS_NEEDED: + if self.valid_blocks < INPUTS_NEEDED: self.cal_status = Calibration.UNCALIBRATED else: self.cal_status = Calibration.CALIBRATED if is_calibration_valid(self.vp) else Calibration.INVALID @@ -63,19 +88,28 @@ class Calibrator(): if start_status == Calibration.UNCALIBRATED and end_status == Calibration.CALIBRATED: self.just_calibrated = True - def handle_cam_odom(self, log): - trans, rot = log.trans, log.rot - if np.linalg.norm(trans) > MIN_SPEED_FILTER and abs(rot[2]) < MAX_YAW_RATE_FILTER: - new_vp = eon_intrinsics.dot(view_frame_from_device_frame.dot(trans)) + def handle_cam_odom(self, trans, rot, trans_std, rot_std): + if ((trans[0] > MIN_SPEED_FILTER) and + (trans_std[0] < MAX_SPEED_STD) and + (abs(rot[2]) < MAX_YAW_RATE_FILTER)): + # intrinsics are not eon intrinsics, since this is calibrated frame + intrinsics = intrinsics_from_vp(self.vp) + new_vp = intrinsics.dot(view_frame_from_device_frame.dot(trans)) new_vp = new_vp[:2]/new_vp[2] - self.vps.append(new_vp) - self.vps = self.vps[-INPUTS_WANTED:] - self.vp = np.mean(self.vps, axis=0) + + self.vps[self.block_idx] = (self.idx*self.vps[self.block_idx] + (BLOCK_SIZE - self.idx) * new_vp) / float(BLOCK_SIZE) + self.idx = (self.idx + 1) % BLOCK_SIZE + if self.idx == 0: + self.block_idx += 1 + self.valid_blocks = max(self.block_idx, self.valid_blocks) + self.block_idx = self.block_idx % INPUTS_WANTED + raw_vp = np.mean(self.vps[:max(1, self.valid_blocks)], axis=0) + self.vp = sanity_clip(raw_vp) self.update_status() - self.write_counter += 1 - if self.param_put and (self.write_counter % WRITE_CYCLES == 0 or self.just_calibrated): + + if self.param_put and ((self.idx == 0 and self.block_idx == 0) or self.just_calibrated): cal_params = {"vanishing_point": list(self.vp), - "valid_points": len(self.vps)} + "valid_blocks": self.valid_blocks} put_nonblocking("CalibrationParams", json.dumps(cal_params).encode('utf8')) return new_vp else: @@ -88,7 +122,7 @@ class Calibrator(): cal_send = messaging.new_message() cal_send.init('liveCalibration') cal_send.liveCalibration.calStatus = self.cal_status - cal_send.liveCalibration.calPerc = min(len(self.vps) * 100 // INPUTS_NEEDED, 100) + cal_send.liveCalibration.calPerc = min(100 * (self.valid_blocks * BLOCK_SIZE + self.idx) // (INPUTS_NEEDED * BLOCK_SIZE), 100) cal_send.liveCalibration.extrinsicMatrix = [float(x) for x in extrinsic_matrix.flatten()] cal_send.liveCalibration.rpyCalib = [float(x) for x in calib] @@ -104,15 +138,22 @@ def calibrationd_thread(sm=None, pm=None): calibrator = Calibrator(param_put=True) - # buffer with all the messages that still need to be input into the kalman + send_counter = 0 while 1: sm.update() - new_vp = calibrator.handle_cam_odom(sm['cameraOdometry']) + if sm.updated['cameraOdometry']: + new_vp = calibrator.handle_cam_odom(sm['cameraOdometry'].trans, + sm['cameraOdometry'].rot, + sm['cameraOdometry'].transStd, + sm['cameraOdometry'].rotStd) if DEBUG and new_vp is not None: print('got new vp', new_vp) - calibrator.send_data(pm) + # decimate outputs for efficiency + if (send_counter % 5) == 0: + calibrator.send_data(pm) + send_counter += 1 def main(sm=None, pm=None): diff --git a/selfdrive/locationd/locationd_yawrate.cc b/selfdrive/locationd/locationd_yawrate.cc index 83c837d7fb..b2b87557ce 100644 --- a/selfdrive/locationd/locationd_yawrate.cc +++ b/selfdrive/locationd/locationd_yawrate.cc @@ -40,7 +40,7 @@ void Localizer::handle_sensor_events(capnp::List::Reade } void Localizer::handle_camera_odometry(cereal::CameraOdometry::Reader camera_odometry, double current_time) { - double R = 100.0 * pow(camera_odometry.getRotStd()[2], 2); + double R = pow(30.0 *camera_odometry.getRotStd()[2], 2); double meas = camera_odometry.getRot()[2]; update_state(C_posenet, R, current_time, meas); @@ -73,7 +73,7 @@ Localizer::Localizer() { 0, 0, 0, 0, 0, pow(0.1, 2.0), 0, 0, 0, 0, 0, 0, - 0, 0, pow(0.0005 / 100.0, 2.0), 0; + 0, 0, pow(0.005 / 100.0, 2.0), 0; P << pow(100.0, 2.0), 0, 0, 0, 0, pow(100.0, 2.0), 0, 0, diff --git a/selfdrive/loggerd/SConscript b/selfdrive/loggerd/SConscript index 6a392d15d6..b319c773c2 100644 --- a/selfdrive/loggerd/SConscript +++ b/selfdrive/loggerd/SConscript @@ -1,6 +1,12 @@ -Import('env', 'messaging', 'common', 'visionipc') -env.Program(['loggerd.cc', 'logger.c', 'raw_logger.cc', 'encoder.c'], LIBS=[ - 'zmq', 'czmq', 'capnp', 'kj', 'yaml-cpp', 'z', +Import('env', 'arch', 'messaging', 'common', 'visionipc') + +src = ['loggerd.cc', 'logger.c'] +libs = ['zmq', 'czmq', 'capnp', 'kj', 'yaml-cpp', 'z', 'avformat', 'avcodec', 'swscale', 'avutil', - 'OmxVenc', 'OmxCore', 'yuv', - 'bz2', 'cutils', common, 'json', messaging, visionipc]) + 'yuv', 'bz2', common, 'json', messaging, visionipc] + +if arch == "aarch64": + src += ['encoder.c', 'raw_logger.cc'] + libs += ['OmxVenc', 'OmxCore', 'cutils'] + +env.Program(src, LIBS=libs) diff --git a/selfdrive/loggerd/config.py b/selfdrive/loggerd/config.py index 14e1e67a9e..0ee6fa671d 100644 --- a/selfdrive/loggerd/config.py +++ b/selfdrive/loggerd/config.py @@ -9,11 +9,21 @@ else: SEGMENT_LENGTH = 60 -def get_available_percent(): +def get_available_percent(default=None): try: statvfs = os.statvfs(ROOT) available_percent = 100.0 * statvfs.f_bavail / statvfs.f_blocks except OSError: - available_percent = 100.0 + available_percent = default return available_percent + + +def get_available_bytes(default=None): + try: + statvfs = os.statvfs(ROOT) + available_bytes = statvfs.f_bavail * statvfs.f_frsize + except OSError: + available_bytes = default + + return available_bytes diff --git a/selfdrive/loggerd/deleter.py b/selfdrive/loggerd/deleter.py index 5669e2342d..1c687ff4b0 100644 --- a/selfdrive/loggerd/deleter.py +++ b/selfdrive/loggerd/deleter.py @@ -3,15 +3,15 @@ import os import shutil import threading from selfdrive.swaglog import cloudlog -from selfdrive.loggerd.config import ROOT, get_available_percent +from selfdrive.loggerd.config import ROOT, get_available_bytes from selfdrive.loggerd.uploader import listdir_by_creation def deleter_thread(exit_event): while not exit_event.is_set(): - available_percent = get_available_percent() + available_bytes = get_available_bytes() - if available_percent < 10.0: + if available_bytes is not None and available_bytes < (5 * 1024 * 1024 * 1024): # remove the earliest directory we can dirs = listdir_by_creation(ROOT) for delete_dir in dirs: diff --git a/selfdrive/loggerd/loggerd.cc b/selfdrive/loggerd/loggerd.cc index 4334af0f3a..1b3a81d7a4 100644 --- a/selfdrive/loggerd/loggerd.cc +++ b/selfdrive/loggerd/loggerd.cc @@ -25,7 +25,10 @@ #include #include #include + +#ifdef QCOM #include +#endif #include "common/version.h" #include "common/timing.h" @@ -38,6 +41,11 @@ #include "logger.h" #include "messaging.hpp" +#ifndef QCOM +// no encoder on PC +#define DISABLE_ENCODER +#endif + #ifndef DISABLE_ENCODER #include "encoder.h" @@ -420,6 +428,7 @@ kj::Array gen_init_data() { init.setKernelVersion(util::read_file("/proc/version")); +#ifdef QCOM { std::vector > properties; property_list(append_property, (void*)&properties); @@ -431,6 +440,7 @@ kj::Array gen_init_data() { lentry.setValue(properties[i].second); } } +#endif const char* dongle_id = getenv("DONGLE_ID"); if (dongle_id) { diff --git a/selfdrive/loggerd/tests/test_deleter.py b/selfdrive/loggerd/tests/test_deleter.py index adbb0f0316..f06946b2fe 100644 --- a/selfdrive/loggerd/tests/test_deleter.py +++ b/selfdrive/loggerd/tests/test_deleter.py @@ -1,6 +1,7 @@ import os import time import threading +import unittest from collections import namedtuple import selfdrive.loggerd.deleter as deleter @@ -8,7 +9,8 @@ from common.timeout import Timeout, TimeoutException from selfdrive.loggerd.tests.loggerd_tests_common import UploaderTestCase -Stats = namedtuple("Stats", ['f_bavail', 'f_blocks']) +Stats = namedtuple("Stats", ['f_bavail', 'f_blocks', 'f_frsize']) + class TestDeleter(UploaderTestCase): def fake_statvfs(self, d): @@ -17,7 +19,7 @@ class TestDeleter(UploaderTestCase): def setUp(self): self.f_type = "fcamera.hevc" super(TestDeleter, self).setUp() - self.fake_stats = Stats(f_bavail=0, f_blocks=10) + self.fake_stats = Stats(f_bavail=0, f_blocks=10, f_frsize=4096) deleter.os.statvfs = self.fake_statvfs deleter.ROOT = self.root @@ -68,7 +70,9 @@ class TestDeleter(UploaderTestCase): def test_no_delete_when_available_space(self): f_path = self.make_file_with_data(self.seg_dir, self.f_type) - self.fake_stats = Stats(f_bavail=10, f_blocks=10) + block_size = 4096 + available = (10 * 1024 * 1024 * 1024) / block_size # 10GB free + self.fake_stats = Stats(f_bavail=available, f_blocks=10, f_frsize=block_size) self.start_thread() @@ -98,3 +102,7 @@ class TestDeleter(UploaderTestCase): self.join_thread() self.assertTrue(os.path.exists(f_path), "File deleted when locked") + + +if __name__ == "__main__": + unittest.main() diff --git a/selfdrive/loggerd/uploader.py b/selfdrive/loggerd/uploader.py index bea384b543..8f7e0a67a4 100644 --- a/selfdrive/loggerd/uploader.py +++ b/selfdrive/loggerd/uploader.py @@ -68,13 +68,15 @@ def is_on_wifi(): # ConnectivityManager.getActiveNetworkInfo() try: result = android.parse_service_call_string(["connectivity", "2"]) + if result is None: + return True return 'WIFI' in result except AttributeError: return False def is_on_hotspot(): try: - result = subprocess.check_output(["ifconfig", "wlan0"], encoding='utf8') + result = subprocess.check_output(["ifconfig", "wlan0"], stderr=subprocess.STDOUT, encoding='utf8') result = re.findall(r"inet addr:((\d+\.){3}\d+)", result)[0][0] is_android = result.startswith('192.168.43.') diff --git a/selfdrive/manager.py b/selfdrive/manager.py index b603bf3d41..358eb38937 100755 --- a/selfdrive/manager.py +++ b/selfdrive/manager.py @@ -5,10 +5,12 @@ import sys import fcntl import errno import signal +import shutil import subprocess import datetime from common.basedir import BASEDIR +from common.android import ANDROID sys.path.append(os.path.join(BASEDIR, "pyextra")) os.environ['BASEDIR'] = BASEDIR @@ -21,7 +23,7 @@ try: except FileExistsError: pass -if os.path.isfile('/EON'): +if ANDROID: os.chmod("/dev/shm", 0o777) def unblock_stdout(): @@ -74,7 +76,11 @@ if not prebuilt: # run scons env = os.environ.copy() env['SCONS_PROGRESS'] = "1" - scons = subprocess.Popen(["scons", "-j4"], cwd=BASEDIR, env=env, stderr=subprocess.PIPE) + env['SCONS_CACHE'] = "1" + + nproc = os.cpu_count() + j_flag = "" if nproc is None else "-j%d" % (nproc - 1) + scons = subprocess.Popen(["scons", j_flag], cwd=BASEDIR, env=env, stderr=subprocess.PIPE) # Read progress from stderr and update spinner while scons.poll() is None: @@ -96,8 +102,12 @@ if not prebuilt: if scons.returncode != 0: if retry: - print("scons build failed, make clean") + print("scons build failed, cleaning in") + for i in range(3,-1,-1): + print("....%d" % i) + time.sleep(1) subprocess.check_call(["scons", "-c"], cwd=BASEDIR, env=env) + shutil.rmtree("/tmp/scons_cache") else: raise RuntimeError("scons build failed") else: @@ -139,11 +149,13 @@ managed_processes = { "paramsd": ("selfdrive/locationd", ["./paramsd"]), "camerad": ("selfdrive/camerad", ["./camerad"]), "sensord": ("selfdrive/sensord", ["./sensord"]), + "clocksd": ("selfdrive/clocksd", ["./clocksd"]), "gpsd": ("selfdrive/sensord", ["./gpsd"]), "updated": "selfdrive.updated", "monitoringd": ("selfdrive/modeld", ["./monitoringd"]), "modeld": ("selfdrive/modeld", ["./modeld"]), } + daemon_processes = { "manage_athenad": ("selfdrive.athena.manage_athenad", "AthenadPid"), } @@ -161,32 +173,42 @@ interrupt_processes = [] # processes to end with SIGKILL instead of SIGTERM kill_processes = ['sensord', 'paramsd'] +# processes to end if thermal conditions exceed Green parameters +green_temp_processes = ['uploader'] + persistent_processes = [ 'thermald', 'logmessaged', - 'logcatd', - 'tombstoned', - 'uploader', 'ui', - 'updated', + 'uploader', ] +if ANDROID: + persistent_processes += [ + 'logcatd', + 'tombstoned', + 'updated', + ] car_started_processes = [ 'controlsd', 'plannerd', 'loggerd', - 'sensord', 'radard', 'calibrationd', 'paramsd', 'camerad', 'modeld', - 'monitoringd', 'proclogd', 'ubloxd', - 'gpsd', - 'deleter', ] +if ANDROID: + car_started_processes += [ + 'sensord', + 'clocksd', + 'gpsd', + 'monitoringd', + 'deleter', + ] def register_managed_process(name, desc, car_started=False): global managed_processes, car_started_processes, persistent_processes @@ -303,7 +325,8 @@ def kill_managed_process(name): def cleanup_all_processes(signal, frame): cloudlog.info("caught ctrl-c %s %s" % (signal, frame)) - pm_apply_packages('disable') + if ANDROID: + pm_apply_packages('disable') for name in list(running.keys()): kill_managed_process(name) @@ -365,8 +388,9 @@ def manager_thread(): start_managed_process(p) # start frame - pm_apply_packages('enable') - start_frame() + if ANDROID: + pm_apply_packages('enable') + start_frame() if os.getenv("NOBOARD") is None: start_managed_process("pandad") @@ -376,11 +400,15 @@ def manager_thread(): while 1: msg = messaging.recv_sock(thermal_sock, wait=True) - # uploader is gated based on the phone temperature + # heavyweight batch processes are gated on favorable thermal conditions if msg.thermal.thermalStatus >= ThermalStatus.yellow: - kill_managed_process("uploader") + for p in green_temp_processes: + if p in persistent_processes: + kill_managed_process(p) else: - start_managed_process("uploader") + for p in green_temp_processes: + if p in persistent_processes: + start_managed_process(p) if msg.thermal.freeSpace < 0.05: logger_dead = True @@ -430,13 +458,6 @@ def main(): # disable bluetooth os.system('service call bluetooth_manager 8') - # support additional internal only extensions - try: - import selfdrive.manager_extensions - selfdrive.manager_extensions.register(register_managed_process) # pylint: disable=no-member - except ImportError: - pass - params = Params() params.manager_start() @@ -480,7 +501,8 @@ def main(): if params.get("Passive") is None: raise Exception("Passive must be set to continue") - update_apks() + if ANDROID: + update_apks() manager_init() manager_prepare(spinner) spinner.close() diff --git a/selfdrive/modeld/SConscript b/selfdrive/modeld/SConscript index b752bb3ade..aa995fb3f4 100644 --- a/selfdrive/modeld/SConscript +++ b/selfdrive/modeld/SConscript @@ -1,25 +1,36 @@ Import('env', 'arch', 'messaging', 'common', 'gpucommon', 'visionipc') +lenv = env.Clone() libs = [messaging, common, 'OpenCL', 'SNPE', 'capnp', 'zmq', 'kj', 'yuv', gpucommon, visionipc] +common_src = [ + "models/commonmodel.c", + "runners/snpemodel.cc", + "transforms/loadyuv.c", + "transforms/transform.c"] + if arch == "aarch64": libs += ['gsl', 'CB', 'gnustl_shared'] else: libs += ['symphony-cpu', 'pthread'] -common = env.Object([ - "models/commonmodel.c", - "runners/snpemodel.cc", - "transforms/loadyuv.c", - "transforms/transform.c"]) + if FindFile('libtensorflow.so', env['LIBPATH']): + # for tensorflow support + common_src += ['runners/tfmodel.cc'] + libs += ['tensorflow'] + # tell runners to use it + lenv['CFLAGS'].append("-DUSE_TF_MODEL") + lenv['CXXFLAGS'].append("-DUSE_TF_MODEL") + +common = lenv.Object(common_src) -env.Program('_monitoringd', [ +lenv.Program('_monitoringd', [ "monitoringd.cc", "models/monitoring.cc", ]+common, LIBS=libs) -env.Program('_modeld', [ +lenv.Program('_modeld', [ "modeld.cc", "models/driving.cc", - "models/posenet.cc", ]+common, LIBS=libs) + diff --git a/selfdrive/modeld/modeld b/selfdrive/modeld/modeld index cb7dc65e7b..3629f7a71a 100755 --- a/selfdrive/modeld/modeld +++ b/selfdrive/modeld/modeld @@ -1,4 +1,4 @@ #!/bin/sh -export LD_LIBRARY_PATH="/data/pythonpath/phonelibs/snpe/aarch64-android-clang3.8/:$LD_LIBRARY_PATH" +export LD_LIBRARY_PATH="/data/pythonpath/phonelibs/snpe/aarch64-android-clang3.8/:/home/batman/one/phonelibs/snpe/x86_64-linux-clang:$LD_LIBRARY_PATH" exec ./_modeld diff --git a/selfdrive/modeld/modeld.cc b/selfdrive/modeld/modeld.cc index 276a347925..fa49d1b5df 100644 --- a/selfdrive/modeld/modeld.cc +++ b/selfdrive/modeld/modeld.cc @@ -1,18 +1,11 @@ #include #include -#ifdef QCOM -#include -#else -#include -#endif - #include "common/visionbuf.h" #include "common/visionipc.h" #include "common/swaglog.h" #include "models/driving.h" -#include "models/posenet.h" volatile sig_atomic_t do_exit = 0; @@ -122,13 +115,26 @@ int main(int argc, char **argv) { cl_command_queue q; { // TODO: refactor this - cl_platform_id platform_id = NULL; + cl_platform_id platform_id[2]; cl_uint num_devices; cl_uint num_platforms; - err = clGetPlatformIDs(1, &platform_id, &num_platforms); + err = clGetPlatformIDs(sizeof(platform_id)/sizeof(cl_platform_id), platform_id, &num_platforms); assert(err == 0); - err = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_DEFAULT, 1, + + #ifdef QCOM + int clPlatform = 0; + #else + // don't use nvidia on pc, it's broken + // TODO: write this nicely + int clPlatform = num_platforms-1; + #endif + + char cBuffer[1024]; + clGetPlatformInfo(platform_id[clPlatform], CL_PLATFORM_NAME, sizeof(cBuffer), &cBuffer, NULL); + LOGD("got %d opencl platform(s), using %s", num_platforms, cBuffer); + + err = clGetDeviceIDs(platform_id[clPlatform], CL_DEVICE_TYPE_DEFAULT, 1, &device_id, &num_devices); assert(err == 0); @@ -141,9 +147,7 @@ int main(int argc, char **argv) { // init the models ModelState model; - PosenetState posenet; model_init(&model, device_id, context, true); - posenet_init(&posenet); LOGW("models loaded, modeld starting"); // debayering does a 2x downscale @@ -213,54 +217,18 @@ int main(int argc, char **argv) { // TODO: don't make copies! memcpy(yuv_ion.addr, buf->addr, buf_info.buf_len); - ModelData model_buf = + ModelDataRaw model_buf = model_eval_frame(&model, q, yuv_cl, buf_info.width, buf_info.height, model_transform, NULL, vec_desire); mt2 = millis_since_boot(); model_publish(model_sock, extra.frame_id, model_buf, extra.timestamp_eof); + posenet_publish(posenet_sock, extra.frame_id, model_buf, extra.timestamp_eof); LOGD("model process: %.2fms, from last %.2fms", mt2-mt1, mt1-last); last = mt1; } - // push the frame to the posenet - // TODO: This doesn't always have to run - double pt1 = 0, pt2 = 0, pt3 = 0; - pt1 = millis_since_boot(); - posenet_push(&posenet, (uint8_t*)buf->addr, buf_info.width); - pt2 = millis_since_boot(); - - // posenet runs every 5 - if (extra.frame_id % 5 == 0) { - posenet_eval(&posenet); - - // send posenet event - { - capnp::MallocMessageBuilder msg; - cereal::Event::Builder event = msg.initRoot(); - event.setLogMonoTime(nanos_since_boot()); - - auto posenetd = event.initCameraOdometry(); - kj::ArrayPtr trans_vs(&posenet.output[0], 3); - posenetd.setTrans(trans_vs); - kj::ArrayPtr rot_vs(&posenet.output[3], 3); - posenetd.setRot(rot_vs); - kj::ArrayPtr trans_std_vs(&posenet.output[6], 3); - posenetd.setTransStd(trans_std_vs); - kj::ArrayPtr rot_std_vs(&posenet.output[9], 3); - posenetd.setRotStd(rot_std_vs); - posenetd.setTimestampEof(extra.timestamp_eof); - posenetd.setFrameId(extra.frame_id); - - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - posenet_sock->send((char*)bytes.begin(), bytes.size()); - } - pt3 = millis_since_boot(); - LOGD("pre: %.2fms | posenet: %.2fms", (pt2-pt1), (pt3-pt1)); - } - } visionbuf_free(&yuv_ion); } @@ -268,9 +236,7 @@ int main(int argc, char **argv) { visionstream_destroy(&stream); delete model_sock; - delete posenet_sock; - - posenet_free(&posenet); + model_free(&model); LOG("joining live_thread"); diff --git a/selfdrive/modeld/models/commonmodel.c b/selfdrive/modeld/models/commonmodel.c index 0369d16d5d..143480fb0b 100644 --- a/selfdrive/modeld/models/commonmodel.c +++ b/selfdrive/modeld/models/commonmodel.c @@ -5,57 +5,57 @@ #include "common/mat.h" #include "common/timing.h" -void model_input_init(ModelInput* s, int width, int height, +void frame_init(ModelFrame* frame, int width, int height, cl_device_id device_id, cl_context context) { int err; - s->device_id = device_id; - s->context = context; + frame->device_id = device_id; + frame->context = context; - transform_init(&s->transform, context, device_id); - s->transformed_width = width; - s->transformed_height = height; + transform_init(&frame->transform, context, device_id); + frame->transformed_width = width; + frame->transformed_height = height; - s->transformed_y_cl = clCreateBuffer(s->context, CL_MEM_READ_WRITE, - s->transformed_width*s->transformed_height, NULL, &err); + frame->transformed_y_cl = clCreateBuffer(frame->context, CL_MEM_READ_WRITE, + frame->transformed_width*frame->transformed_height, NULL, &err); assert(err == 0); - s->transformed_u_cl = clCreateBuffer(s->context, CL_MEM_READ_WRITE, - (s->transformed_width/2)*(s->transformed_height/2), NULL, &err); + frame->transformed_u_cl = clCreateBuffer(frame->context, CL_MEM_READ_WRITE, + (frame->transformed_width/2)*(frame->transformed_height/2), NULL, &err); assert(err == 0); - s->transformed_v_cl = clCreateBuffer(s->context, CL_MEM_READ_WRITE, - (s->transformed_width/2)*(s->transformed_height/2), NULL, &err); + frame->transformed_v_cl = clCreateBuffer(frame->context, CL_MEM_READ_WRITE, + (frame->transformed_width/2)*(frame->transformed_height/2), NULL, &err); assert(err == 0); - s->net_input_size = ((width*height*3)/2)*sizeof(float); - s->net_input = clCreateBuffer(s->context, CL_MEM_READ_WRITE, - s->net_input_size, (void*)NULL, &err); + frame->net_input_size = ((width*height*3)/2)*sizeof(float); + frame->net_input = clCreateBuffer(frame->context, CL_MEM_READ_WRITE, + frame->net_input_size, (void*)NULL, &err); assert(err == 0); - loadyuv_init(&s->loadyuv, context, device_id, s->transformed_width, s->transformed_height); + loadyuv_init(&frame->loadyuv, context, device_id, frame->transformed_width, frame->transformed_height); } -float *model_input_prepare(ModelInput* s, cl_command_queue q, +float *frame_prepare(ModelFrame* frame, cl_command_queue q, cl_mem yuv_cl, int width, int height, mat3 transform) { int err; int i = 0; - transform_queue(&s->transform, q, + transform_queue(&frame->transform, q, yuv_cl, width, height, - s->transformed_y_cl, s->transformed_u_cl, s->transformed_v_cl, - s->transformed_width, s->transformed_height, + frame->transformed_y_cl, frame->transformed_u_cl, frame->transformed_v_cl, + frame->transformed_width, frame->transformed_height, transform); - loadyuv_queue(&s->loadyuv, q, - s->transformed_y_cl, s->transformed_u_cl, s->transformed_v_cl, - s->net_input); - float *net_input_buf = (float *)clEnqueueMapBuffer(q, s->net_input, CL_TRUE, - CL_MAP_READ, 0, s->net_input_size, + loadyuv_queue(&frame->loadyuv, q, + frame->transformed_y_cl, frame->transformed_u_cl, frame->transformed_v_cl, + frame->net_input); + float *net_input_buf = (float *)clEnqueueMapBuffer(q, frame->net_input, CL_TRUE, + CL_MAP_READ, 0, frame->net_input_size, 0, NULL, NULL, &err); clFinish(q); return net_input_buf; } -void model_input_free(ModelInput* s) { - transform_destroy(&s->transform); - loadyuv_destroy(&s->loadyuv); +void frame_free(ModelFrame* frame) { + transform_destroy(&frame->transform); + loadyuv_destroy(&frame->loadyuv); } diff --git a/selfdrive/modeld/models/commonmodel.h b/selfdrive/modeld/models/commonmodel.h index 2a03a3d00f..4e3ee448cf 100644 --- a/selfdrive/modeld/models/commonmodel.h +++ b/selfdrive/modeld/models/commonmodel.h @@ -4,7 +4,6 @@ #include #include "common/mat.h" -#include "common/modeldata.h" #include "transforms/transform.h" #include "transforms/loadyuv.h" @@ -15,7 +14,7 @@ extern "C" { float softplus(float input); float sigmoid(float input); -typedef struct ModelInput { +typedef struct ModelFrame { cl_device_id device_id; cl_context context; @@ -26,14 +25,14 @@ typedef struct ModelInput { LoadYUVState loadyuv; cl_mem net_input; size_t net_input_size; -} ModelInput; +} ModelFrame; -void model_input_init(ModelInput* s, int width, int height, +void frame_init(ModelFrame* frame, int width, int height, cl_device_id device_id, cl_context context); -float *model_input_prepare(ModelInput* s, cl_command_queue q, +float *frame_prepare(ModelFrame* frame, cl_command_queue q, cl_mem yuv_cl, int width, int height, mat3 transform); -void model_input_free(ModelInput* s); +void frame_free(ModelFrame* frame); #ifdef __cplusplus } diff --git a/selfdrive/modeld/models/driving.cc b/selfdrive/modeld/models/driving.cc index 127e3c2e80..06c820ff79 100644 --- a/selfdrive/modeld/models/driving.cc +++ b/selfdrive/modeld/models/driving.cc @@ -2,26 +2,20 @@ #include #include #include - -#ifdef QCOM -#include -#else -#include -#endif - #include "common/timing.h" #include "driving.h" -#define MODEL_WIDTH 512 -#define MODEL_HEIGHT 256 -#define MODEL_NAME "driving_model_dlc" -#define LEAD_MDN_N 5 // probs for 5 groups -#define MDN_VALS 4 // output xyva for each lead group -#define SELECTION 3 //output 3 group (lead now, in 2s and 6s) -#define MDN_GROUP_SIZE 11 -#define SPEED_BUCKETS 100 -#define OUTPUT_SIZE ((MODEL_PATH_DISTANCE*2) + (2*(MODEL_PATH_DISTANCE*2 + 1)) + MDN_GROUP_SIZE*LEAD_MDN_N + SELECTION + OTHER_META_SIZE + DESIRE_PRED_SIZE) +#define PATH_IDX 0 +#define LL_IDX PATH_IDX + MODEL_PATH_DISTANCE*2 +#define RL_IDX LL_IDX + MODEL_PATH_DISTANCE*2 + 1 +#define LEAD_IDX RL_IDX + MODEL_PATH_DISTANCE*2 + 1 +#define LONG_X_IDX LEAD_IDX + MDN_GROUP_SIZE*LEAD_MDN_N + SELECTION +#define LONG_V_IDX LONG_X_IDX + TIME_DISTANCE*2 +#define LONG_A_IDX LONG_V_IDX + TIME_DISTANCE*2 +#define META_IDX LONG_A_IDX + TIME_DISTANCE*2 +#define POSE_IDX META_IDX + OTHER_META_SIZE + DESIRE_PRED_SIZE +#define OUTPUT_SIZE POSE_IDX + POSE_SIZE #ifdef TEMPORAL #define TEMPORAL_SIZE 512 #else @@ -33,15 +27,19 @@ Eigen::Matrix vander; void model_init(ModelState* s, cl_device_id device_id, cl_context context, int temporal) { - model_input_init(&s->in, MODEL_WIDTH, MODEL_HEIGHT, device_id, context); + frame_init(&s->frame, MODEL_WIDTH, MODEL_HEIGHT, device_id, context); + s->input_frames = (float*)calloc(MODEL_FRAME_SIZE * 2, sizeof(float)); + const int output_size = OUTPUT_SIZE + TEMPORAL_SIZE; - s->output = (float*)malloc(output_size * sizeof(float)); - memset(s->output, 0, output_size * sizeof(float)); - s->m = new DefaultRunModel("../../models/driving_model.dlc", s->output, output_size, USE_GPU_RUNTIME); + s->output = (float*)calloc(output_size, sizeof(float)); + + s->m = new DefaultRunModel("../../models/supercombo.dlc", s->output, output_size, USE_GPU_RUNTIME); + #ifdef TEMPORAL assert(temporal); s->m->addRecurrent(&s->output[OUTPUT_SIZE], TEMPORAL_SIZE); #endif + #ifdef DESIRE s->desire = (float*)malloc(DESIRE_SIZE * sizeof(float)); for (int i = 0; i < DESIRE_SIZE; i++) s->desire[i] = 0.0; @@ -56,18 +54,11 @@ void model_init(ModelState* s, cl_device_id device_id, cl_context context, int t } } -ModelData model_eval_frame(ModelState* s, cl_command_queue q, + + +ModelDataRaw model_eval_frame(ModelState* s, cl_command_queue q, cl_mem yuv_cl, int width, int height, mat3 transform, void* sock, float *desire_in) { - struct { - float *path; - float *left_lane; - float *right_lane; - float *lead; - float *speed; - float *meta; - } net_outputs = {NULL}; - #ifdef DESIRE if (desire_in != NULL) { for (int i = 0; i < DESIRE_SIZE; i++) s->desire[i] = desire_in[i]; @@ -76,124 +67,36 @@ ModelData model_eval_frame(ModelState* s, cl_command_queue q, //for (int i = 0; i < OUTPUT_SIZE + TEMPORAL_SIZE; i++) { printf("%f ", s->output[i]); } printf("\n"); - float *net_input_buf = model_input_prepare(&s->in, q, yuv_cl, width, height, transform); + float *new_frame_buf = frame_prepare(&s->frame, q, yuv_cl, width, height, transform); + memmove(&s->input_frames[0], &s->input_frames[MODEL_FRAME_SIZE], sizeof(float)*MODEL_FRAME_SIZE); + memmove(&s->input_frames[MODEL_FRAME_SIZE], new_frame_buf, sizeof(float)*MODEL_FRAME_SIZE); + s->m->execute(s->input_frames); #ifdef DUMP_YUV FILE *dump_yuv_file = fopen("/sdcard/dump.yuv", "wb"); - fwrite(net_input_buf, MODEL_HEIGHT*MODEL_WIDTH*3/2, sizeof(float), dump_yuv_file); + fwrite(new_frame_buf, MODEL_HEIGHT*MODEL_WIDTH*3/2, sizeof(float), dump_yuv_file); fclose(dump_yuv_file); assert(1==2); #endif - //printf("readinggggg \n"); - //FILE *f = fopen("goof_frame", "r"); - //fread(net_input_buf, sizeof(float), MODEL_HEIGHT*MODEL_WIDTH*3/2, f); - //fclose(f); - //sleep(1); - //printf("%i \n",OUTPUT_SIZE); - //printf("%i \n",MDN_GROUP_SIZE); - s->m->execute(net_input_buf); - // net outputs - net_outputs.path = &s->output[0]; - net_outputs.left_lane = &s->output[MODEL_PATH_DISTANCE*2]; - net_outputs.right_lane = &s->output[MODEL_PATH_DISTANCE*2 + MODEL_PATH_DISTANCE*2 + 1]; - net_outputs.lead = &s->output[MODEL_PATH_DISTANCE*2 + (MODEL_PATH_DISTANCE*2 + 1)*2]; - //net_outputs.speed = &s->output[OUTPUT_SIZE - SPEED_BUCKETS]; - net_outputs.meta = &s->output[OUTPUT_SIZE - OTHER_META_SIZE - DESIRE_PRED_SIZE]; - - ModelData model = {0}; - - for (int i=0; i net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + 8]) { - mdn_max_idx = i; - } - } - model.lead.prob = sigmoid(net_outputs.lead[LEAD_MDN_N*MDN_GROUP_SIZE]); - model.lead.dist = net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE] * max_dist; - model.lead.std = softplus(net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + MDN_VALS]) * max_dist; - model.lead.rel_y = net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + 1]; - model.lead.rel_y_std = softplus(net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + MDN_VALS + 1]); - model.lead.rel_v = net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + 2] * max_rel_vel; - model.lead.rel_v_std = softplus(net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + MDN_VALS + 2]) * max_rel_vel; - model.lead.rel_a = net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + 3]; - model.lead.rel_a_std = softplus(net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + MDN_VALS + 3]); - - // Find the distribution that corresponds to the lead in 2s - mdn_max_idx = 0; - for (int i=1; i net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + 9]) { - mdn_max_idx = i; - } - } - model.lead_future.prob = sigmoid(net_outputs.lead[LEAD_MDN_N*MDN_GROUP_SIZE + 1]); - model.lead_future.dist = net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE] * max_dist; - model.lead_future.std = softplus(net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + MDN_VALS]) * max_dist; - model.lead_future.rel_y = net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + 1]; - model.lead_future.rel_y_std = softplus(net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + MDN_VALS + 1]); - model.lead_future.rel_v = net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + 2] * max_rel_vel; - model.lead_future.rel_v_std = softplus(net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + MDN_VALS + 2]) * max_rel_vel; - model.lead_future.rel_a = net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + 3]; - model.lead_future.rel_a_std = softplus(net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + MDN_VALS + 3]); - - - // get speed percentiles numbers represent 5th, 15th, ... 95th percentile - for (int i=0; i < SPEED_PERCENTILES; i++) { - model.speed[i] = ((float) SPEED_BUCKETS)/2.0; - } - //float sum = 0; - //for (int idx = 0; idx < SPEED_BUCKETS; idx++) { - // sum += net_outputs.speed[idx]; - // int idx_percentile = (sum + .05) * SPEED_PERCENTILES; - // if (idx_percentile < SPEED_PERCENTILES ){ - // model.speed[idx_percentile] = ((float)idx)/2.0; - // } - //} - // make sure no percentiles are skipped - //for (int i=SPEED_PERCENTILES-1; i > 0; i--){ - // if (model.speed[i-1] > model.speed[i]){ - // model.speed[i-1] = model.speed[i]; - // } - //} - for (int i=0; ioutput[PATH_IDX]; + net_outputs.left_lane = &s->output[LL_IDX]; + net_outputs.right_lane = &s->output[RL_IDX]; + net_outputs.lead = &s->output[LEAD_IDX]; + net_outputs.long_x = &s->output[LONG_X_IDX]; + net_outputs.long_v = &s->output[LONG_V_IDX]; + net_outputs.long_a = &s->output[LONG_A_IDX]; + net_outputs.meta = &s->output[META_IDX]; + net_outputs.pose = &s->output[POSE_IDX]; + return net_outputs; } void model_free(ModelState* s) { free(s->output); - model_input_free(&s->in); + free(s->input_frames); + frame_free(&s->frame); delete s->m; } @@ -224,31 +127,52 @@ void poly_fit(float *in_pts, float *in_stds, float *out) { } -void fill_path(cereal::ModelData::PathData::Builder path, const PathData path_data) { +void fill_path(cereal::ModelData::PathData::Builder path, const float * data, bool has_prob, const float offset) { + float points_arr[MODEL_PATH_DISTANCE]; + float stds_arr[MODEL_PATH_DISTANCE]; + float poly_arr[POLYFIT_DEGREE]; + float std; + float prob; + + for (int i=0; i stds(&path_data.stds[0], ARRAYSIZE(path_data.stds)); + kj::ArrayPtr stds(&stds_arr[0], ARRAYSIZE(stds_arr)); path.setStds(stds); - kj::ArrayPtr points(&path_data.points[0], ARRAYSIZE(path_data.points)); + kj::ArrayPtr points(&points_arr[0], ARRAYSIZE(points_arr)); path.setPoints(points); } - kj::ArrayPtr poly(&path_data.poly[0], ARRAYSIZE(path_data.poly)); + kj::ArrayPtr poly(&poly_arr[0], ARRAYSIZE(poly_arr)); path.setPoly(poly); - path.setProb(path_data.prob); - path.setStd(path_data.std); + path.setProb(prob); + path.setStd(std); } -void fill_lead(cereal::ModelData::LeadData::Builder lead, const LeadData lead_data) { - lead.setDist(lead_data.dist); - lead.setProb(lead_data.prob); - lead.setStd(lead_data.std); - lead.setRelY(lead_data.rel_y); - lead.setRelYStd(lead_data.rel_y_std); - lead.setRelVel(lead_data.rel_v); - lead.setRelVelStd(lead_data.rel_v_std); - lead.setRelA(lead_data.rel_a); - lead.setRelAStd(lead_data.rel_a_std); +void fill_lead(cereal::ModelData::LeadData::Builder lead, const float * data, int mdn_max_idx) { + const double x_scale = 10.0; + const double y_scale = 10.0; + + lead.setProb(sigmoid(data[LEAD_MDN_N*MDN_GROUP_SIZE])); + lead.setDist(x_scale * data[mdn_max_idx*MDN_GROUP_SIZE]); + lead.setStd(x_scale * softplus(data[mdn_max_idx*MDN_GROUP_SIZE + MDN_VALS])); + lead.setRelY(y_scale * data[mdn_max_idx*MDN_GROUP_SIZE + 1]); + lead.setRelYStd(y_scale * softplus(data[mdn_max_idx*MDN_GROUP_SIZE + MDN_VALS + 1])); + lead.setRelVel(data[mdn_max_idx*MDN_GROUP_SIZE + 2]); + lead.setRelVelStd(softplus(data[mdn_max_idx*MDN_GROUP_SIZE + MDN_VALS + 2])); + lead.setRelA(data[mdn_max_idx*MDN_GROUP_SIZE + 3]); + lead.setRelAStd(softplus(data[mdn_max_idx*MDN_GROUP_SIZE + MDN_VALS + 3])); } void fill_meta(cereal::ModelData::MetaData::Builder meta, const float * meta_data) { @@ -260,39 +184,104 @@ void fill_meta(cereal::ModelData::MetaData::Builder meta, const float * meta_dat meta.setDesirePrediction(desire_pred); } +void fill_longi(cereal::ModelData::LongitudinalData::Builder longi, const float * long_v_data, const float * long_a_data) { + // just doing 10 vals, 1 every sec for now + float speed_arr[TIME_DISTANCE/10]; + float accel_arr[TIME_DISTANCE/10]; + for (int i=0; i speed(&speed_arr[0], ARRAYSIZE(speed_arr)); + longi.setSpeeds(speed); + kj::ArrayPtr accel(&accel_arr[0], ARRAYSIZE(accel_arr)); + longi.setAccelerations(accel); +} + void model_publish(PubSocket *sock, uint32_t frame_id, - const ModelData data, uint64_t timestamp_eof) { - // make msg - capnp::MallocMessageBuilder msg; - cereal::Event::Builder event = msg.initRoot(); - event.setLogMonoTime(nanos_since_boot()); + const ModelDataRaw net_outputs, uint64_t timestamp_eof) { + // make msg + capnp::MallocMessageBuilder msg; + cereal::Event::Builder event = msg.initRoot(); + event.setLogMonoTime(nanos_since_boot()); + + auto framed = event.initModel(); + framed.setFrameId(frame_id); + framed.setTimestampEof(timestamp_eof); + + auto lpath = framed.initPath(); + fill_path(lpath, net_outputs.path, false, 0); + auto left_lane = framed.initLeftLane(); + fill_path(left_lane, net_outputs.left_lane, true, 1.8); + auto right_lane = framed.initRightLane(); + fill_path(right_lane, net_outputs.right_lane, true, -1.8); + auto longi = framed.initLongitudinal(); + fill_longi(longi, net_outputs.long_v, net_outputs.long_a); + + + // Find the distribution that corresponds to the current lead + int mdn_max_idx = 0; + for (int i=1; i net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + 8]) { + mdn_max_idx = i; + } + } + auto lead = framed.initLead(); + fill_lead(lead, net_outputs.lead, mdn_max_idx); + // Find the distribution that corresponds to the lead in 2s + mdn_max_idx = 0; + for (int i=1; i net_outputs.lead[mdn_max_idx*MDN_GROUP_SIZE + 9]) { + mdn_max_idx = i; + } + } + auto lead_future = framed.initLeadFuture(); + fill_lead(lead_future, net_outputs.lead, mdn_max_idx); - auto framed = event.initModel(); - framed.setFrameId(frame_id); - framed.setTimestampEof(timestamp_eof); - kj::ArrayPtr speed(&data.speed[0], ARRAYSIZE(data.speed)); - framed.setSpeed(speed); + auto meta = framed.initMeta(); + fill_meta(meta, net_outputs.meta); - auto lpath = framed.initPath(); - fill_path(lpath, data.path); - auto left_lane = framed.initLeftLane(); - fill_path(left_lane, data.left_lane); - auto right_lane = framed.initRightLane(); - fill_path(right_lane, data.right_lane); + // send message + auto words = capnp::messageToFlatArray(msg); + auto bytes = words.asBytes(); + sock->send((char*)bytes.begin(), bytes.size()); + } - auto lead = framed.initLead(); - fill_lead(lead, data.lead); - auto lead_future = framed.initLeadFuture(); - fill_lead(lead_future, data.lead_future); +void posenet_publish(PubSocket *sock, uint32_t frame_id, + const ModelDataRaw net_outputs, uint64_t timestamp_eof) { + capnp::MallocMessageBuilder msg; + cereal::Event::Builder event = msg.initRoot(); + event.setLogMonoTime(nanos_since_boot()); - auto meta = framed.initMeta(); - fill_meta(meta, data.meta); + float trans_arr[3]; + float trans_std_arr[3]; + float rot_arr[3]; + float rot_std_arr[3]; + for (int i =0; i < 3; i++) { + trans_arr[i] = net_outputs.pose[i]; + trans_std_arr[i] = softplus(net_outputs.pose[6 + i]) + 1e-6; - // send message - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - sock->send((char*)bytes.begin(), bytes.size()); - } + rot_arr[i] = M_PI * net_outputs.pose[3 + i] / 180.0; + rot_std_arr[i] = M_PI * (softplus(net_outputs.pose[9 + i]) + 1e-6) / 180.0; + } + + auto posenetd = event.initCameraOdometry(); + kj::ArrayPtr trans_vs(&trans_arr[0], 3); + posenetd.setTrans(trans_vs); + kj::ArrayPtr rot_vs(&rot_arr[0], 3); + posenetd.setRot(rot_vs); + kj::ArrayPtr trans_std_vs(&trans_std_arr[0], 3); + posenetd.setTransStd(trans_std_vs); + kj::ArrayPtr rot_std_vs(&rot_std_arr[0], 3); + posenetd.setRotStd(rot_std_vs); + + posenetd.setTimestampEof(timestamp_eof); + posenetd.setFrameId(frame_id); + + auto words = capnp::messageToFlatArray(msg); + auto bytes = words.asBytes(); + sock->send((char*)bytes.begin(), bytes.size()); + } diff --git a/selfdrive/modeld/models/driving.h b/selfdrive/modeld/models/driving.h index ccf8a94be2..bf46cb9d47 100644 --- a/selfdrive/modeld/models/driving.h +++ b/selfdrive/modeld/models/driving.h @@ -9,8 +9,13 @@ #define DESIRE_SIZE 8 #endif +#ifdef QCOM +#include +#else +#include +#endif + #include "common/mat.h" -#include "common/modeldata.h" #include "common/util.h" #include "commonmodel.h" @@ -21,10 +26,40 @@ #include #include "messaging.hpp" +#define MODEL_WIDTH 512 +#define MODEL_HEIGHT 256 +#define MODEL_FRAME_SIZE MODEL_WIDTH * MODEL_HEIGHT * 3 / 2 +#define MODEL_NAME "supercombo_dlc" + +#define MODEL_PATH_DISTANCE 192 +#define POLYFIT_DEGREE 4 +#define SPEED_PERCENTILES 10 +#define DESIRE_PRED_SIZE 32 +#define OTHER_META_SIZE 4 +#define LEAD_MDN_N 5 // probs for 5 groups +#define MDN_VALS 4 // output xyva for each lead group +#define SELECTION 3 //output 3 group (lead now, in 2s and 6s) +#define MDN_GROUP_SIZE 11 +#define TIME_DISTANCE 100 +#define POSE_SIZE 12 + +struct ModelDataRaw { + float *path; + float *left_lane; + float *right_lane; + float *lead; + float *long_x; + float *long_v; + float *long_a; + float *meta; + float *pose; + }; + typedef struct ModelState { - ModelInput in; + ModelFrame frame; float *output; + float *input_frames; RunModel *m; #ifdef DESIRE float *desire; @@ -33,12 +68,14 @@ typedef struct ModelState { void model_init(ModelState* s, cl_device_id device_id, cl_context context, int temporal); -ModelData model_eval_frame(ModelState* s, cl_command_queue q, +ModelDataRaw model_eval_frame(ModelState* s, cl_command_queue q, cl_mem yuv_cl, int width, int height, mat3 transform, void* sock, float *desire_in); void model_free(ModelState* s); void poly_fit(float *in_pts, float *in_stds, float *out); void model_publish(PubSocket* sock, uint32_t frame_id, - const ModelData data, uint64_t timestamp_eof); + const ModelDataRaw data, uint64_t timestamp_eof); +void posenet_publish(PubSocket* sock, uint32_t frame_id, + const ModelDataRaw data, uint64_t timestamp_eof); #endif diff --git a/selfdrive/modeld/models/posenet.cc b/selfdrive/modeld/models/posenet.cc deleted file mode 100644 index c843e81f4d..0000000000 --- a/selfdrive/modeld/models/posenet.cc +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include "posenet.h" - -void posenet_init(PosenetState *s) { - s->input = (float*)malloc(2*200*532*sizeof(float)); - s->m = new DefaultRunModel("../../models/posenet.dlc", s->output, sizeof(s->output)/sizeof(float), USE_GPU_RUNTIME); -} - -void posenet_push(PosenetState *s, uint8_t *yuv_ptr_y, int yuv_width) { - // move second frame to first frame - memmove(&s->input[0], &s->input[1], sizeof(float)*(200*532*2 - 1)); - - // fill posenet input - float a; - // posenet uses a half resolution cropped frame - // with upper left corner: [50, 237] and - // bottom right corner: [1114, 637] - // So the resulting crop is 532 X 200 - for (int y=237; y<637; y+=2) { - int yy = (y-237)/2; - for (int x = 50; x < 1114; x+=2) { - int xx = (x-50)/2; - a = 0; - a += yuv_ptr_y[yuv_width*(y+0) + (x+1)]; - a += yuv_ptr_y[yuv_width*(y+1) + (x+1)]; - a += yuv_ptr_y[yuv_width*(y+0) + (x+0)]; - a += yuv_ptr_y[yuv_width*(y+1) + (x+0)]; - // The posenet takes a normalized image input - // like the driving model so [0,255] is remapped - // to [-1,1] - s->input[(yy*532+xx)*2 + 1] = (a/512.0 - 1.0); - } - } -} - -void posenet_eval(PosenetState *s) { - s->m->execute(s->input); - - // fix stddevs - for (int i = 6; i < 12; i++) { - s->output[i] = log1p(exp(s->output[i])) + 1e-6; - } - // to radians - for (int i = 3; i < 6; i++) { - s->output[i] = M_PI * s->output[i] / 180.0; - } - // to radians - for (int i = 9; i < 12; i++) { - s->output[i] = M_PI * s->output[i] / 180.0; - } -} - -void posenet_free(PosenetState *s) { - delete s->m; - free(s->input); -} - diff --git a/selfdrive/modeld/models/posenet.h b/selfdrive/modeld/models/posenet.h deleted file mode 100644 index 2e6571a1d4..0000000000 --- a/selfdrive/modeld/models/posenet.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef POSENET_H -#define POSENET_H - -#include -#include "runners/run.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct PosenetState { - float output[12]; - float *input; - RunModel *m; -} PosenetState; - -void posenet_init(PosenetState *s); -void posenet_push(PosenetState *s, uint8_t *yuv_ptr_y, int yuv_width); -void posenet_eval(PosenetState *s); -void posenet_free(PosenetState *s); - -#ifdef __cplusplus -} -#endif - -#endif - diff --git a/selfdrive/modeld/monitoringd b/selfdrive/modeld/monitoringd index 63e28b12f7..419d826331 100755 --- a/selfdrive/modeld/monitoringd +++ b/selfdrive/modeld/monitoringd @@ -1,5 +1,5 @@ #!/bin/sh -export LD_LIBRARY_PATH="/data/pythonpath/phonelibs/snpe/aarch64-android-clang3.8:$LD_LIBRARY_PATH" +export LD_LIBRARY_PATH="/data/pythonpath/phonelibs/snpe/aarch64-android-clang3.8:/home/batman/one/phonelibs/snpe/x86_64-linux-clang:$LD_LIBRARY_PATH" export ADSP_LIBRARY_PATH="/data/pythonpath/phonelibs/snpe/aarch64-android-clang3.8/" exec ./_monitoringd diff --git a/selfdrive/modeld/runners/run.h b/selfdrive/modeld/runners/run.h index 049f065845..56e7853974 100644 --- a/selfdrive/modeld/runners/run.h +++ b/selfdrive/modeld/runners/run.h @@ -7,9 +7,12 @@ #ifdef QCOM #define DefaultRunModel SNPEModel #else -#define DefaultRunModel SNPEModel - /* #include "tfmodel.h" */ - /* #define DefaultRunModel TFModel */ + #ifdef USE_TF_MODEL + #include "tfmodel.h" + #define DefaultRunModel TFModel + #else + #define DefaultRunModel SNPEModel + #endif #endif #endif diff --git a/selfdrive/pandad.py b/selfdrive/pandad.py index 2ef286fa7a..7cbc704b98 100755 --- a/selfdrive/pandad.py +++ b/selfdrive/pandad.py @@ -4,19 +4,29 @@ import os import time from selfdrive.swaglog import cloudlog -from panda import Panda, PandaDFU, BASEDIR +from panda import Panda, PandaDFU, BASEDIR, build_st -def get_expected_version(): - with open(os.path.join(BASEDIR, "VERSION")) as f: - repo_version = f.read() - repo_version += "-EON" if os.path.isfile('/EON') else "-DEV" - return repo_version +def get_firmware_fn(): + signed_fn = os.path.join(BASEDIR, "board", "obj", "panda.bin.signed") + if os.path.exists(signed_fn): + cloudlog.info("Using prebuilt signed firmware") + return signed_fn + else: + cloudlog.info("Building panda firmware") + fn = "obj/panda.bin" + build_st(fn, clean=False) + return os.path.join(BASEDIR, "board", fn) -def update_panda(): - repo_version = get_expected_version() +def get_expected_signature(fw_fn=None): + if fw_fn is None: + fw_fn = get_firmware_fn() + + return Panda.get_signature_from_firmware(fw_fn) + +def update_panda(): panda = None panda_dfu = None @@ -37,27 +47,28 @@ def update_panda(): panda_dfu = PandaDFU(panda_dfu[0]) panda_dfu.recover() - print("waiting for board...") time.sleep(1) + fw_fn = get_firmware_fn() + fw_signature = get_expected_signature(fw_fn) + try: serial = panda.get_serial()[0].decode("utf-8") except Exception: serial = None - current_version = "bootstub" if panda.bootstub else panda.get_version() - cloudlog.warning("Panda %s connected, version: %s, expected %s" % (serial, current_version, repo_version)) - - if panda.bootstub or not current_version.startswith(repo_version): - cloudlog.info("Panda firmware out of date, update required") - signed_fn = os.path.join(BASEDIR, "board", "obj", "panda.bin.signed") - if os.path.exists(signed_fn): - cloudlog.info("Flashing signed firmware") - panda.flash(fn=signed_fn) - else: - cloudlog.info("Building and flashing unsigned firmware") - panda.flash() + panda_version = "bootstub" if panda.bootstub else panda.get_version() + panda_signature = "bootstub" if panda.bootstub else panda.get_signature() + cloudlog.warning("Panda %s connected, version: %s, signature %s, expected %s" % ( + serial, + panda_version, + panda_signature.hex(), + fw_signature.hex(), + )) + if panda.bootstub or panda_signature != fw_signature: + cloudlog.info("Panda firmware out of date, update required") + panda.flash(fw_fn) cloudlog.info("Done flashing") if panda.bootstub: @@ -69,8 +80,8 @@ def update_panda(): cloudlog.info("Panda still not booting, exiting") raise AssertionError - version = panda.get_version() - if not version.startswith(repo_version): + panda_signature = panda.get_signature() + if panda_signature != fw_signature: cloudlog.info("Version mismatch after flashing, exiting") raise AssertionError diff --git a/selfdrive/registration.py b/selfdrive/registration.py index 734f6f8713..afa2771bc1 100644 --- a/selfdrive/registration.py +++ b/selfdrive/registration.py @@ -7,6 +7,7 @@ from selfdrive.version import version, terms_version, training_version, get_git_ from common.android import get_imei, get_serial, get_subscriber_info from common.api import api_get from common.params import Params +from common.file_helpers import mkdirs_exists_ok def register(): params = Params() @@ -18,6 +19,17 @@ def register(): params.put("GitRemote", get_git_remote()) params.put("SubscriberInfo", get_subscriber_info()) + # create a key for auth + # your private key is kept on your device persist partition and never sent to our servers + # do not erase your persist partition + if not os.path.isfile("/persist/comma/id_rsa.pub"): + cloudlog.warning("generating your personal RSA key") + mkdirs_exists_ok("/persist/comma") + assert os.system("openssl genrsa -out /persist/comma/id_rsa.tmp 2048") == 0 + assert os.system("openssl rsa -in /persist/comma/id_rsa.tmp -pubout -out /persist/comma/id_rsa.tmp.pub") == 0 + os.rename("/persist/comma/id_rsa.tmp", "/persist/comma/id_rsa") + os.rename("/persist/comma/id_rsa.tmp.pub", "/persist/comma/id_rsa.pub") + # make key readable by app users (ai.comma.plus.offroad) os.chmod('/persist/comma/', 0o755) os.chmod('/persist/comma/id_rsa', 0o744) @@ -36,7 +48,7 @@ def register(): try: cloudlog.info("getting pilotauth") resp = api_get("v2/pilotauth/", method='POST', timeout=15, - imei=get_imei(), serial=get_serial(), public_key=public_key, register_token=register_token) + imei=get_imei(0), imei2=get_imei(1), serial=get_serial(), public_key=public_key, register_token=register_token) dongleauth = json.loads(resp.text) dongle_id, access_token = dongleauth["dongle_id"], dongleauth["access_token"] @@ -51,5 +63,4 @@ def register(): return None if __name__ == "__main__": - print(api_get("").text) print(register()) diff --git a/selfdrive/sensord/gpsd.cc b/selfdrive/sensord/gpsd.cc index 54eb6b4dc4..ae2ecec035 100644 --- a/selfdrive/sensord/gpsd.cc +++ b/selfdrive/sensord/gpsd.cc @@ -7,7 +7,6 @@ #include #include #include -#include #include #include @@ -31,8 +30,6 @@ volatile sig_atomic_t do_exit = 0; namespace { -pthread_t clock_thread_handle; - Context *gps_context; PubSocket *gps_publisher; PubSocket *gps_location_publisher; @@ -181,61 +178,6 @@ int64_t arm_cntpct() { return v; } -// TODO: move this out of here -void* clock_thread(void* args) { - int err = 0; - - PubSocket* clock_publisher = PubSocket::create(gps_context, "clocks"); - assert(clock_publisher != NULL); - - int timerfd = timerfd_create(CLOCK_BOOTTIME, 0); - assert(timerfd >= 0); - - struct itimerspec spec = {0}; - spec.it_interval.tv_sec = 1; - spec.it_interval.tv_nsec = 0; - spec.it_value.tv_sec = 1; - spec.it_value.tv_nsec = 0; - - err = timerfd_settime(timerfd, 0, &spec, 0); - assert(err == 0); - - uint64_t expirations = 0; - while ((err = read(timerfd, &expirations, sizeof(expirations)))) { - if (err < 0) break; - - if (do_exit) break; - - uint64_t boottime = nanos_since_boot(); - uint64_t monotonic = nanos_monotonic(); - uint64_t monotonic_raw = nanos_monotonic_raw(); - uint64_t wall_time = nanos_since_epoch(); - - uint64_t modem_uptime_v = arm_cntpct() / 19200ULL; // 19.2 mhz clock - - capnp::MallocMessageBuilder msg; - cereal::Event::Builder event = msg.initRoot(); - event.setLogMonoTime(boottime); - auto clocks = event.initClocks(); - - clocks.setBootTimeNanos(boottime); - clocks.setMonotonicNanos(monotonic); - clocks.setMonotonicRawNanos(monotonic_raw); - clocks.setWallTimeNanos(wall_time); - clocks.setModemUptimeMillis(modem_uptime_v); - - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - clock_publisher->send((char*)bytes.begin(), bytes.size()); - } - - close(timerfd); - delete clock_publisher; - - return NULL; -} - - } int main() { @@ -249,15 +191,8 @@ int main() { rawgps_init(); - err = pthread_create(&clock_thread_handle, NULL, - clock_thread, NULL); - assert(err == 0); - while(!do_exit) pause(); - err = pthread_join(clock_thread_handle, NULL); - assert(err == 0); - rawgps_destroy(); gps_destroy(); diff --git a/selfdrive/sensord/sensors.cc b/selfdrive/sensord/sensors.cc index 0f70bb66c0..952a4863c2 100644 --- a/selfdrive/sensord/sensors.cc +++ b/selfdrive/sensord/sensors.cc @@ -38,6 +38,7 @@ #define SENSOR_LIGHT 7 volatile sig_atomic_t do_exit = 0; +volatile sig_atomic_t re_init_sensors = 0; namespace { @@ -47,180 +48,191 @@ void set_do_exit(int sig) { void sigpipe_handler(int sig) { LOGE("SIGPIPE received"); + re_init_sensors = true; } void sensor_loop() { LOG("*** sensor loop"); - Context * c = Context::create(); - PubSocket * sensor_events_sock = PubSocket::create(c, "sensorEvents"); - assert(sensor_events_sock != NULL); - struct sensors_poll_device_t* device; - struct sensors_module_t* module; - - hw_get_module(SENSORS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); - sensors_open(&module->common, &device); + while (!do_exit) { + Context * c = Context::create(); + PubSocket * sensor_events_sock = PubSocket::create(c, "sensorEvents"); + assert(sensor_events_sock != NULL); - // required - struct sensor_t const* list; - int count = module->get_sensors_list(module, &list); - LOG("%d sensors found", count); + struct sensors_poll_device_t* device; + struct sensors_module_t* module; - if (getenv("SENSOR_TEST")) { - exit(count); - } - - for (int i = 0; i < count; i++) { - LOGD("sensor %4d: %4d %60s %d-%ld us", i, list[i].handle, list[i].name, list[i].minDelay, list[i].maxDelay); - } + hw_get_module(SENSORS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); + sensors_open(&module->common, &device); - device->activate(device, SENSOR_MAGNETOMETER_UNCALIBRATED, 0); - device->activate(device, SENSOR_GYRO_UNCALIBRATED, 0); - device->activate(device, SENSOR_ACCELEROMETER, 0); - device->activate(device, SENSOR_MAGNETOMETER, 0); - device->activate(device, SENSOR_GYRO, 0); - device->activate(device, SENSOR_PROXIMITY, 0); - device->activate(device, SENSOR_LIGHT, 0); - - device->activate(device, SENSOR_MAGNETOMETER_UNCALIBRATED, 1); - device->activate(device, SENSOR_GYRO_UNCALIBRATED, 1); - device->activate(device, SENSOR_ACCELEROMETER, 1); - device->activate(device, SENSOR_MAGNETOMETER, 1); - device->activate(device, SENSOR_GYRO, 1); - device->activate(device, SENSOR_PROXIMITY, 1); - device->activate(device, SENSOR_LIGHT, 1); - - device->setDelay(device, SENSOR_GYRO_UNCALIBRATED, ms2ns(10)); - device->setDelay(device, SENSOR_MAGNETOMETER_UNCALIBRATED, ms2ns(100)); - device->setDelay(device, SENSOR_ACCELEROMETER, ms2ns(10)); - device->setDelay(device, SENSOR_GYRO, ms2ns(10)); - device->setDelay(device, SENSOR_MAGNETOMETER, ms2ns(100)); - device->setDelay(device, SENSOR_PROXIMITY, ms2ns(100)); - device->setDelay(device, SENSOR_LIGHT, ms2ns(100)); - - static const size_t numEvents = 16; - sensors_event_t buffer[numEvents]; + // required + struct sensor_t const* list; + int count = module->get_sensors_list(module, &list); + LOG("%d sensors found", count); + if (getenv("SENSOR_TEST")) { + exit(count); + } - while (!do_exit) { - int n = device->poll(device, buffer, numEvents); - if (n == 0) continue; - if (n < 0) { - LOG("sensor_loop poll failed: %d", n); - continue; + for (int i = 0; i < count; i++) { + LOGD("sensor %4d: %4d %60s %d-%ld us", i, list[i].handle, list[i].name, list[i].minDelay, list[i].maxDelay); } - int log_events = 0; - for (int i=0; i < n; i++) { - switch (buffer[i].type) { - case SENSOR_TYPE_ACCELEROMETER: - case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: - case SENSOR_TYPE_MAGNETIC_FIELD: - case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: - case SENSOR_TYPE_GYROSCOPE: - case SENSOR_TYPE_PROXIMITY: - case SENSOR_TYPE_LIGHT: - log_events++; - break; - default: + device->activate(device, SENSOR_MAGNETOMETER_UNCALIBRATED, 0); + device->activate(device, SENSOR_GYRO_UNCALIBRATED, 0); + device->activate(device, SENSOR_ACCELEROMETER, 0); + device->activate(device, SENSOR_MAGNETOMETER, 0); + device->activate(device, SENSOR_GYRO, 0); + device->activate(device, SENSOR_PROXIMITY, 0); + device->activate(device, SENSOR_LIGHT, 0); + + device->activate(device, SENSOR_MAGNETOMETER_UNCALIBRATED, 1); + device->activate(device, SENSOR_GYRO_UNCALIBRATED, 1); + device->activate(device, SENSOR_ACCELEROMETER, 1); + device->activate(device, SENSOR_MAGNETOMETER, 1); + device->activate(device, SENSOR_GYRO, 1); + device->activate(device, SENSOR_PROXIMITY, 1); + device->activate(device, SENSOR_LIGHT, 1); + + device->setDelay(device, SENSOR_GYRO_UNCALIBRATED, ms2ns(10)); + device->setDelay(device, SENSOR_MAGNETOMETER_UNCALIBRATED, ms2ns(100)); + device->setDelay(device, SENSOR_ACCELEROMETER, ms2ns(10)); + device->setDelay(device, SENSOR_GYRO, ms2ns(10)); + device->setDelay(device, SENSOR_MAGNETOMETER, ms2ns(100)); + device->setDelay(device, SENSOR_PROXIMITY, ms2ns(100)); + device->setDelay(device, SENSOR_LIGHT, ms2ns(100)); + + static const size_t numEvents = 16; + sensors_event_t buffer[numEvents]; + + + while (!do_exit) { + int n = device->poll(device, buffer, numEvents); + if (n == 0) continue; + if (n < 0) { + LOG("sensor_loop poll failed: %d", n); continue; } - } - uint64_t log_time = nanos_since_boot(); - - capnp::MallocMessageBuilder msg; - cereal::Event::Builder event = msg.initRoot(); - event.setLogMonoTime(log_time); - - auto sensor_events = event.initSensorEvents(log_events); - - int log_i = 0; - for (int i = 0; i < n; i++) { - - const sensors_event_t& data = buffer[i]; - - switch (data.type) { - case SENSOR_TYPE_ACCELEROMETER: - case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: - case SENSOR_TYPE_MAGNETIC_FIELD: - case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: - case SENSOR_TYPE_GYROSCOPE: - case SENSOR_TYPE_PROXIMITY: - case SENSOR_TYPE_LIGHT: - break; - default: - continue; + int log_events = 0; + for (int i=0; i < n; i++) { + switch (buffer[i].type) { + case SENSOR_TYPE_ACCELEROMETER: + case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: + case SENSOR_TYPE_MAGNETIC_FIELD: + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: + case SENSOR_TYPE_GYROSCOPE: + case SENSOR_TYPE_PROXIMITY: + case SENSOR_TYPE_LIGHT: + log_events++; + break; + default: + continue; + } } - auto log_event = sensor_events[log_i]; + uint64_t log_time = nanos_since_boot(); + + capnp::MallocMessageBuilder msg; + cereal::Event::Builder event = msg.initRoot(); + event.setLogMonoTime(log_time); + + auto sensor_events = event.initSensorEvents(log_events); + + int log_i = 0; + for (int i = 0; i < n; i++) { + + const sensors_event_t& data = buffer[i]; + + switch (data.type) { + case SENSOR_TYPE_ACCELEROMETER: + case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: + case SENSOR_TYPE_MAGNETIC_FIELD: + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: + case SENSOR_TYPE_GYROSCOPE: + case SENSOR_TYPE_PROXIMITY: + case SENSOR_TYPE_LIGHT: + break; + default: + continue; + } + + auto log_event = sensor_events[log_i]; + + log_event.setSource(cereal::SensorEventData::SensorSource::ANDROID); + log_event.setVersion(data.version); + log_event.setSensor(data.sensor); + log_event.setType(data.type); + log_event.setTimestamp(data.timestamp); + + switch (data.type) { + case SENSOR_TYPE_ACCELEROMETER: { + auto svec = log_event.initAcceleration(); + kj::ArrayPtr vs(&data.acceleration.v[0], 3); + svec.setV(vs); + svec.setStatus(data.acceleration.status); + break; + } + case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: { + auto svec = log_event.initMagneticUncalibrated(); + // assuming the uncalib and bias floats are contiguous in memory + kj::ArrayPtr vs(&data.uncalibrated_magnetic.uncalib[0], 6); + svec.setV(vs); + break; + } + case SENSOR_TYPE_MAGNETIC_FIELD: { + auto svec = log_event.initMagnetic(); + kj::ArrayPtr vs(&data.magnetic.v[0], 3); + svec.setV(vs); + svec.setStatus(data.magnetic.status); + break; + } + case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: { + auto svec = log_event.initGyroUncalibrated(); + // assuming the uncalib and bias floats are contiguous in memory + kj::ArrayPtr vs(&data.uncalibrated_gyro.uncalib[0], 6); + svec.setV(vs); + break; + } + case SENSOR_TYPE_GYROSCOPE: { + auto svec = log_event.initGyro(); + kj::ArrayPtr vs(&data.gyro.v[0], 3); + svec.setV(vs); + svec.setStatus(data.gyro.status); + break; + } + case SENSOR_TYPE_PROXIMITY: { + log_event.setProximity(data.distance); + break; + } + case SENSOR_TYPE_LIGHT: + log_event.setLight(data.light); + break; + } + + log_i++; + } - log_event.setSource(cereal::SensorEventData::SensorSource::ANDROID); - log_event.setVersion(data.version); - log_event.setSensor(data.sensor); - log_event.setType(data.type); - log_event.setTimestamp(data.timestamp); + auto words = capnp::messageToFlatArray(msg); + auto bytes = words.asBytes(); + sensor_events_sock->send((char*)bytes.begin(), bytes.size()); - switch (data.type) { - case SENSOR_TYPE_ACCELEROMETER: { - auto svec = log_event.initAcceleration(); - kj::ArrayPtr vs(&data.acceleration.v[0], 3); - svec.setV(vs); - svec.setStatus(data.acceleration.status); + if (re_init_sensors){ + LOGE("Resetting sensors"); + re_init_sensors = false; break; } - case SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED: { - auto svec = log_event.initMagneticUncalibrated(); - // assuming the uncalib and bias floats are contiguous in memory - kj::ArrayPtr vs(&data.uncalibrated_magnetic.uncalib[0], 6); - svec.setV(vs); - break; - } - case SENSOR_TYPE_MAGNETIC_FIELD: { - auto svec = log_event.initMagnetic(); - kj::ArrayPtr vs(&data.magnetic.v[0], 3); - svec.setV(vs); - svec.setStatus(data.magnetic.status); - break; - } - case SENSOR_TYPE_GYROSCOPE_UNCALIBRATED: { - auto svec = log_event.initGyroUncalibrated(); - // assuming the uncalib and bias floats are contiguous in memory - kj::ArrayPtr vs(&data.uncalibrated_gyro.uncalib[0], 6); - svec.setV(vs); - break; - } - case SENSOR_TYPE_GYROSCOPE: { - auto svec = log_event.initGyro(); - kj::ArrayPtr vs(&data.gyro.v[0], 3); - svec.setV(vs); - svec.setStatus(data.gyro.status); - break; - } - case SENSOR_TYPE_PROXIMITY: { - log_event.setProximity(data.distance); - break; - } - case SENSOR_TYPE_LIGHT: - log_event.setLight(data.light); - break; - } - - log_i++; } - auto words = capnp::messageToFlatArray(msg); - auto bytes = words.asBytes(); - sensor_events_sock->send((char*)bytes.begin(), bytes.size()); + delete sensor_events_sock; + delete c; } - - delete sensor_events_sock; - delete c; -} } +}// Namespace end + int main(int argc, char *argv[]) { setpriority(PRIO_PROCESS, 0, -13); signal(SIGINT, (sighandler_t)set_do_exit); diff --git a/selfdrive/test/longitudinal_maneuvers/plant.py b/selfdrive/test/longitudinal_maneuvers/plant.py index 5dd1d0789b..06b2437695 100755 --- a/selfdrive/test/longitudinal_maneuvers/plant.py +++ b/selfdrive/test/longitudinal_maneuvers/plant.py @@ -272,6 +272,7 @@ class Plant(): 'INTERCEPTOR_GAS', 'INTERCEPTOR_GAS2', 'IMPERIAL_UNIT', + 'MOTOR_TORQUE', ]) vls = vls_tuple( self.speed_sensor(speed), @@ -304,7 +305,8 @@ class Plant(): 0, # Brake hold 0, # Interceptor feedback 0, # Interceptor 2 feedback - False + False, + 0, ) # TODO: publish each message at proper frequency diff --git a/selfdrive/test/process_replay/process_replay.py b/selfdrive/test/process_replay/process_replay.py index fdce596e41..14969954c2 100755 --- a/selfdrive/test/process_replay/process_replay.py +++ b/selfdrive/test/process_replay/process_replay.py @@ -159,11 +159,11 @@ def get_car_params(msgs, fsm, can_sock): _, CP = get_car(can, sendcan) Params().put("CarParams", CP.to_bytes()) -def radar_rcv_callback(msg, CP): +def radar_rcv_callback(msg, CP, cfg, fsm): if msg.which() != "can": - return [] + return [], False elif CP.radarOffCan: - return ["radarState", "liveTracks"] + return ["radarState", "liveTracks"], True radar_msgs = {"honda": [0x445], "toyota": [0x19f, 0x22f], "gm": [0x474], "chrysler": [0x2d4]}.get(CP.carName, None) @@ -173,8 +173,15 @@ def radar_rcv_callback(msg, CP): for m in msg.can: if m.src == 1 and m.address in radar_msgs: - return ["radarState", "liveTracks"] - return [] + return ["radarState", "liveTracks"], True + return [], False + +def calibration_rcv_callback(msg, CP, cfg, fsm): + # calibrationd publishes 1 calibrationData every 5 cameraOdometry packets. + # should_recv always true to increment frame + recv_socks = ["liveCalibration"] if (fsm.frame + 1) % 5 == 0 else [] + return recv_socks, True + CONFIGS = [ ProcessConfig( @@ -215,7 +222,7 @@ CONFIGS = [ }, ignore=[("logMonoTime", 0), ("valid", True)], init_callback=get_car_params, - should_recv_callback=None, + should_recv_callback=calibration_rcv_callback, ), ] @@ -263,12 +270,11 @@ def replay_process(cfg, lr): log_msgs, msg_queue = [], [] for msg in tqdm(pub_msgs): if cfg.should_recv_callback is not None: - recv_socks = cfg.should_recv_callback(msg, CP) + recv_socks, should_recv = cfg.should_recv_callback(msg, CP, cfg, fsm) else: recv_socks = [s for s in cfg.pub_sub[msg.which()] if (fsm.frame + 1) % int(service_list[msg.which()].frequency / service_list[s].frequency) == 0] - - should_recv = bool(len(recv_socks)) + should_recv = bool(len(recv_socks)) if msg.which() == 'can': can_sock.send(msg.as_builder().to_bytes()) diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 0c0be19b61..823608db0e 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -89304bdcab73fa43a8dd39cab93bc4ea4c9cbbdb \ No newline at end of file +b60841eb6cf09037200bc2daacf0c9cf69b358fe \ No newline at end of file diff --git a/selfdrive/test/test_car_models.py b/selfdrive/test/test_car_models.py index 0d18496d52..c1aa39a7fa 100755 --- a/selfdrive/test/test_car_models.py +++ b/selfdrive/test/test_car_models.py @@ -39,8 +39,6 @@ def wait_for_socket(name, timeout=10.0): break time.sleep(0.5) - if r is None: - sys.exit(-1) return r def get_route_logs(route_name): @@ -405,42 +403,48 @@ passive_routes = [ #"bfa17080b080f3ec|2018-06-28--23-27-47", ] +forced_dashcam_routes = [ + # Ford fusion + "f1b4c567731f4a1b|2018-04-18--11-29-37", + "f1b4c567731f4a1b|2018-04-30--10-15-35", +] + # TODO: replace all these with public routes # TODO: add routes for untested cars: HONDA ACCORD 2018 HYBRID TOURING and CHRYSLER PACIFICA 2018 non_public_routes = [ - "0607d2516fc2148f|2019-02-13--23-03-16", # CHRYSLER PACIFICA HYBRID 2019 - "3e9592a1c78a3d63|2018-02-08--20-28-24", # HONDA PILOT 2017 TOURING - "aa20e335f61ba898|2019-02-05--16-59-04", # BUICK REGAL ESSENCE 2018 - "1851183c395ef471|2018-05-31--18-07-21", # HONDA CR-V 2017 EX - "9d5fb4f0baa1b3e1|2019-01-14--17-45-59", # KIA SORENTO GT LINE 2018 - "b4c18bf13d5955da|2018-07-29--13-39-46", # TOYOTA C-HR HYBRID 2018 - "5a2cfe4bb362af9e|2018-02-02--23-41-07", # ACURA RDX 2018 ACURAWATCH PLUS - "362d23d4d5bea2fa|2018-08-10--13-31-40", # TOYOTA HIGHLANDER HYBRID 2018 - "aa20e335f61ba898|2018-12-17--21-10-37", # BUICK REGAL ESSENCE 2018 - "215cd70e9c349266|2018-11-25--22-22-12", # KIA STINGER GT2 2018 - "192a598e34926b1e|2019-04-04--13-27-39", # JEEP GRAND CHEROKEE 2019 - "34a84d2b765df688|2018-08-28--12-41-00", # HONDA PILOT 2019 ELITE - "b0c9d2329ad1606b|2019-01-06--10-11-23", # CHRYSLER PACIFICA HYBRID 2017 - "31390e3eb6f7c29a|2019-01-23--08-56-00", # KIA OPTIMA SX 2019 - "fd10b9a107bb2e49|2018-07-24--16-32-42", # TOYOTA C-HR 2018 - "9f7a7e50a51fb9db|2019-01-17--18-34-21", # JEEP GRAND CHEROKEE V6 2018 - "aadda448b49c99ad|2018-10-25--17-16-22", # CHEVROLET MALIBU PREMIER 2017 - "362d23d4d5bea2fa|2018-09-02--17-03-55", # TOYOTA HIGHLANDER HYBRID 2018 - "1582e1dc57175194|2018-08-15--07-46-07", # HONDA ACCORD 2018 LX 1.5T - "fd10b9a107bb2e49|2018-07-24--20-32-08", # TOYOTA C-HR 2018 - "265007255e794bce|2018-11-24--22-08-31", # CADILLAC ATS Premium Performance 2018 - "53ac3251e03f95d7|2019-01-10--13-43-32", # HYUNDAI ELANTRA LIMITED ULTIMATE 2017 - "21aa231dee2a68bd|2018-01-30--04-54-41", # HONDA ODYSSEY 2018 EX-L - "900ad17e536c3dc7|2018-04-12--22-02-36", # HONDA RIDGELINE 2017 BLACK EDITION - "975b26878285314d|2018-12-25--14-42-13", # CHRYSLER PACIFICA HYBRID 2018 - "8ae193ceb56a0efe|2018-06-18--20-07-32", # TOYOTA RAV4 HYBRID 2017 - "a893a80e5c5f72c8|2019-01-14--20-02-59", # HYUNDAI GENESIS 2018 - "49c73650e65ff465|2018-11-19--16-58-04", # HOLDEN ASTRA RS-V BK 2017 - "d2d8152227f7cb82|2018-07-25--13-40-56", # TOYOTA CAMRY 2018 - "07cb8a788c31f645|2018-06-17--18-50-29", # mock - "c9d60e5e02c04c5c|2018-01-08--16-01-49", # HONDA CR-V 2016 TOURING - "1632088eda5e6c4d|2018-06-07--08-03-18", # HONDA CIVIC HATCHBACK 2017 SEDAN/COUPE 2019 - "fbd011384db5e669|2018-07-26--20-51-48", # TOYOTA CAMRY HYBRID 2018 + "0607d2516fc2148f|2019-02-13--23-03-16", # CHRYSLER PACIFICA HYBRID 2019 + "3e9592a1c78a3d63|2018-02-08--20-28-24", # HONDA PILOT 2017 TOURING + "aa20e335f61ba898|2019-02-05--16-59-04", # BUICK REGAL ESSENCE 2018 + "1851183c395ef471|2018-05-31--18-07-21", # HONDA CR-V 2017 EX + "9d5fb4f0baa1b3e1|2019-01-14--17-45-59", # KIA SORENTO GT LINE 2018 + "b4c18bf13d5955da|2018-07-29--13-39-46", # TOYOTA C-HR HYBRID 2018 + "5a2cfe4bb362af9e|2018-02-02--23-41-07", # ACURA RDX 2018 ACURAWATCH PLUS + "362d23d4d5bea2fa|2018-08-10--13-31-40", # TOYOTA HIGHLANDER HYBRID 2018 + "aa20e335f61ba898|2018-12-17--21-10-37", # BUICK REGAL ESSENCE 2018 + "215cd70e9c349266|2018-11-25--22-22-12", # KIA STINGER GT2 2018 + "192a598e34926b1e|2019-04-04--13-27-39", # JEEP GRAND CHEROKEE 2019 + "34a84d2b765df688|2018-08-28--12-41-00", # HONDA PILOT 2019 ELITE + "b0c9d2329ad1606b|2019-01-06--10-11-23", # CHRYSLER PACIFICA HYBRID 2017 + "31390e3eb6f7c29a|2019-01-23--08-56-00", # KIA OPTIMA SX 2019 + "fd10b9a107bb2e49|2018-07-24--16-32-42", # TOYOTA C-HR 2018 + "9f7a7e50a51fb9db|2019-01-17--18-34-21", # JEEP GRAND CHEROKEE V6 2018 + "aadda448b49c99ad|2018-10-25--17-16-22", # CHEVROLET MALIBU PREMIER 2017 + "362d23d4d5bea2fa|2018-09-02--17-03-55", # TOYOTA HIGHLANDER HYBRID 2018 + "1582e1dc57175194|2018-08-15--07-46-07", # HONDA ACCORD 2018 LX 1.5T + "fd10b9a107bb2e49|2018-07-24--20-32-08", # TOYOTA C-HR 2018 + "265007255e794bce|2018-11-24--22-08-31", # CADILLAC ATS Premium Performance 2018 + "53ac3251e03f95d7|2019-01-10--13-43-32", # HYUNDAI ELANTRA LIMITED ULTIMATE 2017 + "21aa231dee2a68bd|2018-01-30--04-54-41", # HONDA ODYSSEY 2018 EX-L + "900ad17e536c3dc7|2018-04-12--22-02-36", # HONDA RIDGELINE 2017 BLACK EDITION + "975b26878285314d|2018-12-25--14-42-13", # CHRYSLER PACIFICA HYBRID 2018 + "8ae193ceb56a0efe|2018-06-18--20-07-32", # TOYOTA RAV4 HYBRID 2017 + "a893a80e5c5f72c8|2019-01-14--20-02-59", # HYUNDAI GENESIS 2018 + "49c73650e65ff465|2018-11-19--16-58-04", # HOLDEN ASTRA RS-V BK 2017 + "d2d8152227f7cb82|2018-07-25--13-40-56", # TOYOTA CAMRY 2018 + "07cb8a788c31f645|2018-06-17--18-50-29", # mock + "c9d60e5e02c04c5c|2018-01-08--16-01-49", # HONDA CR-V 2016 TOURING + "1632088eda5e6c4d|2018-06-07--08-03-18", # HONDA CIVIC HATCHBACK 2017 SEDAN/COUPE 2019 + "fbd011384db5e669|2018-07-26--20-51-48", # TOYOTA CAMRY HYBRID 2018 ] if __name__ == "__main__": @@ -458,96 +462,103 @@ if __name__ == "__main__": elif "UNLOGGER_PATH" not in os.environ: continue - for _ in range(3): - shutil.rmtree('/data/params') - manager.gctx = {} - params = Params() - params.manager_start() - if route in passive_routes: - params.put("Passive", "1") - else: - params.put("Passive", "0") - - print("testing ", route, " ", checks['carFingerprint']) - print("Preparing processes") - manager.prepare_managed_process("radard") - manager.prepare_managed_process("controlsd") - manager.prepare_managed_process("plannerd") - print("Starting processes") - manager.start_managed_process("radard") - manager.start_managed_process("controlsd") - manager.start_managed_process("plannerd") - time.sleep(2) - - # Start unlogger - print("Start unlogger") - if route in non_public_routes: - unlogger_cmd = [os.path.join(BASEDIR, os.environ['UNLOGGER_PATH']), '%s' % route, '--disable', 'frame,plan,pathPlan,liveLongitudinalMpc,radarState,controlsState,liveTracks,liveMpc,sendcan,carState,carControl,carEvents,carParams', '--no-interactive'] - else: - unlogger_cmd = [os.path.join(BASEDIR, 'tools/replay/unlogger.py'), '%s' % route, '/tmp', '--disable', 'frame,plan,pathPlan,liveLongitudinalMpc,radarState,controlsState,liveTracks,liveMpc,sendcan,carState,carControl,carEvents,carParams', '--no-interactive'] - unlogger = subprocess.Popen(unlogger_cmd, preexec_fn=os.setsid) + shutil.rmtree('/data/params') + manager.gctx = {} + params = Params() + params.manager_start() + params.put("OpenpilotEnabledToggle", "1") + params.put("CommunityFeaturesToggle", "1") - print("Check sockets") - controls_state_result = wait_for_socket('controlsState', timeout=30) - radarstate_result = wait_for_socket('radarState', timeout=30) - plan_result = wait_for_socket('plan', timeout=30) + if route in passive_routes: + params.put("Passive", "1") + else: + params.put("Passive", "0") - if route not in passive_routes: # TODO The passive routes have very flaky models - path_plan_result = wait_for_socket('pathPlan', timeout=30) - else: - path_plan_result = True - - carstate_result = wait_for_socket('carState', timeout=30) - - print("Check if everything is running") - running = manager.get_running() - controlsd_running = running['controlsd'].is_alive() - radard_running = running['radard'].is_alive() - plannerd_running = running['plannerd'].is_alive() - - manager.kill_managed_process("controlsd") - manager.kill_managed_process("radard") - manager.kill_managed_process("plannerd") - os.killpg(os.getpgid(unlogger.pid), signal.SIGTERM) - - sockets_ok = all([ - controls_state_result, radarstate_result, plan_result, path_plan_result, carstate_result, - controlsd_running, radard_running, plannerd_running - ]) - params_ok = True - failures = [] - - if not controlsd_running: - failures.append('controlsd') - if not radard_running: - failures.append('radard') - if not radarstate_result: - failures.append('radarState') - if not controls_state_result: - failures.append('controlsState') - if not plan_result: - failures.append('plan') - if not path_plan_result: - failures.append('pathPlan') - - try: - car_params = car.CarParams.from_bytes(params.get("CarParams")) - for k, v in checks.items(): - if not v == getattr(car_params, k): - params_ok = False - failures.append(k) - except: - params_ok = False - - if sockets_ok and params_ok: - print("Success") - results[route] = True, failures - break - else: - print("Failure") - results[route] = False, failures + print("testing ", route, " ", checks['carFingerprint']) + print("Preparing processes") + manager.prepare_managed_process("radard") + manager.prepare_managed_process("controlsd") + manager.prepare_managed_process("plannerd") + print("Starting processes") + manager.start_managed_process("radard") + manager.start_managed_process("controlsd") + manager.start_managed_process("plannerd") + time.sleep(2) + + # Start unlogger + print("Start unlogger") + if route in non_public_routes: + unlogger_cmd = [os.path.join(BASEDIR, os.environ['UNLOGGER_PATH']), '%s' % route, '--disable', 'frame,plan,pathPlan,liveLongitudinalMpc,radarState,controlsState,liveTracks,liveMpc,sendcan,carState,carControl,carEvents,carParams', '--no-interactive'] + else: + unlogger_cmd = [os.path.join(BASEDIR, 'tools/replay/unlogger.py'), '%s' % route, '/tmp', '--disable', 'frame,plan,pathPlan,liveLongitudinalMpc,radarState,controlsState,liveTracks,liveMpc,sendcan,carState,carControl,carEvents,carParams', '--no-interactive'] + unlogger = subprocess.Popen(unlogger_cmd, preexec_fn=os.setsid) + + print("Check sockets") + controls_state_result = wait_for_socket('controlsState', timeout=30) + + has_camera = checks.get('enableCamera', False) + if (route not in passive_routes) and (route not in forced_dashcam_routes) and has_camera: + controls_state_result = controls_state_result and wait_for_socket('sendcan', timeout=30) + + radarstate_result = wait_for_socket('radarState', timeout=30) + plan_result = wait_for_socket('plan', timeout=30) + + if route not in passive_routes: # TODO The passive routes have very flaky models + path_plan_result = wait_for_socket('pathPlan', timeout=30) + else: + path_plan_result = True + + carstate_result = wait_for_socket('carState', timeout=30) + + print("Check if everything is running") + running = manager.get_running() + controlsd_running = running['controlsd'].is_alive() + radard_running = running['radard'].is_alive() + plannerd_running = running['plannerd'].is_alive() + + manager.kill_managed_process("controlsd") + manager.kill_managed_process("radard") + manager.kill_managed_process("plannerd") + os.killpg(os.getpgid(unlogger.pid), signal.SIGTERM) + + sockets_ok = all([ + controls_state_result, radarstate_result, plan_result, path_plan_result, carstate_result, + controlsd_running, radard_running, plannerd_running + ]) + params_ok = True + failures = [] + + if not controlsd_running: + failures.append('controlsd') + if not radard_running: + failures.append('radard') + if not radarstate_result: + failures.append('radarState') + if not controls_state_result: + failures.append('controlsState') + if not plan_result: + failures.append('plan') + if not path_plan_result: + failures.append('pathPlan') + + try: + car_params = car.CarParams.from_bytes(params.get("CarParams")) + for k, v in checks.items(): + if not v == getattr(car_params, k): + params_ok = False + failures.append(k) + except Exception: + params_ok = False + + if sockets_ok and params_ok: + print("Success") + results[route] = True, failures + else: + print("Failure") + results[route] = False, failures + break - time.sleep(2) + time.sleep(2) for route in results: print(results[route]) diff --git a/selfdrive/test/test_openpilot.py b/selfdrive/test/test_openpilot.py index 68e35d90bc..27b964c47d 100644 --- a/selfdrive/test/test_openpilot.py +++ b/selfdrive/test/test_openpilot.py @@ -149,11 +149,11 @@ def test_athena(): assert False, f"Athena did not start within {timeout} seconds" time.sleep(0.5) - def athena_post(payload, max_retries=5): + def athena_post(payload, max_retries=5, wait=5): tries = 0 while 1: try: - return requests.post( + resp = requests.post( "https://athena.comma.ai/" + params.get("DongleId", encoding="utf-8"), headers={ "Authorization": "JWT " + os.getenv("COMMA_JWT"), @@ -162,29 +162,26 @@ def test_athena(): data=json.dumps(payload), timeout=30 ) + resp_json = resp.json() + if resp_json.get('error'): + raise Exception(resp_json['error']) + return resp_json except Exception as e: - print(e) - time.sleep(5.0) + time.sleep(wait) tries += 1 if tries == max_retries: raise + else: + print(f'athena_post failed {e}. retrying...') - def expect_athena_registers(timeout=60): - now = time.time() - while 1: - resp = athena_post({ - "method": "echo", - "params": ["hello"], - "id": 0, - "jsonrpc": "2.0" - }) - resp_json = resp.json() - if resp_json.get('result') == "hello": - break - elif time.time() - now > timeout: - assert False, f"Athena did not become available within {timeout} seconds." - else: - time.sleep(5.0) + def expect_athena_registers(): + resp = athena_post({ + "method": "echo", + "params": ["hello"], + "id": 0, + "jsonrpc": "2.0" + }, max_retries=12, wait=5) + assert resp.get('result') == "hello", f'Athena failed to register ({resp})' try: athenad_pid = expect_athena_starts() @@ -204,9 +201,8 @@ def test_athena(): "id": 0, "jsonrpc": "2.0" }) - resp_json = resp.json() - assert resp_json.get('result'), resp_json - assert 'sim_id' in resp_json['result'], resp_json['result'] + assert resp.get('result'), resp + assert 'sim_id' in resp['result'], resp['result'] print("ATHENA: takeSnapshot") resp = athena_post({ @@ -214,9 +210,8 @@ def test_athena(): "id": 0, "jsonrpc": "2.0" }) - resp_json = resp.json() - assert resp_json.get('result'), resp_json - assert resp_json['result']['jpegBack'], resp_json['result'] + assert resp.get('result'), resp + assert resp['result']['jpegBack'], resp['result'] @with_processes(["thermald"]) def test_athena_thermal(): @@ -227,9 +222,8 @@ def test_athena(): "id": 0, "jsonrpc": "2.0" }) - resp_json = resp.json() - assert resp_json.get('result'), resp_json - assert resp_json['result']['thermal'], resp_json['result'] + assert resp.get('result'), resp + assert resp['result']['thermal'], resp['result'] test_athena_thermal() finally: try: diff --git a/selfdrive/thermald.py b/selfdrive/thermald.py index d78e0011d1..aa4c47a6ee 100755 --- a/selfdrive/thermald.py +++ b/selfdrive/thermald.py @@ -6,6 +6,7 @@ import datetime import psutil from smbus2 import SMBus from cereal import log +from common.android import ANDROID from common.basedir import BASEDIR from common.params import Params from common.realtime import sec_since_boot, DT_TRML @@ -15,9 +16,9 @@ from selfdrive.version import terms_version, training_version from selfdrive.swaglog import cloudlog import cereal.messaging as messaging from selfdrive.loggerd.config import get_available_percent -from selfdrive.pandad import get_expected_version +from selfdrive.pandad import get_expected_signature -FW_VERSION = get_expected_version() +FW_SIGNATURE = get_expected_signature() ThermalStatus = log.ThermalData.ThermalStatus CURRENT_TAU = 15. # 15s time constant @@ -29,10 +30,13 @@ with open(BASEDIR + "/selfdrive/controls/lib/alerts_offroad.json") as json_file: OFFROAD_ALERTS = json.load(json_file) def read_tz(x, clip=True): - with open("/sys/devices/virtual/thermal/thermal_zone%d/temp" % x) as f: - ret = int(f.read()) - if clip: - ret = max(0, ret) + try: + with open("/sys/devices/virtual/thermal/thermal_zone%d/temp" % x) as f: + ret = int(f.read()) + if clip: + ret = max(0, ret) + except FileNotFoundError: + return 0 return ret @@ -156,7 +160,7 @@ def thermald_thread(): should_start_prev = False is_uno = (read_tz(29, clip=False) < -1000) - if is_uno: + if is_uno or not ANDROID: handle_fan = handle_fan_uno else: setup_eon_fan() @@ -178,20 +182,28 @@ def thermald_thread(): if health is not None: usb_power = health.health.usbPowerMode != log.HealthData.UsbPowerMode.client - msg.thermal.freeSpace = get_available_percent() / 100.0 # disk space + msg.thermal.freeSpace = get_available_percent(default=100.0) / 100.0 msg.thermal.memUsedPercent = int(round(psutil.virtual_memory().percent)) msg.thermal.cpuPerc = int(round(psutil.cpu_percent())) - with open("/sys/class/power_supply/battery/capacity") as f: - msg.thermal.batteryPercent = int(f.read()) - with open("/sys/class/power_supply/battery/status") as f: - msg.thermal.batteryStatus = f.read().strip() - with open("/sys/class/power_supply/battery/current_now") as f: - msg.thermal.batteryCurrent = int(f.read()) - with open("/sys/class/power_supply/battery/voltage_now") as f: - msg.thermal.batteryVoltage = int(f.read()) - with open("/sys/class/power_supply/usb/present") as f: - msg.thermal.usbOnline = bool(int(f.read())) + try: + with open("/sys/class/power_supply/battery/capacity") as f: + msg.thermal.batteryPercent = int(f.read()) + with open("/sys/class/power_supply/battery/status") as f: + msg.thermal.batteryStatus = f.read().strip() + with open("/sys/class/power_supply/battery/current_now") as f: + msg.thermal.batteryCurrent = int(f.read()) + with open("/sys/class/power_supply/battery/voltage_now") as f: + msg.thermal.batteryVoltage = int(f.read()) + with open("/sys/class/power_supply/usb/present") as f: + msg.thermal.usbOnline = bool(int(f.read())) + except FileNotFoundError: + pass + + # Fake battery levels on uno for frame + if is_uno: + msg.thermal.batteryPercent = 100 + msg.thermal.batteryStatus = "Charging" current_filter.update(msg.thermal.batteryCurrent / 1e6) @@ -268,8 +280,9 @@ def thermald_thread(): do_uninstall = params.get("DoUninstall") == b"1" accepted_terms = params.get("HasAcceptedTerms") == terms_version completed_training = params.get("CompletedTrainingVersion") == training_version - fw_version = params.get("PandaFirmware", encoding="utf8") - fw_version_match = fw_version is None or fw_version.startswith(FW_VERSION) # don't show alert is no panda is connected (None) + + panda_signature = params.get("PandaFirmware") + fw_version_match = (panda_signature is None) or (panda_signature == FW_SIGNATURE) # don't show alert is no panda is connected (None) should_start = ignition @@ -306,12 +319,18 @@ def thermald_thread(): params.delete("Offroad_TemperatureTooHigh") if should_start: + if not should_start_prev: + params.delete("IsOffroad") + off_ts = None if started_ts is None: started_ts = sec_since_boot() started_seen = True os.system('echo performance > /sys/class/devfreq/soc:qcom,cpubw/governor') else: + if should_start_prev or (count == 0): + params.put("IsOffroad", "1") + started_ts = None if off_ts is None: off_ts = sec_since_boot() diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index b3e96e79af..ad96cb0a4d 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -1,5 +1,15 @@ -Import('env', 'common', 'messaging', 'gpucommon', 'visionipc', 'cereal') +Import('env', 'arch', 'common', 'messaging', 'gpucommon', 'visionipc', 'cereal') -env.Program('_ui', ['ui.cc', 'slplay.c', '#phonelibs/nanovg/nanovg.c'], +src = ['ui.cc', 'paint.cc', '#phonelibs/nanovg/nanovg.c'] +libs = [common, 'zmq', 'czmq', 'capnp', 'capnp_c', 'm', cereal, 'json', messaging, 'OpenCL', gpucommon, visionipc] + +if arch == "aarch64": + src += ['sound.cc', 'slplay.c'] + libs += ['EGL', 'GLESv3', 'gnustl_shared', 'log', 'utils', 'gui', 'hardware', 'ui', 'CB', 'gsl', 'adreno_utils', 'OpenSLES', 'cutils', 'uuid'] +else: + src += ['linux.cc'] + libs += ['EGL', 'pthread', 'X11-xcb', 'xcb', 'X11', 'glfw'] + +env.Program('_ui', src, LINKFLAGS=['-Wl,-rpath=/system/lib64,-rpath=/system/comma/usr/lib'], - LIBS=[common, 'zmq', 'czmq', 'capnp', 'capnp_c', 'm', 'GLESv3', 'EGL', cereal, 'gnustl_shared', 'log', 'utils', 'gui', 'hardware', 'ui', 'json', messaging, 'CB', 'OpenCL', 'gsl', 'adreno_utils', 'OpenSLES', 'cutils', 'uuid', gpucommon, visionipc]) + LIBS=libs) diff --git a/selfdrive/ui/linux.cc b/selfdrive/ui/linux.cc new file mode 100644 index 0000000000..62531e356d --- /dev/null +++ b/selfdrive/ui/linux.cc @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include + +#include "ui.hpp" + +#define GLFW_INCLUDE_ES2 +#define GLFW_INCLUDE_GLEXT +#include + +typedef struct FramebufferState FramebufferState; +typedef struct TouchState TouchState; + +#define FALSE 0 +#define TRUE 1 + +#include +#include + +extern "C" { + +FramebufferState* framebuffer_init( + const char* name, int32_t layer, int alpha, + int *out_w, int *out_h) { + glfwInit(); + + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); + glfwWindowHint(GLFW_RESIZABLE, 0); + GLFWwindow* window; + window = glfwCreateWindow(1920, 1080, "ui", NULL, NULL); + if (!window) { + printf("glfwCreateWindow failed\n"); + } + + glfwMakeContextCurrent(window); + glfwSwapInterval(0); + + // clear screen + glClearColor(0.2f, 0.2f, 0.2f, 1.0f ); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + framebuffer_swap((FramebufferState*)window); + + if (out_w) *out_w = 1920; + if (out_h) *out_h = 1080; + + return (FramebufferState*)window; +} + +void framebuffer_set_power(FramebufferState *s, int mode) { +} + +void framebuffer_swap(FramebufferState *s) { + glfwSwapBuffers((GLFWwindow*)s); +} + +void touch_init(TouchState *s) { + printf("touch_init\n"); +} + +int touch_poll(TouchState *s, int* out_x, int* out_y, int timeout) { + return -1; +} + +int touch_read(TouchState *s, int* out_x, int* out_y) { + return -1; +} + +} + +#include "sound.hpp" + +void ui_sound_init() {} +void ui_sound_destroy() {} + +void set_volume(int volume) {} + +void play_alert_sound(AudibleAlert alert) {} +void stop_alert_sound(AudibleAlert alert) {} + +#include "common/visionimg.h" +#include + +GLuint visionimg_to_gl(const VisionImg *img, EGLImageKHR *pkhr, void **pph) { + unsigned int texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img->width, img->height, 0, GL_RGB, GL_UNSIGNED_BYTE, *pph); + glGenerateMipmap(GL_TEXTURE_2D); + *pkhr = (EGLImageKHR *)1; // not NULL + return texture; +} + +void visionimg_destroy_gl(EGLImageKHR khr, void *ph) { + // empty +} + diff --git a/selfdrive/ui/paint.cc b/selfdrive/ui/paint.cc new file mode 100644 index 0000000000..0728a5eab3 --- /dev/null +++ b/selfdrive/ui/paint.cc @@ -0,0 +1,1050 @@ +#include +#include "ui.hpp" + +#include "common/util.h" + +#define NANOVG_GLES3_IMPLEMENTATION + +#include "nanovg_gl.h" +#include "nanovg_gl_utils.h" + +extern "C"{ +#include "common/glutil.h" +} + +// TODO: this is also hardcoded in common/transformations/camera.py +const mat3 intrinsic_matrix = (mat3){{ + 910., 0., 582., + 0., 910., 437., + 0., 0., 1. +}}; + +const uint8_t alert_colors[][4] = { + [STATUS_STOPPED] = {0x07, 0x23, 0x39, 0xf1}, + [STATUS_DISENGAGED] = {0x17, 0x33, 0x49, 0xc8}, + [STATUS_ENGAGED] = {0x17, 0x86, 0x44, 0xf1}, + [STATUS_WARNING] = {0xDA, 0x6F, 0x25, 0xf1}, + [STATUS_ALERT] = {0xC9, 0x22, 0x31, 0xf1}, +}; + +const int alert_sizes[] = { + [ALERTSIZE_NONE] = 0, + [ALERTSIZE_SMALL] = 241, + [ALERTSIZE_MID] = 390, + [ALERTSIZE_FULL] = vwp_h, +}; + +// Projects a point in car to space to the corresponding point in full frame +// image space. +vec3 car_space_to_full_frame(const UIState *s, vec4 car_space_projective) { + const UIScene *scene = &s->scene; + + // We'll call the car space point p. + // First project into normalized image coordinates with the extrinsics matrix. + const vec4 Ep4 = matvecmul(scene->extrinsic_matrix, car_space_projective); + + // The last entry is zero because of how we store E (to use matvecmul). + const vec3 Ep = {{Ep4.v[0], Ep4.v[1], Ep4.v[2]}}; + const vec3 KEp = matvecmul3(intrinsic_matrix, Ep); + + // Project. + const vec3 p_image = {{KEp.v[0] / KEp.v[2], KEp.v[1] / KEp.v[2], 1.}}; + return p_image; +} + +// Calculate an interpolation between two numbers at a specific increment +static float lerp(float v0, float v1, float t) { + return (1 - t) * v0 + t * v1; +} + +static void draw_chevron(UIState *s, float x_in, float y_in, float sz, + NVGcolor fillColor, NVGcolor glowColor) { + const UIScene *scene = &s->scene; + + nvgSave(s->vg); + + nvgTranslate(s->vg, 240.0f, 0.0); + nvgTranslate(s->vg, -1440.0f / 2, -1080.0f / 2); + nvgScale(s->vg, 2.0, 2.0); + nvgScale(s->vg, 1440.0f / s->rgb_width, 1080.0f / s->rgb_height); + + const vec4 p_car_space = (vec4){{x_in, y_in, 0., 1.}}; + const vec3 p_full_frame = car_space_to_full_frame(s, p_car_space); + + sz *= 30; + sz /= (x_in / 3 + 30); + if (sz > 30) sz = 30; + if (sz < 15) sz = 15; + + float x = p_full_frame.v[0]; + float y = p_full_frame.v[1]; + + // glow + nvgBeginPath(s->vg); + float g_xo = sz/5; + float g_yo = sz/10; + if (x >= 0 && y >= 0.) { + nvgMoveTo(s->vg, x+(sz*1.35)+g_xo, y+sz+g_yo); + nvgLineTo(s->vg, x, y-g_xo); + nvgLineTo(s->vg, x-(sz*1.35)-g_xo, y+sz+g_yo); + nvgLineTo(s->vg, x+(sz*1.35)+g_xo, y+sz+g_yo); + nvgClosePath(s->vg); + } + nvgFillColor(s->vg, glowColor); + nvgFill(s->vg); + + // chevron + nvgBeginPath(s->vg); + if (x >= 0 && y >= 0.) { + nvgMoveTo(s->vg, x+(sz*1.25), y+sz); + nvgLineTo(s->vg, x, y); + nvgLineTo(s->vg, x-(sz*1.25), y+sz); + nvgLineTo(s->vg, x+(sz*1.25), y+sz); + nvgClosePath(s->vg); + } + nvgFillColor(s->vg, fillColor); + nvgFill(s->vg); + + nvgRestore(s->vg); +} + +static void ui_draw_lane_line(UIState *s, const model_path_vertices_data *pvd, NVGcolor color) { + const UIScene *scene = &s->scene; + + nvgSave(s->vg); + nvgTranslate(s->vg, 240.0f, 0.0); // rgb-box space + nvgTranslate(s->vg, -1440.0f / 2, -1080.0f / 2); // zoom 2x + nvgScale(s->vg, 2.0, 2.0); + nvgScale(s->vg, 1440.0f / s->rgb_width, 1080.0f / s->rgb_height); + nvgBeginPath(s->vg); + + bool started = false; + for (int i=0; icnt; i++) { + if (pvd->v[i].x < 0 || pvd->v[i].y < 0.) { + continue; + } + if (!started) { + nvgMoveTo(s->vg, pvd->v[i].x, pvd->v[i].y); + started = true; + } else { + nvgLineTo(s->vg, pvd->v[i].x, pvd->v[i].y); + } + } + + nvgClosePath(s->vg); + nvgFillColor(s->vg, color); + nvgFill(s->vg); + nvgRestore(s->vg); +} + +static void update_track_data(UIState *s, bool is_mpc, track_vertices_data *pvd) { + const UIScene *scene = &s->scene; + const PathData path = scene->model.path; + const float *mpc_x_coords = &scene->mpc_x[0]; + const float *mpc_y_coords = &scene->mpc_y[0]; + + bool started = false; + float off = is_mpc?0.3:0.5; + float lead_d = scene->lead_d_rel*2.; + float path_height = is_mpc?(lead_d>5.)?fmin(lead_d, 25.)-fmin(lead_d*0.35, 10.):20. + :(lead_d>0.)?fmin(lead_d, 50.)-fmin(lead_d*0.35, 10.):49.; + pvd->cnt = 0; + // left side up + for (int i=0; i<=path_height; i++) { + float px, py, mpx; + if (is_mpc) { + mpx = i==0?0.0:mpc_x_coords[i]; + px = lerp(mpx+1.0, mpx, i/100.0); + py = mpc_y_coords[i] - off; + } else { + px = lerp(i+1.0, i, i/100.0); + py = path.points[i] - off; + } + + vec4 p_car_space = (vec4){{px, py, 0., 1.}}; + vec3 p_full_frame = car_space_to_full_frame(s, p_car_space); + if (p_full_frame.v[0] < 0. || p_full_frame.v[1] < 0.) { + continue; + } + pvd->v[pvd->cnt].x = p_full_frame.v[0]; + pvd->v[pvd->cnt].y = p_full_frame.v[1]; + pvd->cnt += 1; + } + + // right side down + for (int i=path_height; i>=0; i--) { + float px, py, mpx; + if (is_mpc) { + mpx = i==0?0.0:mpc_x_coords[i]; + px = lerp(mpx+1.0, mpx, i/100.0); + py = mpc_y_coords[i] + off; + } else { + px = lerp(i+1.0, i, i/100.0); + py = path.points[i] + off; + } + + vec4 p_car_space = (vec4){{px, py, 0., 1.}}; + vec3 p_full_frame = car_space_to_full_frame(s, p_car_space); + pvd->v[pvd->cnt].x = p_full_frame.v[0]; + pvd->v[pvd->cnt].y = p_full_frame.v[1]; + pvd->cnt += 1; + } +} + +static void update_all_track_data(UIState *s) { + const UIScene *scene = &s->scene; + // Draw vision path + update_track_data(s, false, &s->track_vertices[0]); + + if (scene->engaged) { + // Draw MPC path when engaged + update_track_data(s, true, &s->track_vertices[1]); + } +} + + +static void ui_draw_track(UIState *s, bool is_mpc, track_vertices_data *pvd) { +const UIScene *scene = &s->scene; + const PathData path = scene->model.path; + const float *mpc_x_coords = &scene->mpc_x[0]; + const float *mpc_y_coords = &scene->mpc_y[0]; + + nvgSave(s->vg); + nvgTranslate(s->vg, 240.0f, 0.0); // rgb-box space + nvgTranslate(s->vg, -1440.0f / 2, -1080.0f / 2); // zoom 2x + nvgScale(s->vg, 2.0, 2.0); + nvgScale(s->vg, 1440.0f / s->rgb_width, 1080.0f / s->rgb_height); + nvgBeginPath(s->vg); + + bool started = false; + float off = is_mpc?0.3:0.5; + float lead_d = scene->lead_d_rel*2.; + float path_height = is_mpc?(lead_d>5.)?fmin(lead_d, 25.)-fmin(lead_d*0.35, 10.):20. + :(lead_d>0.)?fmin(lead_d, 50.)-fmin(lead_d*0.35, 10.):49.; + int vi = 0; + for(int i = 0;i < pvd->cnt;i++) { + if (pvd->v[i].x < 0 || pvd->v[i].y < 0) { + continue; + } + + if (!started) { + nvgMoveTo(s->vg, pvd->v[i].x, pvd->v[i].y); + started = true; + } else { + nvgLineTo(s->vg, pvd->v[i].x, pvd->v[i].y); + } + } + + nvgClosePath(s->vg); + + NVGpaint track_bg; + if (is_mpc) { + // Draw colored MPC track + const uint8_t *clr = bg_colors[s->status]; + track_bg = nvgLinearGradient(s->vg, vwp_w, vwp_h, vwp_w, vwp_h*.4, + nvgRGBA(clr[0], clr[1], clr[2], 255), nvgRGBA(clr[0], clr[1], clr[2], 255/2)); + } else { + // Draw white vision track + track_bg = nvgLinearGradient(s->vg, vwp_w, vwp_h, vwp_w, vwp_h*.4, + nvgRGBA(255, 255, 255, 255), nvgRGBA(255, 255, 255, 0)); + } + + nvgFillPaint(s->vg, track_bg); + nvgFill(s->vg); + nvgRestore(s->vg); +} + +static void draw_steering(UIState *s, float curvature) { + float points[50]; + for (int i = 0; i < 50; i++) { + float y_actual = i * tan(asin(clamp(i * curvature, -0.999, 0.999)) / 2.); + points[i] = y_actual; + } + + // ui_draw_lane_edge(s, points, 0.0, nvgRGBA(0, 0, 255, 128), 5); +} + +static void draw_frame(UIState *s) { + const UIScene *scene = &s->scene; + + float x1, x2, y1, y2; + if (s->scene.frontview) { + glBindVertexArray(s->frame_vao[1]); + } else { + glBindVertexArray(s->frame_vao[0]); + } + + mat4 *out_mat; + if (s->scene.frontview || s->scene.fullview) { + out_mat = &s->front_frame_mat; + } else { + out_mat = &s->rear_frame_mat; + } + glActiveTexture(GL_TEXTURE0); + if (s->scene.frontview && s->cur_vision_front_idx >= 0) { + glBindTexture(GL_TEXTURE_2D, s->frame_front_texs[s->cur_vision_front_idx]); + } else if (!scene->frontview && s->cur_vision_idx >= 0) { + glBindTexture(GL_TEXTURE_2D, s->frame_texs[s->cur_vision_idx]); + #ifndef QCOM + // TODO: a better way to do this? + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1164, 874, 0, GL_RGB, GL_UNSIGNED_BYTE, s->priv_hnds[s->cur_vision_idx]); + #endif + } + + glUseProgram(s->frame_program); + glUniform1i(s->frame_texture_loc, 0); + glUniformMatrix4fv(s->frame_transform_loc, 1, GL_TRUE, out_mat->v); + + assert(glGetError() == GL_NO_ERROR); + glEnableVertexAttribArray(0); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (const void*)0); + glDisableVertexAttribArray(0); + glBindVertexArray(0); +} + +static inline bool valid_frame_pt(UIState *s, float x, float y) { + return x >= 0 && x <= s->rgb_width && y >= 0 && y <= s->rgb_height; + +} +static void update_lane_line_data(UIState *s, const float *points, float off, bool is_ghost, model_path_vertices_data *pvd) { + pvd->cnt = 0; + for (int i = 0; i < MODEL_PATH_MAX_VERTICES_CNT / 2; i++) { + float px = (float)i; + float py = points[i] - off; + const vec4 p_car_space = (vec4){{px, py, 0., 1.}}; + const vec3 p_full_frame = car_space_to_full_frame(s, p_car_space); + if(!valid_frame_pt(s, p_full_frame.v[0], p_full_frame.v[1])) + continue; + pvd->v[pvd->cnt].x = p_full_frame.v[0]; + pvd->v[pvd->cnt].y = p_full_frame.v[1]; + pvd->cnt += 1; + } + for (int i = MODEL_PATH_MAX_VERTICES_CNT / 2; i > 0; i--) { + float px = (float)i; + float py = is_ghost?(points[i]-off):(points[i]+off); + const vec4 p_car_space = (vec4){{px, py, 0., 1.}}; + const vec3 p_full_frame = car_space_to_full_frame(s, p_car_space); + if(!valid_frame_pt(s, p_full_frame.v[0], p_full_frame.v[1])) + continue; + pvd->v[pvd->cnt].x = p_full_frame.v[0]; + pvd->v[pvd->cnt].y = p_full_frame.v[1]; + pvd->cnt += 1; + } +} + +static void update_all_lane_lines_data(UIState *s, const PathData path, model_path_vertices_data *pstart) { + update_lane_line_data(s, path.points, 0.025*path.prob, false, pstart); + float var = fmin(path.std, 0.7); + update_lane_line_data(s, path.points, -var, true, pstart + 1); + update_lane_line_data(s, path.points, var, true, pstart + 2); +} + +static void ui_draw_lane(UIState *s, const PathData *path, model_path_vertices_data *pstart, NVGcolor color) { + ui_draw_lane_line(s, pstart, color); + float var = fmin(path->std, 0.7); + color.a /= 4; + ui_draw_lane_line(s, pstart + 1, color); + ui_draw_lane_line(s, pstart + 2, color); +} + +static void ui_draw_vision_lanes(UIState *s) { + const UIScene *scene = &s->scene; + model_path_vertices_data *pvd = &s->model_path_vertices[0]; + if(s->model_changed) { + update_all_lane_lines_data(s, scene->model.left_lane, pvd); + update_all_lane_lines_data(s, scene->model.right_lane, pvd + MODEL_LANE_PATH_CNT); + s->model_changed = false; + } + // Draw left lane edge + ui_draw_lane( + s, &scene->model.left_lane, + pvd, + nvgRGBAf(1.0, 1.0, 1.0, scene->model.left_lane.prob)); + + // Draw right lane edge + ui_draw_lane( + s, &scene->model.right_lane, + pvd + MODEL_LANE_PATH_CNT, + nvgRGBAf(1.0, 1.0, 1.0, scene->model.right_lane.prob)); + + if(s->livempc_or_radarstate_changed) { + update_all_track_data(s); + s->livempc_or_radarstate_changed = false; + } + // Draw vision path + ui_draw_track(s, false, &s->track_vertices[0]); + if (scene->engaged) { + // Draw MPC path when engaged + ui_draw_track(s, true, &s->track_vertices[1]); + } +} + +// Draw all world space objects. +static void ui_draw_world(UIState *s) { + const UIScene *scene = &s->scene; + if (!scene->world_objects_visible) { + return; + } + + // Draw lane edges and vision/mpc tracks + ui_draw_vision_lanes(s); + + if (scene->lead_status) { + // Draw lead car indicator + float fillAlpha = 0; + float speedBuff = 10.; + float leadBuff = 40.; + if (scene->lead_d_rel < leadBuff) { + fillAlpha = 255*(1.0-(scene->lead_d_rel/leadBuff)); + if (scene->lead_v_rel < 0) { + fillAlpha += 255*(-1*(scene->lead_v_rel/speedBuff)); + } + fillAlpha = (int)(fmin(fillAlpha, 255)); + } + draw_chevron(s, scene->lead_d_rel+2.7, scene->lead_y_rel, 25, + nvgRGBA(201, 34, 49, fillAlpha), nvgRGBA(218, 202, 37, 255)); + } +} + +static void ui_draw_vision_maxspeed(UIState *s) { + /*if (!s->longitudinal_control){ + return; + }*/ + + const UIScene *scene = &s->scene; + int ui_viz_rx = scene->ui_viz_rx; + int ui_viz_rw = scene->ui_viz_rw; + + char maxspeed_str[32]; + float maxspeed = s->scene.v_cruise; + int maxspeed_calc = maxspeed * 0.6225 + 0.5; + float speedlimit = s->scene.speedlimit; + int speedlim_calc = speedlimit * 2.2369363 + 0.5; + int speed_lim_off = s->speed_lim_off * 2.2369363 + 0.5; + if (s->is_metric) { + maxspeed_calc = maxspeed + 0.5; + speedlim_calc = speedlimit * 3.6 + 0.5; + speed_lim_off = s->speed_lim_off * 3.6 + 0.5; + } + + bool is_cruise_set = (maxspeed != 0 && maxspeed != SET_SPEED_NA); + bool is_speedlim_valid = s->scene.speedlimit_valid; + bool is_set_over_limit = is_speedlim_valid && s->scene.engaged && + is_cruise_set && maxspeed_calc > (speedlim_calc + speed_lim_off); + + int viz_maxspeed_w = 184; + int viz_maxspeed_h = 202; + int viz_maxspeed_x = (ui_viz_rx + (bdr_s*2)); + int viz_maxspeed_y = (box_y + (bdr_s*1.5)); + int viz_maxspeed_xo = 180; + +#ifdef SHOW_SPEEDLIMIT + viz_maxspeed_w += viz_maxspeed_xo; + viz_maxspeed_x += viz_maxspeed_w - (viz_maxspeed_xo * 2); +#else + viz_maxspeed_xo = 0; +#endif + + // Draw Background + nvgBeginPath(s->vg); + nvgRoundedRect(s->vg, viz_maxspeed_x, viz_maxspeed_y, viz_maxspeed_w, viz_maxspeed_h, 30); + if (is_set_over_limit) { + nvgFillColor(s->vg, nvgRGBA(218, 111, 37, 180)); + } else { + nvgFillColor(s->vg, nvgRGBA(0, 0, 0, 100)); + } + nvgFill(s->vg); + + // Draw Border + nvgBeginPath(s->vg); + nvgRoundedRect(s->vg, viz_maxspeed_x, viz_maxspeed_y, viz_maxspeed_w, viz_maxspeed_h, 20); + if (is_set_over_limit) { + nvgStrokeColor(s->vg, nvgRGBA(218, 111, 37, 255)); + } else if (is_speedlim_valid && !s->is_ego_over_limit) { + nvgStrokeColor(s->vg, nvgRGBA(255, 255, 255, 255)); + } else if (is_speedlim_valid && s->is_ego_over_limit) { + nvgStrokeColor(s->vg, nvgRGBA(255, 255, 255, 20)); + } else { + nvgStrokeColor(s->vg, nvgRGBA(255, 255, 255, 100)); + } + nvgStrokeWidth(s->vg, 10); + nvgStroke(s->vg); + + // Draw "MAX" Text + nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); + nvgFontFace(s->vg, "sans-regular"); + nvgFontSize(s->vg, 26*2.5); + if (is_cruise_set) { + nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 200)); + } else { + nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 100)); + } + nvgText(s->vg, viz_maxspeed_x+(viz_maxspeed_xo/2)+(viz_maxspeed_w/2), 148, "MAX", NULL); + + // Draw Speed Text + nvgFontFace(s->vg, "sans-bold"); + nvgFontSize(s->vg, 48*2.5); + if (is_cruise_set) { + snprintf(maxspeed_str, sizeof(maxspeed_str), "%d", maxspeed_calc); + nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 255)); + nvgText(s->vg, viz_maxspeed_x+(viz_maxspeed_xo/2)+(viz_maxspeed_w/2), 242, maxspeed_str, NULL); + } else { + nvgFontFace(s->vg, "sans-semibold"); + nvgFontSize(s->vg, 42*2.5); + nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 100)); + nvgText(s->vg, viz_maxspeed_x+(viz_maxspeed_xo/2)+(viz_maxspeed_w/2), 242, "N/A", NULL); + } + +} + +static void ui_draw_vision_speedlimit(UIState *s) { + const UIScene *scene = &s->scene; + int ui_viz_rx = scene->ui_viz_rx; + int ui_viz_rw = scene->ui_viz_rw; + + char speedlim_str[32]; + float speedlimit = s->scene.speedlimit; + int speedlim_calc = speedlimit * 2.2369363 + 0.5; + if (s->is_metric) { + speedlim_calc = speedlimit * 3.6 + 0.5; + } + + bool is_speedlim_valid = s->scene.speedlimit_valid; + float hysteresis_offset = 0.5; + if (s->is_ego_over_limit) { + hysteresis_offset = 0.0; + } + s->is_ego_over_limit = is_speedlim_valid && s->scene.v_ego > (speedlimit + s->speed_lim_off + hysteresis_offset); + + int viz_speedlim_w = 180; + int viz_speedlim_h = 202; + int viz_speedlim_x = (ui_viz_rx + (bdr_s*2)); + int viz_speedlim_y = (box_y + (bdr_s*1.5)); + if (!is_speedlim_valid) { + viz_speedlim_w -= 5; + viz_speedlim_h -= 10; + viz_speedlim_x += 9; + viz_speedlim_y += 5; + } + int viz_speedlim_bdr = is_speedlim_valid ? 30 : 15; + + // Draw Background + nvgBeginPath(s->vg); + nvgRoundedRect(s->vg, viz_speedlim_x, viz_speedlim_y, viz_speedlim_w, viz_speedlim_h, viz_speedlim_bdr); + if (is_speedlim_valid && s->is_ego_over_limit) { + nvgFillColor(s->vg, nvgRGBA(218, 111, 37, 180)); + } else if (is_speedlim_valid) { + nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 255)); + } else { + nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 100)); + } + nvgFill(s->vg); + + // Draw Border + if (is_speedlim_valid) { + nvgStrokeWidth(s->vg, 10); + nvgStroke(s->vg); + nvgBeginPath(s->vg); + nvgRoundedRect(s->vg, viz_speedlim_x, viz_speedlim_y, viz_speedlim_w, viz_speedlim_h, 20); + if (s->is_ego_over_limit) { + nvgStrokeColor(s->vg, nvgRGBA(218, 111, 37, 255)); + } else if (is_speedlim_valid) { + nvgStrokeColor(s->vg, nvgRGBA(255, 255, 255, 255)); + } + } + + // Draw "Speed Limit" Text + nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); + nvgFontFace(s->vg, "sans-semibold"); + nvgFontSize(s->vg, 50); + nvgFillColor(s->vg, nvgRGBA(0, 0, 0, 255)); + if (is_speedlim_valid && s->is_ego_over_limit) { + nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 255)); + } + nvgText(s->vg, viz_speedlim_x+viz_speedlim_w/2 + (is_speedlim_valid ? 6 : 0), viz_speedlim_y + (is_speedlim_valid ? 50 : 45), "SMART", NULL); + nvgText(s->vg, viz_speedlim_x+viz_speedlim_w/2 + (is_speedlim_valid ? 6 : 0), viz_speedlim_y + (is_speedlim_valid ? 90 : 85), "SPEED", NULL); + + // Draw Speed Text + nvgFontFace(s->vg, "sans-bold"); + nvgFontSize(s->vg, 48*2.5); + if (s->is_ego_over_limit) { + nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 255)); + } else { + nvgFillColor(s->vg, nvgRGBA(0, 0, 0, 255)); + } + if (is_speedlim_valid) { + snprintf(speedlim_str, sizeof(speedlim_str), "%d", speedlim_calc); + nvgText(s->vg, viz_speedlim_x+viz_speedlim_w/2, viz_speedlim_y + (is_speedlim_valid ? 170 : 165), speedlim_str, NULL); + } else { + nvgFontFace(s->vg, "sans-semibold"); + nvgFontSize(s->vg, 42*2.5); + nvgText(s->vg, viz_speedlim_x+viz_speedlim_w/2, viz_speedlim_y + (is_speedlim_valid ? 170 : 165), "N/A", NULL); + } +} + +static void ui_draw_vision_speed(UIState *s) { + const UIScene *scene = &s->scene; + int ui_viz_rx = scene->ui_viz_rx; + int ui_viz_rw = scene->ui_viz_rw; + float speed = s->scene.v_ego; + + const int viz_speed_w = 280; + const int viz_speed_x = ui_viz_rx+((ui_viz_rw/2)-(viz_speed_w/2)); + char speed_str[32]; + + nvgBeginPath(s->vg); + nvgRect(s->vg, viz_speed_x, box_y, viz_speed_w, header_h); + nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); + + if (s->is_metric) { + snprintf(speed_str, sizeof(speed_str), "%d", (int)(speed * 3.6 + 0.5)); + } else { + snprintf(speed_str, sizeof(speed_str), "%d", (int)(speed * 2.2369363 + 0.5)); + } + nvgFontFace(s->vg, "sans-bold"); + nvgFontSize(s->vg, 96*2.5); + nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 255)); + nvgText(s->vg, viz_speed_x+viz_speed_w/2, 240, speed_str, NULL); + + nvgFontFace(s->vg, "sans-regular"); + nvgFontSize(s->vg, 36*2.5); + nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 200)); + + if (s->is_metric) { + nvgText(s->vg, viz_speed_x+viz_speed_w/2, 320, "kph", NULL); + } else { + nvgText(s->vg, viz_speed_x+viz_speed_w/2, 320, "mph", NULL); + } +} + +static void ui_draw_vision_event(UIState *s) { + const UIScene *scene = &s->scene; + const int ui_viz_rx = scene->ui_viz_rx; + const int ui_viz_rw = scene->ui_viz_rw; + const int viz_event_w = 220; + const int viz_event_x = ((ui_viz_rx + ui_viz_rw) - (viz_event_w + (bdr_s*2))); + const int viz_event_y = (box_y + (bdr_s*1.5)); + const int viz_event_h = (header_h - (bdr_s*1.5)); + if (s->scene.decel_for_model && s->scene.engaged) { + // draw winding road sign + const int img_turn_size = 160*1.5; + const int img_turn_x = viz_event_x-(img_turn_size/4); + const int img_turn_y = viz_event_y+bdr_s-25; + float img_turn_alpha = 1.0f; + nvgBeginPath(s->vg); + NVGpaint imgPaint = nvgImagePattern(s->vg, img_turn_x, img_turn_y, + img_turn_size, img_turn_size, 0, s->img_turn, img_turn_alpha); + nvgRect(s->vg, img_turn_x, img_turn_y, img_turn_size, img_turn_size); + nvgFillPaint(s->vg, imgPaint); + nvgFill(s->vg); + } else { + // draw steering wheel + const int bg_wheel_size = 96; + const int bg_wheel_x = viz_event_x + (viz_event_w-bg_wheel_size); + const int bg_wheel_y = viz_event_y + (bg_wheel_size/2); + const int img_wheel_size = bg_wheel_size*1.5; + const int img_wheel_x = bg_wheel_x-(img_wheel_size/2); + const int img_wheel_y = bg_wheel_y-25; + float img_wheel_alpha = 0.1f; + bool is_engaged = (s->status == STATUS_ENGAGED); + bool is_warning = (s->status == STATUS_WARNING); + bool is_engageable = scene->engageable; + if (is_engaged || is_warning || is_engageable) { + nvgBeginPath(s->vg); + nvgCircle(s->vg, bg_wheel_x, (bg_wheel_y + (bdr_s*1.5)), bg_wheel_size); + if (is_engaged) { + nvgFillColor(s->vg, nvgRGBA(23, 134, 68, 255)); + } else if (is_warning) { + nvgFillColor(s->vg, nvgRGBA(218, 111, 37, 255)); + } else if (is_engageable) { + nvgFillColor(s->vg, nvgRGBA(23, 51, 73, 255)); + } + nvgFill(s->vg); + img_wheel_alpha = 1.0f; + } + nvgBeginPath(s->vg); + NVGpaint imgPaint = nvgImagePattern(s->vg, img_wheel_x, img_wheel_y, + img_wheel_size, img_wheel_size, 0, s->img_wheel, img_wheel_alpha); + nvgRect(s->vg, img_wheel_x, img_wheel_y, img_wheel_size, img_wheel_size); + nvgFillPaint(s->vg, imgPaint); + nvgFill(s->vg); + } +} + +static void ui_draw_vision_map(UIState *s) { + const UIScene *scene = &s->scene; + const int map_size = 96; + const int map_x = (scene->ui_viz_rx + (map_size * 3) + (bdr_s * 3)); + const int map_y = (footer_y + ((footer_h - map_size) / 2)); + const int map_img_size = (map_size * 1.5); + const int map_img_x = (map_x - (map_img_size / 2)); + const int map_img_y = (map_y - (map_size / 4)); + + bool map_valid = s->scene.map_valid; + float map_img_alpha = map_valid ? 1.0f : 0.15f; + float map_bg_alpha = map_valid ? 0.3f : 0.1f; + NVGcolor map_bg = nvgRGBA(0, 0, 0, (255 * map_bg_alpha)); + NVGpaint map_img = nvgImagePattern(s->vg, map_img_x, map_img_y, + map_img_size, map_img_size, 0, s->img_map, map_img_alpha); + + nvgBeginPath(s->vg); + nvgCircle(s->vg, map_x, (map_y + (bdr_s * 1.5)), map_size); + nvgFillColor(s->vg, map_bg); + nvgFill(s->vg); + + nvgBeginPath(s->vg); + nvgRect(s->vg, map_img_x, map_img_y, map_img_size, map_img_size); + nvgFillPaint(s->vg, map_img); + nvgFill(s->vg); +} + +static void ui_draw_vision_face(UIState *s) { + const UIScene *scene = &s->scene; + const int face_size = 96; + const int face_x = (scene->ui_viz_rx + face_size + (bdr_s * 2)); + const int face_y = (footer_y + ((footer_h - face_size) / 2)); + const int face_img_size = (face_size * 1.5); + const int face_img_x = (face_x - (face_img_size / 2)); + const int face_img_y = (face_y - (face_size / 4)); + float face_img_alpha = scene->monitoring_active ? 1.0f : 0.15f; + float face_bg_alpha = scene->monitoring_active ? 0.3f : 0.1f; + NVGcolor face_bg = nvgRGBA(0, 0, 0, (255 * face_bg_alpha)); + NVGpaint face_img = nvgImagePattern(s->vg, face_img_x, face_img_y, + face_img_size, face_img_size, 0, s->img_face, face_img_alpha); + + nvgBeginPath(s->vg); + nvgCircle(s->vg, face_x, (face_y + (bdr_s * 1.5)), face_size); + nvgFillColor(s->vg, face_bg); + nvgFill(s->vg); + + nvgBeginPath(s->vg); + nvgRect(s->vg, face_img_x, face_img_y, face_img_size, face_img_size); + nvgFillPaint(s->vg, face_img); + nvgFill(s->vg); +} + +static void ui_draw_vision_header(UIState *s) { + const UIScene *scene = &s->scene; + int ui_viz_rx = scene->ui_viz_rx; + int ui_viz_rw = scene->ui_viz_rw; + + nvgBeginPath(s->vg); + NVGpaint gradient = nvgLinearGradient(s->vg, ui_viz_rx, + (box_y+(header_h-(header_h/2.5))), + ui_viz_rx, box_y+header_h, + nvgRGBAf(0,0,0,0.45), nvgRGBAf(0,0,0,0)); + nvgFillPaint(s->vg, gradient); + nvgRect(s->vg, ui_viz_rx, box_y, ui_viz_rw, header_h); + nvgFill(s->vg); + + ui_draw_vision_maxspeed(s); + +#ifdef SHOW_SPEEDLIMIT + ui_draw_vision_speedlimit(s); +#endif + ui_draw_vision_speed(s); + ui_draw_vision_event(s); +} + +static void ui_draw_vision_footer(UIState *s) { + const UIScene *scene = &s->scene; + int ui_viz_rx = scene->ui_viz_rx; + int ui_viz_rw = scene->ui_viz_rw; + + nvgBeginPath(s->vg); + nvgRect(s->vg, ui_viz_rx, footer_y, ui_viz_rw, footer_h); + + ui_draw_vision_face(s); + +#ifdef SHOW_SPEEDLIMIT + // ui_draw_vision_map(s); +#endif +} + +void ui_draw_vision_alert(UIState *s, int va_size, int va_color, + const char* va_text1, const char* va_text2) { + const UIScene *scene = &s->scene; + int ui_viz_rx = scene->ui_viz_rx; + int ui_viz_rw = scene->ui_viz_rw; + bool hasSidebar = !s->scene.uilayout_sidebarcollapsed; + bool mapEnabled = s->scene.uilayout_mapenabled; + bool longAlert1 = strlen(va_text1) > 15; + + const uint8_t *color = alert_colors[va_color]; + const int alr_s = alert_sizes[va_size]; + const int alr_x = ui_viz_rx-(mapEnabled?(hasSidebar?nav_w:(nav_ww)):0)-bdr_s; + const int alr_w = ui_viz_rw+(mapEnabled?(hasSidebar?nav_w:(nav_ww)):0)+(bdr_s*2); + const int alr_h = alr_s+(va_size==ALERTSIZE_NONE?0:bdr_s); + const int alr_y = vwp_h-alr_h; + + nvgBeginPath(s->vg); + nvgRect(s->vg, alr_x, alr_y, alr_w, alr_h); + nvgFillColor(s->vg, nvgRGBA(color[0],color[1],color[2],(color[3]*s->alert_blinking_alpha))); + nvgFill(s->vg); + + nvgBeginPath(s->vg); + NVGpaint gradient = nvgLinearGradient(s->vg, alr_x, alr_y, alr_x, alr_y+alr_h, + nvgRGBAf(0.0,0.0,0.0,0.05), nvgRGBAf(0.0,0.0,0.0,0.35)); + nvgFillPaint(s->vg, gradient); + nvgRect(s->vg, alr_x, alr_y, alr_w, alr_h); + nvgFill(s->vg); + + nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 255)); + nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); + + if (va_size == ALERTSIZE_SMALL) { + nvgFontFace(s->vg, "sans-semibold"); + nvgFontSize(s->vg, 40*2.5); + nvgText(s->vg, alr_x+alr_w/2, alr_y+alr_h/2+15, va_text1, NULL); + } else if (va_size== ALERTSIZE_MID) { + nvgFontFace(s->vg, "sans-bold"); + nvgFontSize(s->vg, 48*2.5); + nvgText(s->vg, alr_x+alr_w/2, alr_y+alr_h/2-45, va_text1, NULL); + nvgFontFace(s->vg, "sans-regular"); + nvgFontSize(s->vg, 36*2.5); + nvgText(s->vg, alr_x+alr_w/2, alr_y+alr_h/2+75, va_text2, NULL); + } else if (va_size== ALERTSIZE_FULL) { + nvgFontSize(s->vg, (longAlert1?72:96)*2.5); + nvgFontFace(s->vg, "sans-bold"); + nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); + nvgTextBox(s->vg, alr_x, alr_y+(longAlert1?360:420), alr_w-60, va_text1, NULL); + nvgFontSize(s->vg, 48*2.5); + nvgFontFace(s->vg, "sans-regular"); + nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BOTTOM); + nvgTextBox(s->vg, alr_x, alr_h-(longAlert1?300:360), alr_w-60, va_text2, NULL); + } +} + +static void ui_draw_vision(UIState *s) { + const UIScene *scene = &s->scene; + int ui_viz_rx = scene->ui_viz_rx; + int ui_viz_rw = scene->ui_viz_rw; + int ui_viz_ro = scene->ui_viz_ro; + + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + // Draw video frames + glEnable(GL_SCISSOR_TEST); + glViewport(ui_viz_rx+ui_viz_ro, s->fb_h-(box_y+box_h), viz_w, box_h); + glScissor(ui_viz_rx, s->fb_h-(box_y+box_h), ui_viz_rw, box_h); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + draw_frame(s); + glViewport(0, 0, s->fb_w, s->fb_h); + glDisable(GL_SCISSOR_TEST); + + glClear(GL_STENCIL_BUFFER_BIT); + + nvgBeginFrame(s->vg, s->fb_w, s->fb_h, 1.0f); + nvgSave(s->vg); + + // Draw augmented elements + const int inner_height = viz_w*9/16; + nvgScissor(s->vg, ui_viz_rx, box_y, ui_viz_rw, box_h); + nvgTranslate(s->vg, ui_viz_rx+ui_viz_ro, box_y + (box_h-inner_height)/2.0); + nvgScale(s->vg, (float)viz_w / s->fb_w, (float)inner_height / s->fb_h); + if (!scene->frontview && !scene->fullview) { + ui_draw_world(s); + } + + nvgRestore(s->vg); + + // Set Speed, Current Speed, Status/Events + ui_draw_vision_header(s); + + if (s->scene.alert_size != ALERTSIZE_NONE) { + // Controls Alerts + ui_draw_vision_alert(s, s->scene.alert_size, s->status, + s->scene.alert_text1, s->scene.alert_text2); + } else { + ui_draw_vision_footer(s); + } + + + nvgEndFrame(s->vg); + glDisable(GL_BLEND); +} + +static void ui_draw_blank(UIState *s) { + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); +} + +void ui_draw(UIState *s) { + if (s->vision_connected && s->active_app == cereal_UiLayoutState_App_home && s->status != STATUS_STOPPED) { + ui_draw_vision(s); + } else { + ui_draw_blank(s); + } + + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glClear(GL_STENCIL_BUFFER_BIT); + + nvgBeginFrame(s->vg, s->fb_w, s->fb_h, 1.0f); + + nvgEndFrame(s->vg); + glDisable(GL_BLEND); + } +} + +static const char frame_vertex_shader[] = + "attribute vec4 aPosition;\n" + "attribute vec4 aTexCoord;\n" + "uniform mat4 uTransform;\n" + "varying vec4 vTexCoord;\n" + "void main() {\n" + " gl_Position = uTransform * aPosition;\n" + " vTexCoord = aTexCoord;\n" + "}\n"; + +static const char frame_fragment_shader[] = + "precision mediump float;\n" + "uniform sampler2D uTexture;\n" + "varying vec4 vTexCoord;\n" + "void main() {\n" + " gl_FragColor = texture2D(uTexture, vTexCoord.xy);\n" + "}\n"; + +static const char line_vertex_shader[] = + "attribute vec4 aPosition;\n" + "attribute vec4 aColor;\n" + "uniform mat4 uTransform;\n" + "varying vec4 vColor;\n" + "void main() {\n" + " gl_Position = uTransform * aPosition;\n" + " vColor = aColor;\n" + "}\n"; + +static const char line_fragment_shader[] = + "precision mediump float;\n" + "uniform sampler2D uTexture;\n" + "varying vec4 vColor;\n" + "void main() {\n" + " gl_FragColor = vColor;\n" + "}\n"; + +static const mat4 device_transform = {{ + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, +}}; + +// frame from 4/3 to box size with a 2x zoom +static const mat4 frame_transform = {{ + 2*(4./3.)/((float)viz_w/box_h), 0.0, 0.0, 0.0, + 0.0, 2.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, +}}; + +// frame from 4/3 to 16/9 display +static const mat4 full_to_wide_frame_transform = {{ + .75, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, + 0.0, 0.0, 0.0, 1.0, +}}; + +void ui_nvg_init(UIState *s) { + // init drawing + s->vg = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES | NVG_DEBUG); + assert(s->vg); + + s->font_courbd = nvgCreateFont(s->vg, "courbd", "../assets/fonts/courbd.ttf"); + assert(s->font_courbd >= 0); + s->font_sans_regular = nvgCreateFont(s->vg, "sans-regular", "../assets/fonts/opensans_regular.ttf"); + assert(s->font_sans_regular >= 0); + s->font_sans_semibold = nvgCreateFont(s->vg, "sans-semibold", "../assets/fonts/opensans_semibold.ttf"); + assert(s->font_sans_semibold >= 0); + s->font_sans_bold = nvgCreateFont(s->vg, "sans-bold", "../assets/fonts/opensans_bold.ttf"); + assert(s->font_sans_bold >= 0); + + assert(s->img_wheel >= 0); + s->img_wheel = nvgCreateImage(s->vg, "../assets/img_chffr_wheel.png", 1); + + assert(s->img_turn >= 0); + s->img_turn = nvgCreateImage(s->vg, "../assets/img_trafficSign_turn.png", 1); + + assert(s->img_face >= 0); + s->img_face = nvgCreateImage(s->vg, "../assets/img_driver_face.png", 1); + + assert(s->img_map >= 0); + s->img_map = nvgCreateImage(s->vg, "../assets/img_map.png", 1); + + // init gl + s->frame_program = load_program(frame_vertex_shader, frame_fragment_shader); + assert(s->frame_program); + + s->frame_pos_loc = glGetAttribLocation(s->frame_program, "aPosition"); + s->frame_texcoord_loc = glGetAttribLocation(s->frame_program, "aTexCoord"); + + s->frame_texture_loc = glGetUniformLocation(s->frame_program, "uTexture"); + s->frame_transform_loc = glGetUniformLocation(s->frame_program, "uTransform"); + + s->line_program = load_program(line_vertex_shader, line_fragment_shader); + assert(s->line_program); + + s->line_pos_loc = glGetAttribLocation(s->line_program, "aPosition"); + s->line_color_loc = glGetAttribLocation(s->line_program, "aColor"); + s->line_transform_loc = glGetUniformLocation(s->line_program, "uTransform"); + + glViewport(0, 0, s->fb_w, s->fb_h); + + glDisable(GL_DEPTH_TEST); + + assert(glGetError() == GL_NO_ERROR); + + for(int i = 0; i < 2; i++) { + float x1, x2, y1, y2; + if (i == 1) { + // flip horizontally so it looks like a mirror + x1 = 0.0; + x2 = 1.0; + y1 = 1.0; + y2 = 0.0; + } else { + x1 = 1.0; + x2 = 0.0; + y1 = 1.0; + y2 = 0.0; + } + const uint8_t frame_indicies[] = {0, 1, 2, 0, 2, 3}; + const float frame_coords[4][4] = { + {-1.0, -1.0, x2, y1}, //bl + {-1.0, 1.0, x2, y2}, //tl + { 1.0, 1.0, x1, y2}, //tr + { 1.0, -1.0, x1, y1}, //br + }; + + glGenVertexArrays(1,&s->frame_vao[i]); + glBindVertexArray(s->frame_vao[i]); + glGenBuffers(1, &s->frame_vbo[i]); + glBindBuffer(GL_ARRAY_BUFFER, s->frame_vbo[i]); + glBufferData(GL_ARRAY_BUFFER, sizeof(frame_coords), frame_coords, GL_STATIC_DRAW); + glEnableVertexAttribArray(s->frame_pos_loc); + glVertexAttribPointer(s->frame_pos_loc, 2, GL_FLOAT, GL_FALSE, + sizeof(frame_coords[0]), (const void *)0); + glEnableVertexAttribArray(s->frame_texcoord_loc); + glVertexAttribPointer(s->frame_texcoord_loc, 2, GL_FLOAT, GL_FALSE, + sizeof(frame_coords[0]), (const void *)(sizeof(float) * 2)); + glGenBuffers(1, &s->frame_ibo[i]); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->frame_ibo[i]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(frame_indicies), frame_indicies, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER,0); + glBindVertexArray(0); + } + + s->front_frame_mat = matmul(device_transform, full_to_wide_frame_transform); + s->rear_frame_mat = matmul(device_transform, frame_transform); + + for(int i = 0;i < UI_BUF_COUNT; i++) { + s->khr[i] = NULL; + s->priv_hnds[i] = NULL; + s->khr_front[i] = NULL; + s->priv_hnds_front[i] = NULL; + } +} diff --git a/selfdrive/ui/sound.cc b/selfdrive/ui/sound.cc new file mode 100644 index 0000000000..701fa56b4c --- /dev/null +++ b/selfdrive/ui/sound.cc @@ -0,0 +1,85 @@ +#include +#include "sound.hpp" + +#include "common/swaglog.h" + +typedef struct { + AudibleAlert alert; + const char* uri; + bool loop; +} sound_file; + +extern "C"{ +#include "slplay.h" +} + +void set_volume(int volume) { + char volume_change_cmd[64]; + sprintf(volume_change_cmd, "service call audio 3 i32 3 i32 %d i32 1 &", volume); + + // 5 second timeout at 60fps + int volume_changed = system(volume_change_cmd); +} + + +sound_file sound_table[] = { + { cereal_CarControl_HUDControl_AudibleAlert_chimeDisengage, "../assets/sounds/disengaged.wav", false }, + { cereal_CarControl_HUDControl_AudibleAlert_chimeEngage, "../assets/sounds/engaged.wav", false }, + { cereal_CarControl_HUDControl_AudibleAlert_chimeWarning1, "../assets/sounds/warning_1.wav", false }, + { cereal_CarControl_HUDControl_AudibleAlert_chimeWarning2, "../assets/sounds/warning_2.wav", false }, + { cereal_CarControl_HUDControl_AudibleAlert_chimeWarningRepeat, "../assets/sounds/warning_repeat.wav", true }, + { cereal_CarControl_HUDControl_AudibleAlert_chimeError, "../assets/sounds/error.wav", false }, + { cereal_CarControl_HUDControl_AudibleAlert_chimePrompt, "../assets/sounds/error.wav", false }, + { cereal_CarControl_HUDControl_AudibleAlert_none, NULL, false }, +}; + +sound_file* get_sound_file(AudibleAlert alert) { + for (sound_file *s = sound_table; s->alert != cereal_CarControl_HUDControl_AudibleAlert_none; s++) { + if (s->alert == alert) { + return s; + } + } + + return NULL; +} + +void play_alert_sound(AudibleAlert alert) { + sound_file* sound = get_sound_file(alert); + char* error = NULL; + + slplay_play(sound->uri, sound->loop, &error); + if(error) { + LOGW("error playing sound: %s", error); + } +} + +void stop_alert_sound(AudibleAlert alert) { + sound_file* sound = get_sound_file(alert); + char* error = NULL; + + slplay_stop_uri(sound->uri, &error); + if(error) { + LOGW("error stopping sound: %s", error); + } +} + +void ui_sound_init() { + char *error = NULL; + slplay_setup(&error); + if (error) goto fail; + + for (sound_file *s = sound_table; s->alert != cereal_CarControl_HUDControl_AudibleAlert_none; s++) { + slplay_create_player_for_uri(s->uri, &error); + if (error) goto fail; + } + return; + +fail: + LOGW(error); + exit(1); +} + +void ui_sound_destroy() { + slplay_destroy(); +} + diff --git a/selfdrive/ui/sound.hpp b/selfdrive/ui/sound.hpp new file mode 100644 index 0000000000..cc44c1b4b3 --- /dev/null +++ b/selfdrive/ui/sound.hpp @@ -0,0 +1,17 @@ +#ifndef __SOUND_HPP +#define __SOUND_HPP + +#include "cereal/gen/c/log.capnp.h" + +typedef enum cereal_CarControl_HUDControl_AudibleAlert AudibleAlert; + +void ui_sound_init(); +void ui_sound_destroy(); + +void set_volume(int volume); + +void play_alert_sound(AudibleAlert alert); +void stop_alert_sound(AudibleAlert alert); + +#endif + diff --git a/selfdrive/ui/ui.cc b/selfdrive/ui/ui.cc index fb22ad790d..6a36f49198 100644 --- a/selfdrive/ui/ui.cc +++ b/selfdrive/ui/ui.cc @@ -6,289 +6,19 @@ #include #include -#include - -#include -#include - #include #include -#include "nanovg.h" -#define NANOVG_GLES3_IMPLEMENTATION -#include "nanovg_gl.h" -#include "nanovg_gl_utils.h" - +#include "common/util.h" #include "common/messaging.h" #include "common/timing.h" -#include "common/util.h" #include "common/swaglog.h" -#include "common/mat.h" - -extern "C"{ -#include "common/glutil.h" -} - #include "common/touch.h" -#include "common/framebuffer.h" -#include "common/visionipc.h" #include "common/visionimg.h" -#include "common/modeldata.h" #include "common/params.h" -#include "cereal/gen/c/log.capnp.h" - -extern "C"{ -#include "slplay.h" -} - -#include "messaging.hpp" - -#define STATUS_STOPPED 0 -#define STATUS_DISENGAGED 1 -#define STATUS_ENGAGED 2 -#define STATUS_WARNING 3 -#define STATUS_ALERT 4 - -#define ALERTSIZE_NONE 0 -#define ALERTSIZE_SMALL 1 -#define ALERTSIZE_MID 2 -#define ALERTSIZE_FULL 3 - -//#define UI_60FPS - -#define UI_BUF_COUNT 4 -//#define SHOW_SPEEDLIMIT 1 -//#define DEBUG_TURN - -const int vwp_w = 1920; -const int vwp_h = 1080; -const int nav_w = 640; -const int nav_ww= 760; -const int sbr_w = 300; -const int bdr_s = 30; -const int box_x = sbr_w+bdr_s; -const int box_y = bdr_s; -const int box_w = vwp_w-sbr_w-(bdr_s*2); -const int box_h = vwp_h-(bdr_s*2); -const int viz_w = vwp_w-(bdr_s*2); -const int header_h = 420; -const int footer_h = 280; -const int footer_y = vwp_h-bdr_s-footer_h; - -const int UI_FREQ = 30; // Hz - -const int MODEL_PATH_MAX_VERTICES_CNT = 98; -const int MODEL_LANE_PATH_CNT = 3; -const int TRACK_POINTS_MAX_CNT = 50 * 2; - -const uint8_t bg_colors[][4] = { - [STATUS_STOPPED] = {0x07, 0x23, 0x39, 0xff}, - [STATUS_DISENGAGED] = {0x17, 0x33, 0x49, 0xff}, - [STATUS_ENGAGED] = {0x17, 0x86, 0x44, 0xff}, - [STATUS_WARNING] = {0xDA, 0x6F, 0x25, 0xff}, - [STATUS_ALERT] = {0xC9, 0x22, 0x31, 0xff}, -}; - -const uint8_t alert_colors[][4] = { - [STATUS_STOPPED] = {0x07, 0x23, 0x39, 0xf1}, - [STATUS_DISENGAGED] = {0x17, 0x33, 0x49, 0xc8}, - [STATUS_ENGAGED] = {0x17, 0x86, 0x44, 0xf1}, - [STATUS_WARNING] = {0xDA, 0x6F, 0x25, 0xf1}, - [STATUS_ALERT] = {0xC9, 0x22, 0x31, 0xf1}, -}; - -const int alert_sizes[] = { - [ALERTSIZE_NONE] = 0, - [ALERTSIZE_SMALL] = 241, - [ALERTSIZE_MID] = 390, - [ALERTSIZE_FULL] = vwp_h, -}; - -const int SET_SPEED_NA = 255; - -// TODO: this is also hardcoded in common/transformations/camera.py -const mat3 intrinsic_matrix = (mat3){{ - 910., 0., 582., - 0., 910., 437., - 0., 0., 1. -}}; - -typedef enum cereal_CarControl_HUDControl_AudibleAlert AudibleAlert; - -typedef struct UIScene { - int frontview; - int fullview; - - int transformed_width, transformed_height; - - ModelData model; - - float mpc_x[50]; - float mpc_y[50]; - - bool world_objects_visible; - mat4 extrinsic_matrix; // Last row is 0 so we can use mat4. - - float v_cruise; - uint64_t v_cruise_update_ts; - float v_ego; - bool decel_for_model; - - float speedlimit; - bool speedlimit_valid; - bool map_valid; - - float curvature; - int engaged; - bool engageable; - bool monitoring_active; - - bool uilayout_sidebarcollapsed; - bool uilayout_mapenabled; - // responsive layout - int ui_viz_rx; - int ui_viz_rw; - int ui_viz_ro; - - int lead_status; - float lead_d_rel, lead_y_rel, lead_v_rel; - - int front_box_x, front_box_y, front_box_width, front_box_height; - - uint64_t alert_ts; - char alert_text1[1024]; - char alert_text2[1024]; - uint8_t alert_size; - float alert_blinkingrate; - - float awareness_status; - - // Used to show gps planner status - bool gps_planner_active; -} UIScene; - -typedef struct { - float x, y; -}vertex_data; - -typedef struct { - vertex_data v[MODEL_PATH_MAX_VERTICES_CNT]; - int cnt; -} model_path_vertices_data; - -typedef struct { - vertex_data v[TRACK_POINTS_MAX_CNT]; - int cnt; -} track_vertices_data; - - -typedef struct UIState { - pthread_mutex_t lock; - pthread_cond_t bg_cond; - - FramebufferState *fb; - int fb_w, fb_h; - EGLDisplay display; - EGLSurface surface; - - NVGcontext *vg; - - int font_courbd; - int font_sans_regular; - int font_sans_semibold; - int font_sans_bold; - int img_wheel; - int img_turn; - int img_face; - int img_map; - - // Sockets - Context *ctx; - SubSocket *model_sock; - SubSocket *controlsstate_sock; - SubSocket *livecalibration_sock; - SubSocket *radarstate_sock; - SubSocket *map_data_sock; - SubSocket *uilayout_sock; - Poller * poller; - - int active_app; - - // vision state - bool vision_connected; - bool vision_connect_firstrun; - int ipc_fd; - - VIPCBuf bufs[UI_BUF_COUNT]; - VIPCBuf front_bufs[UI_BUF_COUNT]; - int cur_vision_idx; - int cur_vision_front_idx; - - GLuint frame_program; - GLuint frame_texs[UI_BUF_COUNT]; - EGLImageKHR khr[UI_BUF_COUNT]; - void *priv_hnds[UI_BUF_COUNT]; - GLuint frame_front_texs[UI_BUF_COUNT]; - EGLImageKHR khr_front[UI_BUF_COUNT]; - void *priv_hnds_front[UI_BUF_COUNT]; - - GLint frame_pos_loc, frame_texcoord_loc; - GLint frame_texture_loc, frame_transform_loc; - - GLuint line_program; - GLint line_pos_loc, line_color_loc; - GLint line_transform_loc; - - int rgb_width, rgb_height, rgb_stride; - size_t rgb_buf_len; - mat4 rgb_transform; - - int rgb_front_width, rgb_front_height, rgb_front_stride; - size_t rgb_front_buf_len; - - UIScene scene; - - bool awake; - int awake_timeout; - - int volume_timeout; - int controls_timeout; - int alert_sound_timeout; - int speed_lim_off_timeout; - int is_metric_timeout; - int longitudinal_control_timeout; - int limit_set_speed_timeout; - - bool controls_seen; - - int status; - bool is_metric; - bool longitudinal_control; - bool limit_set_speed; - float speed_lim_off; - bool is_ego_over_limit; - char alert_type[64]; - AudibleAlert alert_sound; - int alert_size; - float alert_blinking_alpha; - bool alert_blinked; - - float light_sensor; - - int touch_fd; - - // Hints for re-calculations and redrawing - bool model_changed; - bool livempc_or_radarstate_changed; - - GLuint frame_vao[2], frame_vbo[2], frame_ibo[2]; - mat4 rear_frame_mat, front_frame_mat; - - model_path_vertices_data model_path_vertices[MODEL_LANE_PATH_CNT * 2]; - - track_vertices_data track_vertices[2]; -} UIState; +#include "ui.hpp" +#include "sound.hpp" static int last_brightness = -1; static void set_brightness(UIState *s, int brightness) { @@ -303,6 +33,7 @@ static void set_brightness(UIState *s, int brightness) { } static void set_awake(UIState *s, bool awake) { +#ifdef QCOM if (awake) { // 30 second timeout at 30 fps s->awake_timeout = 30*30; @@ -322,15 +53,10 @@ static void set_awake(UIState *s, bool awake) { framebuffer_set_power(s->fb, HWC_POWER_MODE_OFF); } } -} - -static void set_volume(UIState *s, int volume) { - char volume_change_cmd[64]; - sprintf(volume_change_cmd, "service call audio 3 i32 3 i32 %d i32 1 &", volume); - - // 5 second timeout at 60fps - s->volume_timeout = 5 * UI_FREQ; - int volume_changed = system(volume_change_cmd); +#else + // computer UI doesn't sleep + s->awake = true; +#endif } volatile sig_atomic_t do_exit = 0; @@ -374,123 +100,6 @@ static void read_param_float_timeout(float* param, const char* param_name, int* } } -static const char frame_vertex_shader[] = - "attribute vec4 aPosition;\n" - "attribute vec4 aTexCoord;\n" - "uniform mat4 uTransform;\n" - "varying vec4 vTexCoord;\n" - "void main() {\n" - " gl_Position = uTransform * aPosition;\n" - " vTexCoord = aTexCoord;\n" - "}\n"; - -static const char frame_fragment_shader[] = - "precision mediump float;\n" - "uniform sampler2D uTexture;\n" - "varying vec4 vTexCoord;\n" - "void main() {\n" - " gl_FragColor = texture2D(uTexture, vTexCoord.xy);\n" - "}\n"; - -static const char line_vertex_shader[] = - "attribute vec4 aPosition;\n" - "attribute vec4 aColor;\n" - "uniform mat4 uTransform;\n" - "varying vec4 vColor;\n" - "void main() {\n" - " gl_Position = uTransform * aPosition;\n" - " vColor = aColor;\n" - "}\n"; - -static const char line_fragment_shader[] = - "precision mediump float;\n" - "uniform sampler2D uTexture;\n" - "varying vec4 vColor;\n" - "void main() {\n" - " gl_FragColor = vColor;\n" - "}\n"; - - -static const mat4 device_transform = {{ - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, -}}; - -// frame from 4/3 to box size with a 2x zoom -static const mat4 frame_transform = {{ - 2*(4./3.)/((float)viz_w/box_h), 0.0, 0.0, 0.0, - 0.0, 2.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, -}}; - -// frame from 4/3 to 16/9 display -static const mat4 full_to_wide_frame_transform = {{ - .75, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0, -}}; - -typedef struct { - AudibleAlert alert; - const char* uri; - bool loop; -} sound_file; - -sound_file sound_table[] = { - { cereal_CarControl_HUDControl_AudibleAlert_chimeDisengage, "../assets/sounds/disengaged.wav", false }, - { cereal_CarControl_HUDControl_AudibleAlert_chimeEngage, "../assets/sounds/engaged.wav", false }, - { cereal_CarControl_HUDControl_AudibleAlert_chimeWarning1, "../assets/sounds/warning_1.wav", false }, - { cereal_CarControl_HUDControl_AudibleAlert_chimeWarning2, "../assets/sounds/warning_2.wav", false }, - { cereal_CarControl_HUDControl_AudibleAlert_chimeWarningRepeat, "../assets/sounds/warning_repeat.wav", true }, - { cereal_CarControl_HUDControl_AudibleAlert_chimeError, "../assets/sounds/error.wav", false }, - { cereal_CarControl_HUDControl_AudibleAlert_chimePrompt, "../assets/sounds/error.wav", false }, - { cereal_CarControl_HUDControl_AudibleAlert_none, NULL, false }, -}; - -sound_file* get_sound_file(AudibleAlert alert) { - for (sound_file *s = sound_table; s->alert != cereal_CarControl_HUDControl_AudibleAlert_none; s++) { - if (s->alert == alert) { - return s; - } - } - - return NULL; -} - -void play_alert_sound(AudibleAlert alert) { - sound_file* sound = get_sound_file(alert); - char* error = NULL; - - slplay_play(sound->uri, sound->loop, &error); - if(error) { - LOGW("error playing sound: %s", error); - } -} - -void stop_alert_sound(AudibleAlert alert) { - sound_file* sound = get_sound_file(alert); - char* error = NULL; - - slplay_stop_uri(sound->uri, &error); - if(error) { - LOGW("error stopping sound: %s", error); - } -} - -void ui_sound_init(char **error) { - slplay_setup(error); - if (*error) return; - - for (sound_file *s = sound_table; s->alert != cereal_CarControl_HUDControl_AudibleAlert_none; s++) { - slplay_create_player_for_uri(s->uri, error); - if (*error) return; - } -} - static void ui_init(UIState *s) { memset(s, 0, sizeof(UIState)); @@ -527,112 +136,15 @@ static void ui_init(UIState *s) { s->ipc_fd = -1; // init display - s->fb = framebuffer_init("ui", 0x00010000, true, - &s->display, &s->surface, &s->fb_w, &s->fb_h); + s->fb = framebuffer_init("ui", 0x00010000, true, &s->fb_w, &s->fb_h); assert(s->fb); set_awake(s, true); - // init drawing - s->vg = nvgCreateGLES3(NVG_ANTIALIAS | NVG_STENCIL_STROKES | NVG_DEBUG); - assert(s->vg); - - s->font_courbd = nvgCreateFont(s->vg, "courbd", "../assets/fonts/courbd.ttf"); - assert(s->font_courbd >= 0); - s->font_sans_regular = nvgCreateFont(s->vg, "sans-regular", "../assets/fonts/opensans_regular.ttf"); - assert(s->font_sans_regular >= 0); - s->font_sans_semibold = nvgCreateFont(s->vg, "sans-semibold", "../assets/fonts/opensans_semibold.ttf"); - assert(s->font_sans_semibold >= 0); - s->font_sans_bold = nvgCreateFont(s->vg, "sans-bold", "../assets/fonts/opensans_bold.ttf"); - assert(s->font_sans_bold >= 0); - - assert(s->img_wheel >= 0); - s->img_wheel = nvgCreateImage(s->vg, "../assets/img_chffr_wheel.png", 1); - - assert(s->img_turn >= 0); - s->img_turn = nvgCreateImage(s->vg, "../assets/img_trafficSign_turn.png", 1); - - assert(s->img_face >= 0); - s->img_face = nvgCreateImage(s->vg, "../assets/img_driver_face.png", 1); - - assert(s->img_map >= 0); - s->img_map = nvgCreateImage(s->vg, "../assets/img_map.png", 1); - - // init gl - s->frame_program = load_program(frame_vertex_shader, frame_fragment_shader); - assert(s->frame_program); - - s->frame_pos_loc = glGetAttribLocation(s->frame_program, "aPosition"); - s->frame_texcoord_loc = glGetAttribLocation(s->frame_program, "aTexCoord"); - - s->frame_texture_loc = glGetUniformLocation(s->frame_program, "uTexture"); - s->frame_transform_loc = glGetUniformLocation(s->frame_program, "uTransform"); - - s->line_program = load_program(line_vertex_shader, line_fragment_shader); - assert(s->line_program); - - s->line_pos_loc = glGetAttribLocation(s->line_program, "aPosition"); - s->line_color_loc = glGetAttribLocation(s->line_program, "aColor"); - s->line_transform_loc = glGetUniformLocation(s->line_program, "uTransform"); - - glViewport(0, 0, s->fb_w, s->fb_h); - - glDisable(GL_DEPTH_TEST); - - assert(glGetError() == GL_NO_ERROR); - - for(int i = 0; i < 2; i++) { - float x1, x2, y1, y2; - if (i == 1) { - // flip horizontally so it looks like a mirror - x1 = 0.0; - x2 = 1.0; - y1 = 1.0; - y2 = 0.0; - } else { - x1 = 1.0; - x2 = 0.0; - y1 = 1.0; - y2 = 0.0; - } - const uint8_t frame_indicies[] = {0, 1, 2, 0, 2, 3}; - const float frame_coords[4][4] = { - {-1.0, -1.0, x2, y1}, //bl - {-1.0, 1.0, x2, y2}, //tl - { 1.0, 1.0, x1, y2}, //tr - { 1.0, -1.0, x1, y1}, //br - }; - - glGenVertexArrays(1,&s->frame_vao[i]); - glBindVertexArray(s->frame_vao[i]); - glGenBuffers(1, &s->frame_vbo[i]); - glBindBuffer(GL_ARRAY_BUFFER, s->frame_vbo[i]); - glBufferData(GL_ARRAY_BUFFER, sizeof(frame_coords), frame_coords, GL_STATIC_DRAW); - glEnableVertexAttribArray(s->frame_pos_loc); - glVertexAttribPointer(s->frame_pos_loc, 2, GL_FLOAT, GL_FALSE, - sizeof(frame_coords[0]), (const void *)0); - glEnableVertexAttribArray(s->frame_texcoord_loc); - glVertexAttribPointer(s->frame_texcoord_loc, 2, GL_FLOAT, GL_FALSE, - sizeof(frame_coords[0]), (const void *)(sizeof(float) * 2)); - glGenBuffers(1, &s->frame_ibo[i]); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->frame_ibo[i]); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(frame_indicies), frame_indicies, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER,0); - glBindVertexArray(0); - } - s->model_changed = false; s->livempc_or_radarstate_changed = false; - s->front_frame_mat = matmul(device_transform, full_to_wide_frame_transform); - s->rear_frame_mat = matmul(device_transform, frame_transform); - - for(int i = 0;i < UI_BUF_COUNT; i++) { - s->khr[i] = NULL; - s->priv_hnds[i] = NULL; - s->khr_front[i] = NULL; - s->priv_hnds_front[i] = NULL; - } + ui_nvg_init(s); } static void ui_init_vision(UIState *s, const VisionStreamBufs back_bufs, @@ -691,858 +203,6 @@ static void ui_init_vision(UIState *s, const VisionStreamBufs back_bufs, s->limit_set_speed_timeout = UI_FREQ; } -// Projects a point in car to space to the corresponding point in full frame -// image space. -vec3 car_space_to_full_frame(const UIState *s, vec4 car_space_projective) { - const UIScene *scene = &s->scene; - - // We'll call the car space point p. - // First project into normalized image coordinates with the extrinsics matrix. - const vec4 Ep4 = matvecmul(scene->extrinsic_matrix, car_space_projective); - - // The last entry is zero because of how we store E (to use matvecmul). - const vec3 Ep = {{Ep4.v[0], Ep4.v[1], Ep4.v[2]}}; - const vec3 KEp = matvecmul3(intrinsic_matrix, Ep); - - // Project. - const vec3 p_image = {{KEp.v[0] / KEp.v[2], KEp.v[1] / KEp.v[2], 1.}}; - return p_image; -} - -// Calculate an interpolation between two numbers at a specific increment -static float lerp(float v0, float v1, float t) { - return (1 - t) * v0 + t * v1; -} - -static void draw_chevron(UIState *s, float x_in, float y_in, float sz, - NVGcolor fillColor, NVGcolor glowColor) { - const UIScene *scene = &s->scene; - - nvgSave(s->vg); - - nvgTranslate(s->vg, 240.0f, 0.0); - nvgTranslate(s->vg, -1440.0f / 2, -1080.0f / 2); - nvgScale(s->vg, 2.0, 2.0); - nvgScale(s->vg, 1440.0f / s->rgb_width, 1080.0f / s->rgb_height); - - const vec4 p_car_space = (vec4){{x_in, y_in, 0., 1.}}; - const vec3 p_full_frame = car_space_to_full_frame(s, p_car_space); - - sz *= 30; - sz /= (x_in / 3 + 30); - if (sz > 30) sz = 30; - if (sz < 15) sz = 15; - - float x = p_full_frame.v[0]; - float y = p_full_frame.v[1]; - - // glow - nvgBeginPath(s->vg); - float g_xo = sz/5; - float g_yo = sz/10; - if (x >= 0 && y >= 0.) { - nvgMoveTo(s->vg, x+(sz*1.35)+g_xo, y+sz+g_yo); - nvgLineTo(s->vg, x, y-g_xo); - nvgLineTo(s->vg, x-(sz*1.35)-g_xo, y+sz+g_yo); - nvgLineTo(s->vg, x+(sz*1.35)+g_xo, y+sz+g_yo); - nvgClosePath(s->vg); - } - nvgFillColor(s->vg, glowColor); - nvgFill(s->vg); - - // chevron - nvgBeginPath(s->vg); - if (x >= 0 && y >= 0.) { - nvgMoveTo(s->vg, x+(sz*1.25), y+sz); - nvgLineTo(s->vg, x, y); - nvgLineTo(s->vg, x-(sz*1.25), y+sz); - nvgLineTo(s->vg, x+(sz*1.25), y+sz); - nvgClosePath(s->vg); - } - nvgFillColor(s->vg, fillColor); - nvgFill(s->vg); - - nvgRestore(s->vg); -} - -static void ui_draw_lane_line(UIState *s, const model_path_vertices_data *pvd, NVGcolor color) { - const UIScene *scene = &s->scene; - - nvgSave(s->vg); - nvgTranslate(s->vg, 240.0f, 0.0); // rgb-box space - nvgTranslate(s->vg, -1440.0f / 2, -1080.0f / 2); // zoom 2x - nvgScale(s->vg, 2.0, 2.0); - nvgScale(s->vg, 1440.0f / s->rgb_width, 1080.0f / s->rgb_height); - nvgBeginPath(s->vg); - - bool started = false; - for (int i=0; icnt; i++) { - if (pvd->v[i].x < 0 || pvd->v[i].y < 0.) { - continue; - } - if (!started) { - nvgMoveTo(s->vg, pvd->v[i].x, pvd->v[i].y); - started = true; - } else { - nvgLineTo(s->vg, pvd->v[i].x, pvd->v[i].y); - } - } - - nvgClosePath(s->vg); - nvgFillColor(s->vg, color); - nvgFill(s->vg); - nvgRestore(s->vg); -} - -static void update_track_data(UIState *s, bool is_mpc, track_vertices_data *pvd) { - const UIScene *scene = &s->scene; - const PathData path = scene->model.path; - const float *mpc_x_coords = &scene->mpc_x[0]; - const float *mpc_y_coords = &scene->mpc_y[0]; - - bool started = false; - float off = is_mpc?0.3:0.5; - float lead_d = scene->lead_d_rel*2.; - float path_height = is_mpc?(lead_d>5.)?fmin(lead_d, 25.)-fmin(lead_d*0.35, 10.):20. - :(lead_d>0.)?fmin(lead_d, 50.)-fmin(lead_d*0.35, 10.):49.; - pvd->cnt = 0; - // left side up - for (int i=0; i<=path_height; i++) { - float px, py, mpx; - if (is_mpc) { - mpx = i==0?0.0:mpc_x_coords[i]; - px = lerp(mpx+1.0, mpx, i/100.0); - py = mpc_y_coords[i] - off; - } else { - px = lerp(i+1.0, i, i/100.0); - py = path.points[i] - off; - } - - vec4 p_car_space = (vec4){{px, py, 0., 1.}}; - vec3 p_full_frame = car_space_to_full_frame(s, p_car_space); - if (p_full_frame.v[0] < 0. || p_full_frame.v[1] < 0.) { - continue; - } - pvd->v[pvd->cnt].x = p_full_frame.v[0]; - pvd->v[pvd->cnt].y = p_full_frame.v[1]; - pvd->cnt += 1; - } - - // right side down - for (int i=path_height; i>=0; i--) { - float px, py, mpx; - if (is_mpc) { - mpx = i==0?0.0:mpc_x_coords[i]; - px = lerp(mpx+1.0, mpx, i/100.0); - py = mpc_y_coords[i] + off; - } else { - px = lerp(i+1.0, i, i/100.0); - py = path.points[i] + off; - } - - vec4 p_car_space = (vec4){{px, py, 0., 1.}}; - vec3 p_full_frame = car_space_to_full_frame(s, p_car_space); - pvd->v[pvd->cnt].x = p_full_frame.v[0]; - pvd->v[pvd->cnt].y = p_full_frame.v[1]; - pvd->cnt += 1; - } -} - -static void update_all_track_data(UIState *s) { - const UIScene *scene = &s->scene; - // Draw vision path - update_track_data(s, false, &s->track_vertices[0]); - - if (scene->engaged) { - // Draw MPC path when engaged - update_track_data(s, true, &s->track_vertices[1]); - } -} - - -static void ui_draw_track(UIState *s, bool is_mpc, track_vertices_data *pvd) { -const UIScene *scene = &s->scene; - const PathData path = scene->model.path; - const float *mpc_x_coords = &scene->mpc_x[0]; - const float *mpc_y_coords = &scene->mpc_y[0]; - - nvgSave(s->vg); - nvgTranslate(s->vg, 240.0f, 0.0); // rgb-box space - nvgTranslate(s->vg, -1440.0f / 2, -1080.0f / 2); // zoom 2x - nvgScale(s->vg, 2.0, 2.0); - nvgScale(s->vg, 1440.0f / s->rgb_width, 1080.0f / s->rgb_height); - nvgBeginPath(s->vg); - - bool started = false; - float off = is_mpc?0.3:0.5; - float lead_d = scene->lead_d_rel*2.; - float path_height = is_mpc?(lead_d>5.)?fmin(lead_d, 25.)-fmin(lead_d*0.35, 10.):20. - :(lead_d>0.)?fmin(lead_d, 50.)-fmin(lead_d*0.35, 10.):49.; - int vi = 0; - for(int i = 0;i < pvd->cnt;i++) { - if (pvd->v[i].x < 0 || pvd->v[i].y < 0) { - continue; - } - - if (!started) { - nvgMoveTo(s->vg, pvd->v[i].x, pvd->v[i].y); - started = true; - } else { - nvgLineTo(s->vg, pvd->v[i].x, pvd->v[i].y); - } - } - - nvgClosePath(s->vg); - - NVGpaint track_bg; - if (is_mpc) { - // Draw colored MPC track - const uint8_t *clr = bg_colors[s->status]; - track_bg = nvgLinearGradient(s->vg, vwp_w, vwp_h, vwp_w, vwp_h*.4, - nvgRGBA(clr[0], clr[1], clr[2], 255), nvgRGBA(clr[0], clr[1], clr[2], 255/2)); - } else { - // Draw white vision track - track_bg = nvgLinearGradient(s->vg, vwp_w, vwp_h, vwp_w, vwp_h*.4, - nvgRGBA(255, 255, 255, 255), nvgRGBA(255, 255, 255, 0)); - } - - nvgFillPaint(s->vg, track_bg); - nvgFill(s->vg); - nvgRestore(s->vg); -} - -static void draw_steering(UIState *s, float curvature) { - float points[50]; - for (int i = 0; i < 50; i++) { - float y_actual = i * tan(asin(clamp(i * curvature, -0.999, 0.999)) / 2.); - points[i] = y_actual; - } - - // ui_draw_lane_edge(s, points, 0.0, nvgRGBA(0, 0, 255, 128), 5); -} - -static void draw_frame(UIState *s) { - const UIScene *scene = &s->scene; - - float x1, x2, y1, y2; - if (s->scene.frontview) { - glBindVertexArray(s->frame_vao[1]); - } else { - glBindVertexArray(s->frame_vao[0]); - } - - mat4 *out_mat; - if (s->scene.frontview || s->scene.fullview) { - out_mat = &s->front_frame_mat; - } else { - out_mat = &s->rear_frame_mat; - } - glActiveTexture(GL_TEXTURE0); - if (s->scene.frontview && s->cur_vision_front_idx >= 0) { - glBindTexture(GL_TEXTURE_2D, s->frame_front_texs[s->cur_vision_front_idx]); - } else if (!scene->frontview && s->cur_vision_idx >= 0) { - glBindTexture(GL_TEXTURE_2D, s->frame_texs[s->cur_vision_idx]); - } - - glUseProgram(s->frame_program); - glUniform1i(s->frame_texture_loc, 0); - glUniformMatrix4fv(s->frame_transform_loc, 1, GL_TRUE, out_mat->v); - - assert(glGetError() == GL_NO_ERROR); - glEnableVertexAttribArray(0); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (const void*)0); - glDisableVertexAttribArray(0); - glBindVertexArray(0); -} - -static inline bool valid_frame_pt(UIState *s, float x, float y) { - return x >= 0 && x <= s->rgb_width && y >= 0 && y <= s->rgb_height; - -} -static void update_lane_line_data(UIState *s, const float *points, float off, bool is_ghost, model_path_vertices_data *pvd) { - pvd->cnt = 0; - for (int i = 0; i < MODEL_PATH_MAX_VERTICES_CNT / 2; i++) { - float px = (float)i; - float py = points[i] - off; - const vec4 p_car_space = (vec4){{px, py, 0., 1.}}; - const vec3 p_full_frame = car_space_to_full_frame(s, p_car_space); - if(!valid_frame_pt(s, p_full_frame.v[0], p_full_frame.v[1])) - continue; - pvd->v[pvd->cnt].x = p_full_frame.v[0]; - pvd->v[pvd->cnt].y = p_full_frame.v[1]; - pvd->cnt += 1; - } - for (int i = MODEL_PATH_MAX_VERTICES_CNT / 2; i > 0; i--) { - float px = (float)i; - float py = is_ghost?(points[i]-off):(points[i]+off); - const vec4 p_car_space = (vec4){{px, py, 0., 1.}}; - const vec3 p_full_frame = car_space_to_full_frame(s, p_car_space); - if(!valid_frame_pt(s, p_full_frame.v[0], p_full_frame.v[1])) - continue; - pvd->v[pvd->cnt].x = p_full_frame.v[0]; - pvd->v[pvd->cnt].y = p_full_frame.v[1]; - pvd->cnt += 1; - } -} - -static void update_all_lane_lines_data(UIState *s, const PathData path, model_path_vertices_data *pstart) { - update_lane_line_data(s, path.points, 0.025*path.prob, false, pstart); - float var = fmin(path.std, 0.7); - update_lane_line_data(s, path.points, -var, true, pstart + 1); - update_lane_line_data(s, path.points, var, true, pstart + 2); -} - -static void ui_draw_lane(UIState *s, const PathData *path, model_path_vertices_data *pstart, NVGcolor color) { - ui_draw_lane_line(s, pstart, color); - float var = fmin(path->std, 0.7); - color.a /= 4; - ui_draw_lane_line(s, pstart + 1, color); - ui_draw_lane_line(s, pstart + 2, color); -} - -static void ui_draw_vision_lanes(UIState *s) { - const UIScene *scene = &s->scene; - model_path_vertices_data *pvd = &s->model_path_vertices[0]; - if(s->model_changed) { - update_all_lane_lines_data(s, scene->model.left_lane, pvd); - update_all_lane_lines_data(s, scene->model.right_lane, pvd + MODEL_LANE_PATH_CNT); - s->model_changed = false; - } - // Draw left lane edge - ui_draw_lane( - s, &scene->model.left_lane, - pvd, - nvgRGBAf(1.0, 1.0, 1.0, scene->model.left_lane.prob)); - - // Draw right lane edge - ui_draw_lane( - s, &scene->model.right_lane, - pvd + MODEL_LANE_PATH_CNT, - nvgRGBAf(1.0, 1.0, 1.0, scene->model.right_lane.prob)); - - if(s->livempc_or_radarstate_changed) { - update_all_track_data(s); - s->livempc_or_radarstate_changed = false; - } - // Draw vision path - ui_draw_track(s, false, &s->track_vertices[0]); - if (scene->engaged) { - // Draw MPC path when engaged - ui_draw_track(s, true, &s->track_vertices[1]); - } -} - -// Draw all world space objects. -static void ui_draw_world(UIState *s) { - const UIScene *scene = &s->scene; - if (!scene->world_objects_visible) { - return; - } - - // Draw lane edges and vision/mpc tracks - ui_draw_vision_lanes(s); - - if (scene->lead_status) { - // Draw lead car indicator - float fillAlpha = 0; - float speedBuff = 10.; - float leadBuff = 40.; - if (scene->lead_d_rel < leadBuff) { - fillAlpha = 255*(1.0-(scene->lead_d_rel/leadBuff)); - if (scene->lead_v_rel < 0) { - fillAlpha += 255*(-1*(scene->lead_v_rel/speedBuff)); - } - fillAlpha = (int)(fmin(fillAlpha, 255)); - } - draw_chevron(s, scene->lead_d_rel+2.7, scene->lead_y_rel, 25, - nvgRGBA(201, 34, 49, fillAlpha), nvgRGBA(218, 202, 37, 255)); - } -} - -static void ui_draw_vision_maxspeed(UIState *s) { - /*if (!s->longitudinal_control){ - return; - }*/ - - const UIScene *scene = &s->scene; - int ui_viz_rx = scene->ui_viz_rx; - int ui_viz_rw = scene->ui_viz_rw; - - char maxspeed_str[32]; - float maxspeed = s->scene.v_cruise; - int maxspeed_calc = maxspeed * 0.6225 + 0.5; - float speedlimit = s->scene.speedlimit; - int speedlim_calc = speedlimit * 2.2369363 + 0.5; - int speed_lim_off = s->speed_lim_off * 2.2369363 + 0.5; - if (s->is_metric) { - maxspeed_calc = maxspeed + 0.5; - speedlim_calc = speedlimit * 3.6 + 0.5; - speed_lim_off = s->speed_lim_off * 3.6 + 0.5; - } - - bool is_cruise_set = (maxspeed != 0 && maxspeed != SET_SPEED_NA); - bool is_speedlim_valid = s->scene.speedlimit_valid; - bool is_set_over_limit = is_speedlim_valid && s->scene.engaged && - is_cruise_set && maxspeed_calc > (speedlim_calc + speed_lim_off); - - int viz_maxspeed_w = 184; - int viz_maxspeed_h = 202; - int viz_maxspeed_x = (ui_viz_rx + (bdr_s*2)); - int viz_maxspeed_y = (box_y + (bdr_s*1.5)); - int viz_maxspeed_xo = 180; - -#ifdef SHOW_SPEEDLIMIT - viz_maxspeed_w += viz_maxspeed_xo; - viz_maxspeed_x += viz_maxspeed_w - (viz_maxspeed_xo * 2); -#else - viz_maxspeed_xo = 0; -#endif - - // Draw Background - nvgBeginPath(s->vg); - nvgRoundedRect(s->vg, viz_maxspeed_x, viz_maxspeed_y, viz_maxspeed_w, viz_maxspeed_h, 30); - if (is_set_over_limit) { - nvgFillColor(s->vg, nvgRGBA(218, 111, 37, 180)); - } else { - nvgFillColor(s->vg, nvgRGBA(0, 0, 0, 100)); - } - nvgFill(s->vg); - - // Draw Border - nvgBeginPath(s->vg); - nvgRoundedRect(s->vg, viz_maxspeed_x, viz_maxspeed_y, viz_maxspeed_w, viz_maxspeed_h, 20); - if (is_set_over_limit) { - nvgStrokeColor(s->vg, nvgRGBA(218, 111, 37, 255)); - } else if (is_speedlim_valid && !s->is_ego_over_limit) { - nvgStrokeColor(s->vg, nvgRGBA(255, 255, 255, 255)); - } else if (is_speedlim_valid && s->is_ego_over_limit) { - nvgStrokeColor(s->vg, nvgRGBA(255, 255, 255, 20)); - } else { - nvgStrokeColor(s->vg, nvgRGBA(255, 255, 255, 100)); - } - nvgStrokeWidth(s->vg, 10); - nvgStroke(s->vg); - - // Draw "MAX" Text - nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); - nvgFontFace(s->vg, "sans-regular"); - nvgFontSize(s->vg, 26*2.5); - if (is_cruise_set) { - nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 200)); - } else { - nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 100)); - } - nvgText(s->vg, viz_maxspeed_x+(viz_maxspeed_xo/2)+(viz_maxspeed_w/2), 148, "MAX", NULL); - - // Draw Speed Text - nvgFontFace(s->vg, "sans-bold"); - nvgFontSize(s->vg, 48*2.5); - if (is_cruise_set) { - snprintf(maxspeed_str, sizeof(maxspeed_str), "%d", maxspeed_calc); - nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 255)); - nvgText(s->vg, viz_maxspeed_x+(viz_maxspeed_xo/2)+(viz_maxspeed_w/2), 242, maxspeed_str, NULL); - } else { - nvgFontFace(s->vg, "sans-semibold"); - nvgFontSize(s->vg, 42*2.5); - nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 100)); - nvgText(s->vg, viz_maxspeed_x+(viz_maxspeed_xo/2)+(viz_maxspeed_w/2), 242, "N/A", NULL); - } - -} - -static void ui_draw_vision_speedlimit(UIState *s) { - const UIScene *scene = &s->scene; - int ui_viz_rx = scene->ui_viz_rx; - int ui_viz_rw = scene->ui_viz_rw; - - char speedlim_str[32]; - float speedlimit = s->scene.speedlimit; - int speedlim_calc = speedlimit * 2.2369363 + 0.5; - if (s->is_metric) { - speedlim_calc = speedlimit * 3.6 + 0.5; - } - - bool is_speedlim_valid = s->scene.speedlimit_valid; - float hysteresis_offset = 0.5; - if (s->is_ego_over_limit) { - hysteresis_offset = 0.0; - } - s->is_ego_over_limit = is_speedlim_valid && s->scene.v_ego > (speedlimit + s->speed_lim_off + hysteresis_offset); - - int viz_speedlim_w = 180; - int viz_speedlim_h = 202; - int viz_speedlim_x = (ui_viz_rx + (bdr_s*2)); - int viz_speedlim_y = (box_y + (bdr_s*1.5)); - if (!is_speedlim_valid) { - viz_speedlim_w -= 5; - viz_speedlim_h -= 10; - viz_speedlim_x += 9; - viz_speedlim_y += 5; - } - int viz_speedlim_bdr = is_speedlim_valid ? 30 : 15; - - // Draw Background - nvgBeginPath(s->vg); - nvgRoundedRect(s->vg, viz_speedlim_x, viz_speedlim_y, viz_speedlim_w, viz_speedlim_h, viz_speedlim_bdr); - if (is_speedlim_valid && s->is_ego_over_limit) { - nvgFillColor(s->vg, nvgRGBA(218, 111, 37, 180)); - } else if (is_speedlim_valid) { - nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 255)); - } else { - nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 100)); - } - nvgFill(s->vg); - - // Draw Border - if (is_speedlim_valid) { - nvgStrokeWidth(s->vg, 10); - nvgStroke(s->vg); - nvgBeginPath(s->vg); - nvgRoundedRect(s->vg, viz_speedlim_x, viz_speedlim_y, viz_speedlim_w, viz_speedlim_h, 20); - if (s->is_ego_over_limit) { - nvgStrokeColor(s->vg, nvgRGBA(218, 111, 37, 255)); - } else if (is_speedlim_valid) { - nvgStrokeColor(s->vg, nvgRGBA(255, 255, 255, 255)); - } - } - - // Draw "Speed Limit" Text - nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); - nvgFontFace(s->vg, "sans-semibold"); - nvgFontSize(s->vg, 50); - nvgFillColor(s->vg, nvgRGBA(0, 0, 0, 255)); - if (is_speedlim_valid && s->is_ego_over_limit) { - nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 255)); - } - nvgText(s->vg, viz_speedlim_x+viz_speedlim_w/2 + (is_speedlim_valid ? 6 : 0), viz_speedlim_y + (is_speedlim_valid ? 50 : 45), "SMART", NULL); - nvgText(s->vg, viz_speedlim_x+viz_speedlim_w/2 + (is_speedlim_valid ? 6 : 0), viz_speedlim_y + (is_speedlim_valid ? 90 : 85), "SPEED", NULL); - - // Draw Speed Text - nvgFontFace(s->vg, "sans-bold"); - nvgFontSize(s->vg, 48*2.5); - if (s->is_ego_over_limit) { - nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 255)); - } else { - nvgFillColor(s->vg, nvgRGBA(0, 0, 0, 255)); - } - if (is_speedlim_valid) { - snprintf(speedlim_str, sizeof(speedlim_str), "%d", speedlim_calc); - nvgText(s->vg, viz_speedlim_x+viz_speedlim_w/2, viz_speedlim_y + (is_speedlim_valid ? 170 : 165), speedlim_str, NULL); - } else { - nvgFontFace(s->vg, "sans-semibold"); - nvgFontSize(s->vg, 42*2.5); - nvgText(s->vg, viz_speedlim_x+viz_speedlim_w/2, viz_speedlim_y + (is_speedlim_valid ? 170 : 165), "N/A", NULL); - } -} - -static void ui_draw_vision_speed(UIState *s) { - const UIScene *scene = &s->scene; - int ui_viz_rx = scene->ui_viz_rx; - int ui_viz_rw = scene->ui_viz_rw; - float speed = s->scene.v_ego; - - const int viz_speed_w = 280; - const int viz_speed_x = ui_viz_rx+((ui_viz_rw/2)-(viz_speed_w/2)); - char speed_str[32]; - - nvgBeginPath(s->vg); - nvgRect(s->vg, viz_speed_x, box_y, viz_speed_w, header_h); - nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); - - if (s->is_metric) { - snprintf(speed_str, sizeof(speed_str), "%d", (int)(speed * 3.6 + 0.5)); - } else { - snprintf(speed_str, sizeof(speed_str), "%d", (int)(speed * 2.2369363 + 0.5)); - } - nvgFontFace(s->vg, "sans-bold"); - nvgFontSize(s->vg, 96*2.5); - nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 255)); - nvgText(s->vg, viz_speed_x+viz_speed_w/2, 240, speed_str, NULL); - - nvgFontFace(s->vg, "sans-regular"); - nvgFontSize(s->vg, 36*2.5); - nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 200)); - - if (s->is_metric) { - nvgText(s->vg, viz_speed_x+viz_speed_w/2, 320, "kph", NULL); - } else { - nvgText(s->vg, viz_speed_x+viz_speed_w/2, 320, "mph", NULL); - } -} - -static void ui_draw_vision_event(UIState *s) { - const UIScene *scene = &s->scene; - const int ui_viz_rx = scene->ui_viz_rx; - const int ui_viz_rw = scene->ui_viz_rw; - const int viz_event_w = 220; - const int viz_event_x = ((ui_viz_rx + ui_viz_rw) - (viz_event_w + (bdr_s*2))); - const int viz_event_y = (box_y + (bdr_s*1.5)); - const int viz_event_h = (header_h - (bdr_s*1.5)); - if (s->scene.decel_for_model && s->scene.engaged) { - // draw winding road sign - const int img_turn_size = 160*1.5; - const int img_turn_x = viz_event_x-(img_turn_size/4); - const int img_turn_y = viz_event_y+bdr_s-25; - float img_turn_alpha = 1.0f; - nvgBeginPath(s->vg); - NVGpaint imgPaint = nvgImagePattern(s->vg, img_turn_x, img_turn_y, - img_turn_size, img_turn_size, 0, s->img_turn, img_turn_alpha); - nvgRect(s->vg, img_turn_x, img_turn_y, img_turn_size, img_turn_size); - nvgFillPaint(s->vg, imgPaint); - nvgFill(s->vg); - } else { - // draw steering wheel - const int bg_wheel_size = 96; - const int bg_wheel_x = viz_event_x + (viz_event_w-bg_wheel_size); - const int bg_wheel_y = viz_event_y + (bg_wheel_size/2); - const int img_wheel_size = bg_wheel_size*1.5; - const int img_wheel_x = bg_wheel_x-(img_wheel_size/2); - const int img_wheel_y = bg_wheel_y-25; - float img_wheel_alpha = 0.1f; - bool is_engaged = (s->status == STATUS_ENGAGED); - bool is_warning = (s->status == STATUS_WARNING); - bool is_engageable = scene->engageable; - if (is_engaged || is_warning || is_engageable) { - nvgBeginPath(s->vg); - nvgCircle(s->vg, bg_wheel_x, (bg_wheel_y + (bdr_s*1.5)), bg_wheel_size); - if (is_engaged) { - nvgFillColor(s->vg, nvgRGBA(23, 134, 68, 255)); - } else if (is_warning) { - nvgFillColor(s->vg, nvgRGBA(218, 111, 37, 255)); - } else if (is_engageable) { - nvgFillColor(s->vg, nvgRGBA(23, 51, 73, 255)); - } - nvgFill(s->vg); - img_wheel_alpha = 1.0f; - } - nvgBeginPath(s->vg); - NVGpaint imgPaint = nvgImagePattern(s->vg, img_wheel_x, img_wheel_y, - img_wheel_size, img_wheel_size, 0, s->img_wheel, img_wheel_alpha); - nvgRect(s->vg, img_wheel_x, img_wheel_y, img_wheel_size, img_wheel_size); - nvgFillPaint(s->vg, imgPaint); - nvgFill(s->vg); - } -} - -static void ui_draw_vision_map(UIState *s) { - const UIScene *scene = &s->scene; - const int map_size = 96; - const int map_x = (scene->ui_viz_rx + (map_size * 3) + (bdr_s * 3)); - const int map_y = (footer_y + ((footer_h - map_size) / 2)); - const int map_img_size = (map_size * 1.5); - const int map_img_x = (map_x - (map_img_size / 2)); - const int map_img_y = (map_y - (map_size / 4)); - - bool map_valid = s->scene.map_valid; - float map_img_alpha = map_valid ? 1.0f : 0.15f; - float map_bg_alpha = map_valid ? 0.3f : 0.1f; - NVGcolor map_bg = nvgRGBA(0, 0, 0, (255 * map_bg_alpha)); - NVGpaint map_img = nvgImagePattern(s->vg, map_img_x, map_img_y, - map_img_size, map_img_size, 0, s->img_map, map_img_alpha); - - nvgBeginPath(s->vg); - nvgCircle(s->vg, map_x, (map_y + (bdr_s * 1.5)), map_size); - nvgFillColor(s->vg, map_bg); - nvgFill(s->vg); - - nvgBeginPath(s->vg); - nvgRect(s->vg, map_img_x, map_img_y, map_img_size, map_img_size); - nvgFillPaint(s->vg, map_img); - nvgFill(s->vg); -} - -static void ui_draw_vision_face(UIState *s) { - const UIScene *scene = &s->scene; - const int face_size = 96; - const int face_x = (scene->ui_viz_rx + face_size + (bdr_s * 2)); - const int face_y = (footer_y + ((footer_h - face_size) / 2)); - const int face_img_size = (face_size * 1.5); - const int face_img_x = (face_x - (face_img_size / 2)); - const int face_img_y = (face_y - (face_size / 4)); - float face_img_alpha = scene->monitoring_active ? 1.0f : 0.15f; - float face_bg_alpha = scene->monitoring_active ? 0.3f : 0.1f; - NVGcolor face_bg = nvgRGBA(0, 0, 0, (255 * face_bg_alpha)); - NVGpaint face_img = nvgImagePattern(s->vg, face_img_x, face_img_y, - face_img_size, face_img_size, 0, s->img_face, face_img_alpha); - - nvgBeginPath(s->vg); - nvgCircle(s->vg, face_x, (face_y + (bdr_s * 1.5)), face_size); - nvgFillColor(s->vg, face_bg); - nvgFill(s->vg); - - nvgBeginPath(s->vg); - nvgRect(s->vg, face_img_x, face_img_y, face_img_size, face_img_size); - nvgFillPaint(s->vg, face_img); - nvgFill(s->vg); -} - -static void ui_draw_vision_header(UIState *s) { - const UIScene *scene = &s->scene; - int ui_viz_rx = scene->ui_viz_rx; - int ui_viz_rw = scene->ui_viz_rw; - - nvgBeginPath(s->vg); - NVGpaint gradient = nvgLinearGradient(s->vg, ui_viz_rx, - (box_y+(header_h-(header_h/2.5))), - ui_viz_rx, box_y+header_h, - nvgRGBAf(0,0,0,0.45), nvgRGBAf(0,0,0,0)); - nvgFillPaint(s->vg, gradient); - nvgRect(s->vg, ui_viz_rx, box_y, ui_viz_rw, header_h); - nvgFill(s->vg); - - ui_draw_vision_maxspeed(s); - -#ifdef SHOW_SPEEDLIMIT - ui_draw_vision_speedlimit(s); -#endif - ui_draw_vision_speed(s); - ui_draw_vision_event(s); -} - -static void ui_draw_vision_footer(UIState *s) { - const UIScene *scene = &s->scene; - int ui_viz_rx = scene->ui_viz_rx; - int ui_viz_rw = scene->ui_viz_rw; - - nvgBeginPath(s->vg); - nvgRect(s->vg, ui_viz_rx, footer_y, ui_viz_rw, footer_h); - - ui_draw_vision_face(s); - -#ifdef SHOW_SPEEDLIMIT - // ui_draw_vision_map(s); -#endif -} - -static void ui_draw_vision_alert(UIState *s, int va_size, int va_color, - const char* va_text1, const char* va_text2) { - const UIScene *scene = &s->scene; - int ui_viz_rx = scene->ui_viz_rx; - int ui_viz_rw = scene->ui_viz_rw; - bool hasSidebar = !s->scene.uilayout_sidebarcollapsed; - bool mapEnabled = s->scene.uilayout_mapenabled; - bool longAlert1 = strlen(va_text1) > 15; - - const uint8_t *color = alert_colors[va_color]; - const int alr_s = alert_sizes[va_size]; - const int alr_x = ui_viz_rx-(mapEnabled?(hasSidebar?nav_w:(nav_ww)):0)-bdr_s; - const int alr_w = ui_viz_rw+(mapEnabled?(hasSidebar?nav_w:(nav_ww)):0)+(bdr_s*2); - const int alr_h = alr_s+(va_size==ALERTSIZE_NONE?0:bdr_s); - const int alr_y = vwp_h-alr_h; - - nvgBeginPath(s->vg); - nvgRect(s->vg, alr_x, alr_y, alr_w, alr_h); - nvgFillColor(s->vg, nvgRGBA(color[0],color[1],color[2],(color[3]*s->alert_blinking_alpha))); - nvgFill(s->vg); - - nvgBeginPath(s->vg); - NVGpaint gradient = nvgLinearGradient(s->vg, alr_x, alr_y, alr_x, alr_y+alr_h, - nvgRGBAf(0.0,0.0,0.0,0.05), nvgRGBAf(0.0,0.0,0.0,0.35)); - nvgFillPaint(s->vg, gradient); - nvgRect(s->vg, alr_x, alr_y, alr_w, alr_h); - nvgFill(s->vg); - - nvgFillColor(s->vg, nvgRGBA(255, 255, 255, 255)); - nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BASELINE); - - if (va_size == ALERTSIZE_SMALL) { - nvgFontFace(s->vg, "sans-semibold"); - nvgFontSize(s->vg, 40*2.5); - nvgText(s->vg, alr_x+alr_w/2, alr_y+alr_h/2+15, va_text1, NULL); - } else if (va_size== ALERTSIZE_MID) { - nvgFontFace(s->vg, "sans-bold"); - nvgFontSize(s->vg, 48*2.5); - nvgText(s->vg, alr_x+alr_w/2, alr_y+alr_h/2-45, va_text1, NULL); - nvgFontFace(s->vg, "sans-regular"); - nvgFontSize(s->vg, 36*2.5); - nvgText(s->vg, alr_x+alr_w/2, alr_y+alr_h/2+75, va_text2, NULL); - } else if (va_size== ALERTSIZE_FULL) { - nvgFontSize(s->vg, (longAlert1?72:96)*2.5); - nvgFontFace(s->vg, "sans-bold"); - nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE); - nvgTextBox(s->vg, alr_x, alr_y+(longAlert1?360:420), alr_w-60, va_text1, NULL); - nvgFontSize(s->vg, 48*2.5); - nvgFontFace(s->vg, "sans-regular"); - nvgTextAlign(s->vg, NVG_ALIGN_CENTER | NVG_ALIGN_BOTTOM); - nvgTextBox(s->vg, alr_x, alr_h-(longAlert1?300:360), alr_w-60, va_text2, NULL); - } -} - -static void ui_draw_vision(UIState *s) { - const UIScene *scene = &s->scene; - int ui_viz_rx = scene->ui_viz_rx; - int ui_viz_rw = scene->ui_viz_rw; - int ui_viz_ro = scene->ui_viz_ro; - - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - - // Draw video frames - glEnable(GL_SCISSOR_TEST); - glViewport(ui_viz_rx+ui_viz_ro, s->fb_h-(box_y+box_h), viz_w, box_h); - glScissor(ui_viz_rx, s->fb_h-(box_y+box_h), ui_viz_rw, box_h); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - draw_frame(s); - glViewport(0, 0, s->fb_w, s->fb_h); - glDisable(GL_SCISSOR_TEST); - - glClear(GL_STENCIL_BUFFER_BIT); - - nvgBeginFrame(s->vg, s->fb_w, s->fb_h, 1.0f); - nvgSave(s->vg); - - // Draw augmented elements - const int inner_height = viz_w*9/16; - nvgScissor(s->vg, ui_viz_rx, box_y, ui_viz_rw, box_h); - nvgTranslate(s->vg, ui_viz_rx+ui_viz_ro, box_y + (box_h-inner_height)/2.0); - nvgScale(s->vg, (float)viz_w / s->fb_w, (float)inner_height / s->fb_h); - if (!scene->frontview && !scene->fullview) { - ui_draw_world(s); - } - - nvgRestore(s->vg); - - // Set Speed, Current Speed, Status/Events - ui_draw_vision_header(s); - - if (s->scene.alert_size != ALERTSIZE_NONE) { - // Controls Alerts - ui_draw_vision_alert(s, s->scene.alert_size, s->status, - s->scene.alert_text1, s->scene.alert_text2); - } else { - ui_draw_vision_footer(s); - } - - - nvgEndFrame(s->vg); - glDisable(GL_BLEND); -} - -static void ui_draw_blank(UIState *s) { - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); -} - -static void ui_draw(UIState *s) { - if (s->vision_connected && s->active_app == cereal_UiLayoutState_App_home && s->status != STATUS_STOPPED) { - ui_draw_vision(s); - } else { - ui_draw_blank(s); - } - - { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glClear(GL_STENCIL_BUFFER_BIT); - - nvgBeginFrame(s->vg, s->fb_w, s->fb_h, 1.0f); - - nvgEndFrame(s->vg); - glDisable(GL_BLEND); - } -} - static PathData read_path(cereal_ModelData_PathData_ptr pathp) { PathData ret = {0}; @@ -1603,11 +263,6 @@ void handle_message(UIState *s, Message * msg) { struct cereal_Event eventd; cereal_read_Event(&eventd, eventp); - // Skip messages from previous run - if (nanos_since_boot() - eventd.logMonoTime > 1e9) { - return; - } - if (eventd.which == cereal_Event_controlsState) { struct cereal_ControlsState datad; cereal_read_ControlsState(&datad, eventd.controlsState); @@ -1789,6 +444,9 @@ static void ui_update(UIState *s) { .bpp = 3, .size = s->rgb_buf_len, }; + #ifndef QCOM + s->priv_hnds[i] = s->bufs[i].addr; + #endif s->frame_texs[i] = visionimg_to_gl(&img, &s->khr[i], &s->priv_hnds[i]); glBindTexture(GL_TEXTURE_2D, s->frame_texs[i]); @@ -1816,6 +474,9 @@ static void ui_update(UIState *s) { .bpp = 3, .size = s->rgb_front_buf_len, }; + #ifndef QCOM + s->priv_hnds_front[i] = s->bufs[i].addr; + #endif s->frame_front_texs[i] = visionimg_to_gl(&img, &s->khr_front[i], &s->priv_hnds_front[i]); glBindTexture(GL_TEXTURE_2D, s->frame_front_texs[i]); @@ -1996,12 +657,28 @@ static void* vision_connect_thread(void *args) { s->vision_connected = true; s->vision_connect_firstrun = true; + + // Drain sockets + while (true){ + auto polls = s->poller->poll(0); + if (polls.size() == 0) + break; + + for (auto sock : polls){ + Message * msg = sock->receive(); + if (msg == NULL) continue; + delete msg; + } + } + pthread_mutex_unlock(&s->lock); } return NULL; } +#ifdef QCOM +#include #include #include @@ -2057,11 +734,7 @@ static void* bg_thread(void* args) { UIState *s = (UIState*)args; set_thread_name("bg"); - EGLDisplay bg_display; - EGLSurface bg_surface; - - FramebufferState *bg_fb = framebuffer_init("bg", 0x00001000, false, - &bg_display, &bg_surface, NULL, NULL); + FramebufferState *bg_fb = framebuffer_init("bg", 0x00001000, false, NULL, NULL); assert(bg_fb); int bg_status = -1; @@ -2080,13 +753,14 @@ static void* bg_thread(void* args) { glClearColor(color[0]/256.0, color[1]/256.0, color[2]/256.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); - eglSwapBuffers(bg_display, bg_surface); - assert(glGetError() == GL_NO_ERROR); + framebuffer_swap(bg_fb); } return NULL; } +#endif + int is_leon() { #define MAXCHAR 1000 FILE *fp; @@ -2121,6 +795,7 @@ int main(int argc, char* argv[]) { vision_connect_thread, s); assert(err == 0); +#ifdef QCOM pthread_t light_sensor_thread_handle; err = pthread_create(&light_sensor_thread_handle, NULL, light_sensor_thread, s); @@ -2130,17 +805,13 @@ int main(int argc, char* argv[]) { err = pthread_create(&bg_thread_handle, NULL, bg_thread, s); assert(err == 0); +#endif TouchState touch = {0}; touch_init(&touch); s->touch_fd = touch.fd; - char* error = NULL; - ui_sound_init(&error); - if (error) { - LOGW(error); - exit(1); - } + ui_sound_init(); // light sensor scaling params const int LEON = is_leon(); @@ -2153,7 +824,8 @@ int main(int argc, char* argv[]) { const int MIN_VOLUME = LEON ? 12 : 9; const int MAX_VOLUME = LEON ? 15 : 12; - set_volume(s, MIN_VOLUME); + set_volume(MIN_VOLUME); + s->volume_timeout = 5 * UI_FREQ; int draws = 0; while (!do_exit) { bool should_swap = false; @@ -2224,7 +896,8 @@ int main(int argc, char* argv[]) { s->volume_timeout--; } else { int volume = fmin(MAX_VOLUME, MIN_VOLUME + s->scene.v_ego / 5); // up one notch every 5 m/s - set_volume(s, volume); + set_volume(volume); + s->volume_timeout = 5 * UI_FREQ; } if (s->controls_timeout > 0) { @@ -2238,6 +911,7 @@ int main(int argc, char* argv[]) { } // if visiond is still running and controlsState times out, display an alert + // TODO: refactor this to not be here if (s->controls_seen && s->vision_connected && strcmp(s->scene.alert_text2, "Controls Unresponsive") != 0) { s->scene.alert_size = ALERTSIZE_FULL; if (s->status != STATUS_STOPPED) { @@ -2272,20 +946,24 @@ int main(int argc, char* argv[]) { LOGW("slow frame(%d) time: %.2f", draws, u2-u1); } draws++; - eglSwapBuffers(s->display, s->surface); + framebuffer_swap(s->fb); } } set_awake(s, true); - - slplay_destroy(); + ui_sound_destroy(); // wake up bg thread to exit pthread_mutex_lock(&s->lock); pthread_cond_signal(&s->bg_cond); pthread_mutex_unlock(&s->lock); + +#ifdef QCOM + // join light_sensor_thread? + err = pthread_join(bg_thread_handle, NULL); assert(err == 0); +#endif err = pthread_join(connect_thread_handle, NULL); assert(err == 0); diff --git a/selfdrive/ui/ui.hpp b/selfdrive/ui/ui.hpp new file mode 100644 index 0000000000..e520f6eae4 --- /dev/null +++ b/selfdrive/ui/ui.hpp @@ -0,0 +1,253 @@ +#ifndef _UI_H +#define _UI_H + +#include +#include + +#include "nanovg.h" + +#include "common/mat.h" +#include "common/visionipc.h" +#include "common/framebuffer.h" +#include "common/modeldata.h" +#include "messaging.hpp" + +#include "cereal/gen/c/log.capnp.h" + +#include "sound.hpp" + +#define STATUS_STOPPED 0 +#define STATUS_DISENGAGED 1 +#define STATUS_ENGAGED 2 +#define STATUS_WARNING 3 +#define STATUS_ALERT 4 + +#define ALERTSIZE_NONE 0 +#define ALERTSIZE_SMALL 1 +#define ALERTSIZE_MID 2 +#define ALERTSIZE_FULL 3 + +#ifndef QCOM + #define UI_60FPS +#endif + +#define UI_BUF_COUNT 4 +//#define SHOW_SPEEDLIMIT 1 +//#define DEBUG_TURN + +const int vwp_w = 1920; +const int vwp_h = 1080; +const int nav_w = 640; +const int nav_ww= 760; +const int sbr_w = 300; +const int bdr_s = 30; +const int box_x = sbr_w+bdr_s; +const int box_y = bdr_s; +const int box_w = vwp_w-sbr_w-(bdr_s*2); +const int box_h = vwp_h-(bdr_s*2); +const int viz_w = vwp_w-(bdr_s*2); +const int header_h = 420; +const int footer_h = 280; +const int footer_y = vwp_h-bdr_s-footer_h; + +const int UI_FREQ = 30; // Hz + +const int MODEL_PATH_MAX_VERTICES_CNT = 98; +const int MODEL_LANE_PATH_CNT = 3; +const int TRACK_POINTS_MAX_CNT = 50 * 2; + +const int SET_SPEED_NA = 255; + +const uint8_t bg_colors[][4] = { + [STATUS_STOPPED] = {0x07, 0x23, 0x39, 0xff}, + [STATUS_DISENGAGED] = {0x17, 0x33, 0x49, 0xff}, + [STATUS_ENGAGED] = {0x17, 0x86, 0x44, 0xff}, + [STATUS_WARNING] = {0xDA, 0x6F, 0x25, 0xff}, + [STATUS_ALERT] = {0xC9, 0x22, 0x31, 0xff}, +}; + + +typedef struct UIScene { + int frontview; + int fullview; + + int transformed_width, transformed_height; + + ModelData model; + + float mpc_x[50]; + float mpc_y[50]; + + bool world_objects_visible; + mat4 extrinsic_matrix; // Last row is 0 so we can use mat4. + + float v_cruise; + uint64_t v_cruise_update_ts; + float v_ego; + bool decel_for_model; + + float speedlimit; + bool speedlimit_valid; + bool map_valid; + + float curvature; + int engaged; + bool engageable; + bool monitoring_active; + + bool uilayout_sidebarcollapsed; + bool uilayout_mapenabled; + // responsive layout + int ui_viz_rx; + int ui_viz_rw; + int ui_viz_ro; + + int lead_status; + float lead_d_rel, lead_y_rel, lead_v_rel; + + int front_box_x, front_box_y, front_box_width, front_box_height; + + uint64_t alert_ts; + char alert_text1[1024]; + char alert_text2[1024]; + uint8_t alert_size; + float alert_blinkingrate; + + float awareness_status; + + // Used to show gps planner status + bool gps_planner_active; +} UIScene; + +typedef struct { + float x, y; +}vertex_data; + +typedef struct { + vertex_data v[MODEL_PATH_MAX_VERTICES_CNT]; + int cnt; +} model_path_vertices_data; + +typedef struct { + vertex_data v[TRACK_POINTS_MAX_CNT]; + int cnt; +} track_vertices_data; + + +typedef struct UIState { + pthread_mutex_t lock; + pthread_cond_t bg_cond; + + // framebuffer + FramebufferState *fb; + int fb_w, fb_h; + EGLDisplay display; + EGLSurface surface; + + // NVG + NVGcontext *vg; + + // fonts and images + int font_courbd; + int font_sans_regular; + int font_sans_semibold; + int font_sans_bold; + int img_wheel; + int img_turn; + int img_face; + int img_map; + + // sockets + Context *ctx; + SubSocket *model_sock; + SubSocket *controlsstate_sock; + SubSocket *livecalibration_sock; + SubSocket *radarstate_sock; + SubSocket *map_data_sock; + SubSocket *uilayout_sock; + Poller * poller; + + int active_app; + + // vision state + bool vision_connected; + bool vision_connect_firstrun; + int ipc_fd; + + VIPCBuf bufs[UI_BUF_COUNT]; + VIPCBuf front_bufs[UI_BUF_COUNT]; + int cur_vision_idx; + int cur_vision_front_idx; + + GLuint frame_program; + GLuint frame_texs[UI_BUF_COUNT]; + EGLImageKHR khr[UI_BUF_COUNT]; + void *priv_hnds[UI_BUF_COUNT]; + GLuint frame_front_texs[UI_BUF_COUNT]; + EGLImageKHR khr_front[UI_BUF_COUNT]; + void *priv_hnds_front[UI_BUF_COUNT]; + + GLint frame_pos_loc, frame_texcoord_loc; + GLint frame_texture_loc, frame_transform_loc; + + GLuint line_program; + GLint line_pos_loc, line_color_loc; + GLint line_transform_loc; + + int rgb_width, rgb_height, rgb_stride; + size_t rgb_buf_len; + mat4 rgb_transform; + + int rgb_front_width, rgb_front_height, rgb_front_stride; + size_t rgb_front_buf_len; + + UIScene scene; + bool awake; + + // timeouts + int awake_timeout; + int volume_timeout; + int controls_timeout; + int alert_sound_timeout; + int speed_lim_off_timeout; + int is_metric_timeout; + int longitudinal_control_timeout; + int limit_set_speed_timeout; + + bool controls_seen; + + int status; + bool is_metric; + bool longitudinal_control; + bool limit_set_speed; + float speed_lim_off; + bool is_ego_over_limit; + char alert_type[64]; + AudibleAlert alert_sound; + int alert_size; + float alert_blinking_alpha; + bool alert_blinked; + + float light_sensor; + + int touch_fd; + + // Hints for re-calculations and redrawing + bool model_changed; + bool livempc_or_radarstate_changed; + + GLuint frame_vao[2], frame_vbo[2], frame_ibo[2]; + mat4 rear_frame_mat, front_frame_mat; + + model_path_vertices_data model_path_vertices[MODEL_LANE_PATH_CNT * 2]; + + track_vertices_data track_vertices[2]; +} UIState; + +// API +void ui_draw_vision_alert(UIState *s, int va_size, int va_color, + const char* va_text1, const char* va_text2); +void ui_draw(UIState *s); +void ui_nvg_init(UIState *s); + +#endif diff --git a/selfdrive/updated.py b/selfdrive/updated.py index 1ac216c4fe..efde9adcc8 100755 --- a/selfdrive/updated.py +++ b/selfdrive/updated.py @@ -1,57 +1,361 @@ #!/usr/bin/env python3 -# simple service that waits for network access and tries to update every hour +# Safe Update: A simple service that waits for network access and tries to +# update every 10 minutes. It's intended to make the OP update process more +# robust against Git repository corruption. This service DOES NOT try to fix +# an already-corrupt BASEDIR Git repo, only prevent it from happening. +# +# During normal operation, both onroad and offroad, the update process makes +# no changes to the BASEDIR install of OP. All update attempts are performed +# in a disposable staging area provided by OverlayFS. It assumes the deleter +# process provides enough disk space to carry out the process. +# +# If an update succeeds, a flag is set, and the update is swapped in at the +# next reboot. If an update is interrupted or otherwise fails, the OverlayFS +# upper layer and metadata can be discarded before trying again. +# +# The swap on boot is triggered by launch_chffrplus.sh +# gated on the existence of $FINALIZED/.overlay_consistent and also the +# existence and mtime of $BASEDIR/.overlay_init. +# +# Other than build byproducts, BASEDIR should not be modified while this +# service is running. Developers modifying code directly in BASEDIR should +# disable this service. +import os import datetime import subprocess -import time +import psutil +from stat import S_ISREG, S_ISDIR, S_ISLNK, S_IMODE, ST_MODE, ST_INO, ST_UID, ST_GID, ST_ATIME, ST_MTIME +import shutil +import signal +from pathlib import Path +import fcntl +import threading +from cffi import FFI +from common.basedir import BASEDIR from common.params import Params from selfdrive.swaglog import cloudlog +STAGING_ROOT = "/data/safe_staging" + +OVERLAY_UPPER = os.path.join(STAGING_ROOT, "upper") +OVERLAY_METADATA = os.path.join(STAGING_ROOT, "metadata") +OVERLAY_MERGED = os.path.join(STAGING_ROOT, "merged") +FINALIZED = os.path.join(STAGING_ROOT, "finalized") + NICE_LOW_PRIORITY = ["nice", "-n", "19"] +SHORT = os.getenv("SHORT") is not None + +# Workaround for the EON/termux build of Python having os.link removed. +ffi = FFI() +ffi.cdef("int link(const char *oldpath, const char *newpath);") +libc = ffi.dlopen(None) + + +class WaitTimeHelper: + ready_event = threading.Event() + shutdown = False + + def __init__(self): + signal.signal(signal.SIGTERM, self.graceful_shutdown) + signal.signal(signal.SIGINT, self.graceful_shutdown) + signal.signal(signal.SIGHUP, self.update_now) + + def graceful_shutdown(self, signum, frame): + # umount -f doesn't appear effective in avoiding "device busy" on EON, + # so don't actually die until the next convenient opportunity in main(). + cloudlog.info("caught SIGINT/SIGTERM, dismounting overlay at next opportunity") + self.shutdown = True + self.ready_event.set() + + def update_now(self, signum, frame): + cloudlog.info("caught SIGHUP, running update check immediately") + self.ready_event.set() + + +def wait_between_updates(ready_event): + ready_event.clear() + if SHORT: + ready_event.wait(timeout=10) + else: + ready_event.wait(timeout=60 * 10) + + +def link(src, dest): + # Workaround for the EON/termux build of Python having os.link removed. + return libc.link(src.encode(), dest.encode()) + + +def run(cmd, cwd=None): + return subprocess.check_output(cmd, cwd=cwd, stderr=subprocess.STDOUT, encoding='utf8') + + +def remove_consistent_flag(): + os.system("sync") + consistent_file = Path(os.path.join(FINALIZED, ".overlay_consistent")) + try: + consistent_file.unlink() + except FileNotFoundError: + pass + os.system("sync") + + +def set_consistent_flag(): + consistent_file = Path(os.path.join(FINALIZED, ".overlay_consistent")) + os.system("sync") + consistent_file.touch() + os.system("sync") + + +def set_update_available_params(new_version=False): + params = Params() + + t = datetime.datetime.now().isoformat() + params.put("LastUpdateTime", t.encode('utf8')) + + if new_version: + try: + with open(os.path.join(FINALIZED, "RELEASES.md"), "rb") as f: + r = f.read() + r = r[:r.find(b'\n\n')] # Slice latest release notes + params.put("ReleaseNotes", r + b"\n") + except Exception: + params.put("ReleaseNotes", "") + params.put("UpdateAvailable", "1") + + +def dismount_ovfs(): + if os.path.ismount(OVERLAY_MERGED): + cloudlog.error("unmounting existing overlay") + run(["umount", "-l", OVERLAY_MERGED]) + + +def init_ovfs(): + cloudlog.info("preparing new safe staging area") + Params().put("UpdateAvailable", "0") + + remove_consistent_flag() + + dismount_ovfs() + if os.path.isdir(STAGING_ROOT): + shutil.rmtree(STAGING_ROOT) + + for dirname in [STAGING_ROOT, OVERLAY_UPPER, OVERLAY_METADATA, OVERLAY_MERGED, FINALIZED]: + os.mkdir(dirname, 0o755) + if not os.lstat(BASEDIR).st_dev == os.lstat(OVERLAY_MERGED).st_dev: + raise RuntimeError("base and overlay merge directories are on different filesystems; not valid for overlay FS!") + + # Remove consistent flag from current BASEDIR so it's not copied over + if os.path.isfile(os.path.join(BASEDIR, ".overlay_consistent")): + os.remove(os.path.join(BASEDIR, ".overlay_consistent")) + + # We sync FS object atimes (which EON doesn't use) and mtimes, but ctimes + # are outside user control. Make sure Git is set up to ignore system ctimes, + # because they change when we make hard links during finalize. Otherwise, + # there is a lot of unnecessary churn. This appears to be a common need on + # OSX as well: https://www.git-tower.com/blog/make-git-rebase-safe-on-osx/ + run(["git", "config", "core.trustctime", "false"], BASEDIR) + + # We are temporarily using copytree to copy the directory, which also changes + # inode numbers. Ignore those changes too. + run(["git", "config", "core.checkStat", "minimal"], BASEDIR) + + # Leave a timestamped canary in BASEDIR to check at startup. The EON clock + # should be correct by the time we get here. If the init file disappears, or + # critical mtimes in BASEDIR are newer than .overlay_init, continue.sh can + # assume that BASEDIR has used for local development or otherwise modified, + # and skips the update activation attempt. + Path(os.path.join(BASEDIR, ".overlay_init")).touch() + + overlay_opts = f"lowerdir={BASEDIR},upperdir={OVERLAY_UPPER},workdir={OVERLAY_METADATA}" + run(["mount", "-t", "overlay", "-o", overlay_opts, "none", OVERLAY_MERGED]) + + +def inodes_in_tree(search_dir): + """Given a search root, produce a dictionary mapping of inodes to relative + pathnames of regular files (no directories, symlinks, or special files).""" + inode_map = {} + for root, dirs, files in os.walk(search_dir, topdown=True): + for file_name in files: + full_path_name = os.path.join(root, file_name) + st = os.lstat(full_path_name) + if S_ISREG(st[ST_MODE]): + inode_map[st[ST_INO]] = full_path_name + return inode_map + + +def dup_ovfs_object(inode_map, source_obj, target_dir): + """Given a relative pathname to copy, and a new target root, duplicate the + source object in the target root, using hardlinks for regular files.""" + + source_full_path = os.path.join(OVERLAY_MERGED, source_obj) + st = os.lstat(source_full_path) + target_full_path = os.path.join(target_dir, source_obj) + + if S_ISREG(st[ST_MODE]): + # Hardlink all regular files; ownership and permissions are shared. + link(inode_map[st[ST_INO]], target_full_path) + else: + # Recreate all directories and symlinks; copy ownership and permissions. + if S_ISDIR(st[ST_MODE]): + os.mkdir(os.path.join(FINALIZED, source_obj), S_IMODE(st[ST_MODE])) + elif S_ISLNK(st[ST_MODE]): + os.symlink(os.readlink(source_full_path), target_full_path) + os.chmod(target_full_path, S_IMODE(st[ST_MODE]), follow_symlinks=False) + else: + # Ran into a FIFO, socket, etc. Should not happen in OP install dir. + # Ignore without copying for the time being; revisit later if needed. + cloudlog.error("can't copy this file type: %s" % source_full_path) + os.chown(target_full_path, st[ST_UID], st[ST_GID], follow_symlinks=False) + + # Sync target mtimes to the cached lstat() value from each source object. + # Restores shared inode mtimes after linking, fixes symlinks and dirs. + os.utime(target_full_path, (st[ST_ATIME], st[ST_MTIME]), follow_symlinks=False) + + +def finalize_from_ovfs_hardlink(): + """Take the current OverlayFS merged view and finalize a copy outside of + OverlayFS, ready to be swapped-in at BASEDIR. Copy using hardlinks""" + + cloudlog.info("creating finalized version of the overlay") + + # The "copy" is done with hardlinks, but since the OverlayFS merge looks + # like a different filesystem, and hardlinks can't cross filesystems, we + # have to borrow a source pathname from the upper or lower layer. + inode_map = inodes_in_tree(BASEDIR) + inode_map.update(inodes_in_tree(OVERLAY_UPPER)) + + shutil.rmtree(FINALIZED) + os.umask(0o077) + os.mkdir(FINALIZED) + for root, dirs, files in os.walk(OVERLAY_MERGED, topdown=True): + for obj_name in dirs: + relative_path_name = os.path.relpath(os.path.join(root, obj_name), OVERLAY_MERGED) + dup_ovfs_object(inode_map, relative_path_name, FINALIZED) + for obj_name in files: + relative_path_name = os.path.relpath(os.path.join(root, obj_name), OVERLAY_MERGED) + dup_ovfs_object(inode_map, relative_path_name, FINALIZED) + cloudlog.info("done finalizing overlay") + + +def finalize_from_ovfs_copy(): + """Take the current OverlayFS merged view and finalize a copy outside of + OverlayFS, ready to be swapped-in at BASEDIR. Copy using shutil.copytree""" + + cloudlog.info("creating finalized version of the overlay") + shutil.rmtree(FINALIZED) + shutil.copytree(OVERLAY_MERGED, FINALIZED, symlinks=True) + cloudlog.info("done finalizing overlay") + + +def attempt_update(): + cloudlog.info("attempting git update inside staging overlay") + + git_fetch_output = run(NICE_LOW_PRIORITY + ["git", "fetch"], OVERLAY_MERGED) + cloudlog.info("git fetch success: %s", git_fetch_output) + + cur_hash = run(["git", "rev-parse", "HEAD"], OVERLAY_MERGED).rstrip() + upstream_hash = run(["git", "rev-parse", "@{u}"], OVERLAY_MERGED).rstrip() + new_version = cur_hash != upstream_hash + + git_fetch_result = len(git_fetch_output) > 0 and (git_fetch_output != "Failed to add the host to the list of known hosts (/data/data/com.termux/files/home/.ssh/known_hosts).\n") + + cloudlog.info("comparing %s to %s" % (cur_hash, upstream_hash)) + if new_version or git_fetch_result: + cloudlog.info("Running update") + if new_version: + cloudlog.info("git reset in progress") + r = [ + run(NICE_LOW_PRIORITY + ["git", "reset", "--hard", "@{u}"], OVERLAY_MERGED), + run(NICE_LOW_PRIORITY + ["git", "clean", "-xdf"], OVERLAY_MERGED), + run(NICE_LOW_PRIORITY + ["git", "submodule", "init"], OVERLAY_MERGED), + run(NICE_LOW_PRIORITY + ["git", "submodule", "update"], OVERLAY_MERGED), + ] + cloudlog.info("git reset success: %s", '\n'.join(r)) + + # Un-set the validity flag to prevent the finalized tree from being + # activated later if the finalize step is interrupted + remove_consistent_flag() + + finalize_from_ovfs_copy() + + # Make sure the validity flag lands on disk LAST, only when the local git + # repo and OP install are in a consistent state. + set_consistent_flag() + + cloudlog.info("update successful!") + else: + cloudlog.info("nothing new from git at this time") + + set_update_available_params(new_version=new_version) + + def main(gctx=None): + overlay_init_done = False + wait_helper = WaitTimeHelper() params = Params() + if not os.geteuid() == 0: + raise RuntimeError("updated must be launched as root!") + + # Set low io priority + p = psutil.Process() + if psutil.LINUX: + p.ionice(psutil.IOPRIO_CLASS_BE, value=7) + + ov_lock_fd = open('/tmp/safe_staging_overlay.lock', 'w') + try: + fcntl.flock(ov_lock_fd, fcntl.LOCK_EX | fcntl.LOCK_NB) + except IOError: + raise RuntimeError("couldn't get overlay lock; is another updated running?") + while True: time_wrong = datetime.datetime.now().year < 2019 ping_failed = subprocess.call(["ping", "-W", "4", "-c", "1", "8.8.8.8"]) - if ping_failed or time_wrong: - time.sleep(60) - continue - # download application update - try: - r = subprocess.check_output(NICE_LOW_PRIORITY + ["git", "fetch"], stderr=subprocess.STDOUT).decode('utf8') - except subprocess.CalledProcessError as e: - cloudlog.event("git fetch failed", - cmd=e.cmd, - output=e.output, - returncode=e.returncode) - time.sleep(60) - continue - cloudlog.info("git fetch success: %s", r) - - # Write update available param - try: - cur_hash = subprocess.check_output(["git", "rev-parse", "HEAD"]).rstrip() - upstream_hash = subprocess.check_output(["git", "rev-parse", "@{u}"]).rstrip() - params.put("UpdateAvailable", str(int(cur_hash != upstream_hash))) - except: - params.put("UpdateAvailable", "0") + # Wait until we have a valid datetime to initialize the overlay + if not (ping_failed or time_wrong): + try: + # If the git directory has modifcations after we created the overlay + # we need to recreate the overlay + if overlay_init_done: + overlay_init_fn = os.path.join(BASEDIR, ".overlay_init") + git_dir_path = os.path.join(BASEDIR, ".git") + new_files = run(["find", git_dir_path, "-newer", overlay_init_fn]) - # Write latest release notes to param - try: - r = subprocess.check_output(["git", "--no-pager", "show", "@{u}:RELEASES.md"]) - r = r[:r.find(b'\n\n')] # Slice latest release notes - params.put("ReleaseNotes", r + b"\n") - except: - params.put("ReleaseNotes", "") + if len(new_files.splitlines()): + cloudlog.info(".git directory changed, recreating overlay") + overlay_init_done = False + + if not overlay_init_done: + init_ovfs() + overlay_init_done = True + + if params.get("IsOffroad") == b"1": + attempt_update() + else: + cloudlog.info("not running updater, openpilot running") + + except subprocess.CalledProcessError as e: + cloudlog.event( + "update process failed", + cmd=e.cmd, + output=e.output, + returncode=e.returncode + ) + overlay_init_done = False + except Exception: + cloudlog.exception("uncaught updated exception, shouldn't happen") + overlay_init_done = False - t = datetime.datetime.now().isoformat() - params.put("LastUpdateTime", t.encode('utf8')) + wait_between_updates(wait_helper.ready_event) + if wait_helper.shutdown: + break - time.sleep(60*60) + # We've been signaled to shut down + dismount_ovfs() if __name__ == "__main__": main() diff --git a/selfdrive/version.py b/selfdrive/version.py index 21c042923e..d2f6651963 100644 --- a/selfdrive/version.py +++ b/selfdrive/version.py @@ -48,7 +48,7 @@ try: dirty_files = subprocess.check_output(["git", "diff-index", branch, "--"], encoding='utf8') commit = subprocess.check_output(["git", "rev-parse", "--verify", "HEAD"], encoding='utf8').rstrip() origin_commit = subprocess.check_output(["git", "rev-parse", "--verify", branch], encoding='utf8').rstrip() - cloudlog.event("dirty comma branch", vesion=version, dirty=dirty, origin=origin, branch=branch, dirty_files=dirty_files, commit=commit, origin_commit=origin_commit) + cloudlog.event("dirty comma branch", version=version, dirty=dirty, origin=origin, branch=branch, dirty_files=dirty_files, commit=commit, origin_commit=origin_commit) else: dirty = True @@ -59,7 +59,7 @@ except subprocess.CalledProcessError: pass dirty = True -training_version = b"0.1.0" +training_version = b"0.2.0" terms_version = b"2" if __name__ == "__main__":