diff --git a/.gitignore b/.gitignore index 8ed8c2c0cabf17..6ed87a3f859315 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 b5a140c5a80f2f..9faa5c282b46ae 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 4f8bc525e81469..4d3e046de077e2 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 b4e69cd0595f75..045857cd1b6588 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 00ae8f969144aa..013397a7744c03 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 2e99a28bc06feb..1b4caf963436fb 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 9de2ba53a1b923..404cc4491fb493 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 58f22edb3e0e9b..11ba39d194df6a 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 7e77114ab14a8b..2a84019cb95a73 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 5053090f144df5..e90f8c750f9b26 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 00000000000000..ec0efc67621992 --- /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 789e83023a078c..e0c1b2b52c16a4 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 68a723206a6d4b..48618a2780b1a9 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 b059218feba89c..bdd7ed1bb18e61 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 7a0d4936b3e653..e5a004740dfaaa 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 @@ def __init__(self, services, ignore_alive=None, addr="127.0.0.1"): 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 7abcdd09dae6e0..8e29566ca26c64 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 bf017d900b6e3f..d37b8c986d7237 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 9b12b298495112..1a9f860cd35666 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 380b9c7fe6aee2..4ccd13df44527a 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 884bfe9a5bf991..e551dac59f9508 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 eda82385a86ce2..e88080884c2401 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 43ae48882b956e..d573327806dd8b 100644 --- a/common/logging_extra.py +++ b/common/logging_extra.py @@ -78,28 +78,6 @@ def __init__(self): 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 5067aa8d42b92a..3a4e4a2a167516 100755 --- a/common/params.py +++ b/common/params.py @@ -69,9 +69,10 @@ class UnknownKeyName(Exception): "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 @@ class UnknownKeyName(Exception): "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 734015bcf0c082..3582d3feed030a 100644 --- a/common/spinner.py +++ b/common/spinner.py @@ -5,21 +5,31 @@ 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 960c063f9436e5..489874eb6e1551 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 fb009b4c1c5c20..6e2692bfad93cc 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 5e2389fe37bddd..a33deaafd61ff1 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 2ff6435ed2caec..00000000000000 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 74a4337a9a707b..59104e18e865ff 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 58dee250f73032..00000000000000 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 00000000000000..fb48eb2ecb5769 Binary files /dev/null and b/models/supercombo.dlc differ diff --git a/opendbc/.gitignore b/opendbc/.gitignore index 5eb52dcca33ae9..9e48c6745a59f0 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 235383eb2d0a9c..b1e2b2cb854c54 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 56f4201a145d1e..1a87ebc55061af 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 3841610a6abd65..6ac0f9ddd5aceb 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 6f7a47d0ae3f0b..48d1c260a952dc 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 @@ def get_ext_filename(self, ext_name): 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 @@ def get_ext_filename(self, ext_name): 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 8ce6e7e7b4dd9a..5662530d7d8eb3 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 @@ def get_ext_filename(self, ext_name): 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 @@ def get_ext_filename(self, ext_name): 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 00000000000000..c4df547dca8d55 --- /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 19585529f01bd3..488eed42417bc5 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 d805d45e87a120..de78403179d680 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 df774482049702..2d3c1a9d2e61eb 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 2fccfd1b2eb4e0..01d9d64383be56 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 2cce31609d179a..da4f59bdaa96d9 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 b41171d4345f90..6d113fafdc9604 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 9c2bf64b5a746d..ed64c1feeb6e38 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 4ad9f2a0621580..4ceda6aefa35a1 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 8f045489106e1f..64cff2e01f32db 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 7927f8c80f4dd5..3ffe59a118e548 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 ea9ec396444332..1da2248b60594f 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 cec7a08e7d295d..adc23d68793275 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 0cf9ea5662e65c..48c571df1f5e65 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 770cfdf1fd5eec..b160dff8537b9e 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 06c6edabdfb64a..d6c9505d94f961 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 cb83511b3df59f..26173859b4398f 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 7aa93a96356832..db11aa3a719596 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 5d3e81ecbd5bc5..ed90b9408d6169 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 ec9cc18abdad97..8730e0357541e2 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 d973416b6e8122..a9cf3eb9e69ece 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 3490737c8e8369..fe76cbf57aa8c1 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 890ae8a2e6afd3..775e22adad132e 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 50868b61882d8b..36af55b113bdd2 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 9ac4b79f99e577..3c5a88a35619cd 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 4c6b14dcd7f79f..1f8221323da2c4 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 a6f719ece1f5ae..cdfb2310038eaf 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 ea0df2a19c246e..9979295a0b2834 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 07895e3e08d2d1..93db2565ca5342 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 dd4edb33d1e6c7..a758bf70520be8 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 8526a5b993edb2..f48f6203cb7a40 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 9091322f1a1091..0b09d8ff8be337 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 0a216e5b1f6204..4588eece653b03 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 ccfa78d3f76b8b..0f500a8cd10327 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 ce9f65f2afc536..8c201a3bb40cad 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 4733438c9c4bd1..ba96b7dd99c874 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 df515b05d6ad8f..a39c4125cefee5 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 47c7342a448a51..97e0f57a2cd6ee 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 92c32ad8086a7d..5356a113f68baa 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 36fd1d8f2adfa9..e7eddf454a1963 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 ab8ceb52905206..b49c9293631c43 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 b2d215f6876217..fcf112a96467e7 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 f1215f23da2acb..f6b19c1a2fab3a 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 66e5947f856dfb..b4ff5f29d9dd21 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 2e5d20c622826e..fbb464dcde1cc0 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 0576a463816f62..844e387fef7716 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 d5833e45db5544..e9515658cdded0 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 c16e559ce18b23..4b01fd4bcd8942 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 e192d74fb7c345..1a6a8dd21a16f9 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 fbdbab8a61e0cf..1c703516ac1731 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 4b9de8c442828a..b77937ce7c8294 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 93d75c14be1c7a..b9a085a6c04ba7 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 06c7a51101914d..786a3187f1f225 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 22879c7cae8e2c..ccda7a6b232558 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 f19c743461d661..bab867ab49ffdc 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 2af24364ff3a36..e22278d4d0a934 100644 --- a/panda/drivers/windows/pandaJ2534DLL/MessageRx.h +++ b/panda/drivers/windows/pandaJ2534DLL/MessageRx.h @@ -21,7 +21,7 @@ class MessageRx } 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 19ae43b0d70d08..e250ded7b44ff0 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 fd5eac56dd4d4a..bc9d145e0fac5f 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 2b5f3120c34721..9174d7e36dd532 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 117fc92760bfd4..541d30584ff972 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 3e74ab1d9c5b33..f23968d744c5ff 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 8f4ae29181bb69..ea8dea13d93874 100644 --- a/panda/python/__init__.py +++ b/panda/python/__init__.py @@ -23,14 +23,14 @@ 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 @@ def call_control_api(self, msg): # ******************* 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 @@ def get_signature_from_firmware(fn): 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 ee9e9ea667351d..96d07e1a722a0f 100644 --- a/panda/python/uds.py +++ b/panda/python/uds.py @@ -268,17 +268,19 @@ class InvalidSubFunctioneError(Exception): 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 @@ def recv(self, drain=False) -> List[bytes]: 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 @@ def send(self, msgs: List[bytes], delay: float=0) -> None: 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 @@ def _tx_first_frame(self) -> None: 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 @@ def _isotp_rx_next(self, rx_data: bytes) -> None: 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 @@ def _isotp_rx_next(self, rx_data: bytes) -> None: 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 @@ def _isotp_rx_next(self, rx_data: bytes) -> None: # 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 @@ def read_dtc_information(self, dtc_report_type: DTC_REPORT_TYPE, dtc_status_mask 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 00000000000000..fc387c996916b2 --- /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 78a9287c10be7e..6b963e954f8f35 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 @@ 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 @@ def init_panda_serials(): 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 de9b224a1ac351..d3be8ff867c8e7 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 e0a270831a3526..0a479bc586942a 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 99f72379211986..63408ce430ed50 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 5b1bd28c9ad7d9..77131c1a3c8e53 100644 --- a/panda/tests/safety/libpandasafety_py.py +++ b/panda/tests/safety/libpandasafety_py.py @@ -30,14 +30,10 @@ 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 @@ 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 @@ 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 de12a4d046a802..59611d3131c67e 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 99c15750c46fd5..06872dede5b1e4 100644 --- a/panda/tests/safety/test_gm.py +++ b/panda/tests/safety/test_gm.py @@ -141,15 +141,10 @@ def test_not_allow_brake_when_moving(self): 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 @@ def test_allow_engage_with_gas_pressed(self): 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 f89e7a593f4e85..87f708930402a9 100755 --- a/panda/tests/safety/test_honda.py +++ b/panda/tests/safety/test_honda.py @@ -3,36 +3,66 @@ 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 @@ def _alt_brake_msg(self, brake): 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 @@ def _send_steer_msg(self, steer): 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 @@ def test_prev_gas_interceptor(self): 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 @@ def test_allow_engage_with_gas_pressed(self): 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 @@ def test_allow_engage_with_gas_interceptor_pressed(self): 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 @@ def test_spam_cancel_safety_check(self): 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 eed3622bcda9f2..99c8d35464d956 100755 --- a/panda/tests/safety/test_honda_bosch.py +++ b/panda/tests/safety/test_honda_bosch.py @@ -3,6 +3,7 @@ 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 58e32f036e50b0..10181624547946 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 @@ def _set_prev_torque(self, t): 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 @@ def _send_interceptor_msg(self, gas, addr): 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 @@ def test_prev_gas_interceptor(self): 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 @@ def test_allow_engage_with_gas_pressed(self): 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 @@ def test_allow_engage_with_gas_interceptor_pressed(self): 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 @@ def test_gas_interceptor_safety_check(self): 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 680fc149b7e55c..3fcca95f1ca53c 100644 --- a/panda/tests/safety/test_toyota_ipas.py +++ b/panda/tests/safety/test_toyota_ipas.py @@ -3,7 +3,8 @@ 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 @@ def _torque_driver_msg(self, torque): 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 99d0916e46d0a8..db58cdc5811a45 100644 --- a/panda/tests/safety/test_volkswagen.py +++ b/panda/tests/safety/test_volkswagen.py @@ -87,16 +87,10 @@ def test_disable_control_allowed_from_cruise(self): 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 8fa1d3a1e9ebab..b5fe1a09a06873 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 09c677cacb83af..456723cb2b1f10 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 4b2f5372df07c5..fd36b248e396e5 100755 --- a/panda/tests/safety_replay/test_safety_replay.py +++ b/panda/tests/safety_replay/test_safety_replay.py @@ -14,7 +14,7 @@ ("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 00000000000000..4243d30e9f9ea5 --- /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 00000000000000..3f0193f081a15c --- /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 99226176bce4c5..0bedfdeb72ae62 100755 --- a/selfdrive/athena/test.py +++ b/selfdrive/athena/test.py @@ -32,10 +32,8 @@ def test_echo(self): 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 @@ def send_thermal(): p = Process(target=send_thermal) p.start() + time.sleep(0.1) try: thermal = dispatcher["getMessage"]("thermal") assert thermal['thermal'] @@ -60,7 +59,7 @@ def test_listDataDirectory(self): 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 @@ def test_do_upload(self): 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 @@ def test_uploadFileToUrl(self): 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 @@ def test_uploadFileToUrl(self): 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 a6b2d48978c7c7..2335ce89c500c5 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 @@ def do_PUT(self): 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 e8a313d90478ea..37ee22e7004f83 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 7679a5248d10b1..896a4cac678f88 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 e3a96617be15cc..4467788611572e 100644 --- a/selfdrive/car/car_helpers.py +++ b/selfdrive/car/car_helpers.py @@ -3,6 +3,7 @@ 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 2a6422ecbff7e9..f96d95ae981352 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -35,13 +35,12 @@ def compute_gb(accel, speed): 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 0e29e6c1e71139..4ca9fa09318d02 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 5b2deed550f065..70df1cf954705d 100755 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -34,13 +34,12 @@ def compute_gb(accel, speed): 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 00000000000000..1175c5978421c8 --- /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 eee03b11d3f474..b58a1a9979aa9a 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -43,12 +43,11 @@ def compute_gb(accel, speed): 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 2ba51ce4e67364..9b0e0706ce5849 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 @@ def __init__(self, dbc_name): 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 @@ def update(self, enabled, CS, frame, actuators, \ 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 @@ def update(self, enabled, CS, frame, actuators, \ 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 @@ def update(self, enabled, CS, frame, actuators, \ 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 @@ def update(self, enabled, CS, frame, actuators, \ 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 55f86d25cea4f0..39b91c866462d8 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 @@ def update(self, cp, cp_cam): 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 411d0c881fdbea..38d099fdceff7a 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 9ffc92e75b5f76..b1abeed3dce8dd 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -8,12 +8,12 @@ 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 @@ def __init__(self, CP, CarController): 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 @@ def calc_accel_override(a_ego, a_target, v_ego, v_target): 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 @@ def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay 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 @@ def get_params(candidate, fingerprint=gen_empty_fingerprint(), vin="", has_relay 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 @@ def apply(self, c): 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 @@ def apply(self, c): 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 90dfd4eab32a9f..4301128bc65960 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 @@ class CAR: 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 @@ class CAR: 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 39d04d3bc8916e..50c31af3d2295b 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -38,13 +38,12 @@ def compute_gb(accel, speed): 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 7a32752781bcca..ca1972a1679429 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -18,7 +18,7 @@ def compute_gb(accel, speed): 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 00000000000000..cda36d50fbd5e7 --- /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 30df9f2fd3da56..09c5b5c6123f48 100755 --- a/selfdrive/car/mock/interface.py +++ b/selfdrive/car/mock/interface.py @@ -34,7 +34,7 @@ def compute_gb(accel, speed): 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 cd102766df0c53..d4388727bba083 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -35,13 +35,12 @@ def compute_gb(accel, speed): 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 3c6772228c470c..83f499f4509f78 100755 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -37,13 +37,12 @@ def compute_gb(accel, speed): 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 5c7c49a69bcb72..f8edbf48bc4bc8 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 @@ class ECU: }] } +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 605e22d50dfb75..648f4165117ca1 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 14c58b367939eb..0e8b5206d3d684 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -42,12 +42,11 @@ def compute_gb(accel, speed): 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 00000000000000..a6d841d65ea4f0 --- /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 00000000000000..63c508c4fe5844 --- /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 00000000000000..0dba6259e24100 --- /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 757c2a1ead46f0..788b812997f3f3 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 6091eebce50780..52c60d8ec73f31 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 6e0e8b186f33ba..79bc5d911f4fe2 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 01b8a0b6d92c80..9bdb23f9991567 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 6f1cf7ff002338..d61e42c497bfa6 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 74b0f3137d1b8c..1cc0cb0ac1768a 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 ad39b19b879757..3cc1de90ef869a 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 e9295bfef7a110..83d430f071c73b 100644 --- a/selfdrive/controls/lib/alerts.py +++ b/selfdrive/controls/lib/alerts.py @@ -410,6 +410,13 @@ def __gt__(self, alert2): 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 @@ def __gt__(self, alert2): 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 @@ def __gt__(self, alert2): 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 13a8130b7c9d76..7539559752b702 100644 --- a/selfdrive/controls/lib/driver_monitor.py +++ b/selfdrive/controls/lib/driver_monitor.py @@ -20,9 +20,9 @@ _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 @@ def _is_driver_distracted(self, pose, blink): 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 87e3c520fca08f..8a6e5286f37c46 100644 --- a/selfdrive/controls/lib/pathplanner.py +++ b/selfdrive/controls/lib/pathplanner.py @@ -14,6 +14,9 @@ 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 @@ def update(self, sm, pm, CP, VM): # 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 @@ def update(self, sm, pm, CP, VM): 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 @@ def update(self, sm, pm, CP, VM): # 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 6646e134546628..1d6140a8167b82 100755 --- a/selfdrive/controls/lib/planner.py +++ b/selfdrive/controls/lib/planner.py @@ -27,7 +27,8 @@ # 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 @@ 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 @@ def __init__(self, CP): 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 @@ def update(self, sm, pm, CP, VM, PP): 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 @@ def update(self, sm, pm, CP, VM, PP): 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 @@ def update(self, sm, pm, CP, VM, PP): 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 cc70bb4d3843e7..63545e6ee49409 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 3811d24f8c9449..cd92a5f630dae8 100755 --- a/selfdrive/locationd/calibrationd.py +++ b/selfdrive/locationd/calibrationd.py @@ -10,19 +10,23 @@ 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 @@ def __init__(self, param_put=False): 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 @@ def update_status(self): 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 @@ def send_data(self, pm): 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 83c837d7fb1bba..b2b87557ce49e0 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 6a392d15d6fdaf..b319c773c2b728 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 14e1e67a9eb44d..0ee6fa671d0327 100644 --- a/selfdrive/loggerd/config.py +++ b/selfdrive/loggerd/config.py @@ -9,11 +9,21 @@ 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 5669e2342d2318..1c687ff4b0cf9a 100644 --- a/selfdrive/loggerd/deleter.py +++ b/selfdrive/loggerd/deleter.py @@ -3,15 +3,15 @@ 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 4334af0f3ad650..1b3a81d7a479db 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 adbb0f0316fc21..f06946b2fe9918 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 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 @@ def fake_statvfs(self, d): 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 @@ def test_delete_files_in_create_order(self): 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 @@ def test_no_delete_with_lock_file(self): 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 bea384b5431756..8f7e0a67a4716d 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 b603bf3d412f53..358eb38937159f 100755 --- a/selfdrive/manager.py +++ b/selfdrive/manager.py @@ -5,10 +5,12 @@ 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 @@ except FileExistsError: pass -if os.path.isfile('/EON'): +if ANDROID: os.chmod("/dev/shm", 0o777) def unblock_stdout(): @@ -74,7 +76,11 @@ def unblock_stdout(): # 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 @@ def unblock_stdout(): 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 @@ def unblock_stdout(): "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 @@ def get_running(): # 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 b752bb3ade87bf..aa995fb3f4cec4 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 cb7dc65e7bdcc4..3629f7a71a931c 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 276a347925c8e0..fa49d1b5dff303 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 0369d16d5dd05d..143480fb0bd608 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 2a03a3d00fbcfd..4e3ee448cfc78f 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 127e3c2e80bbbd..06c820ff7996da 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 ccf8a94be291bf..bf46cb9d472ae6 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 c843e81f4d919f..00000000000000 --- 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 2e6571a1d4b7e0..00000000000000 --- 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 63e28b12f726df..419d8263314183 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 049f06584509ee..56e78539745470 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 2ef286fa7a6a3a..7cbc704b98f352 100755 --- a/selfdrive/pandad.py +++ b/selfdrive/pandad.py @@ -4,19 +4,29 @@ 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 734f6f8713519f..afa2771bc1b13a 100644 --- a/selfdrive/registration.py +++ b/selfdrive/registration.py @@ -7,6 +7,7 @@ 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 54eb6b4dc42007..ae2ecec0352c4b 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 0f70bb66c09bbc..952a4863c20393 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 5dd1d0789ba42a..06b2437695769c 100755 --- a/selfdrive/test/longitudinal_maneuvers/plant.py +++ b/selfdrive/test/longitudinal_maneuvers/plant.py @@ -272,6 +272,7 @@ def step(self, v_lead=0.0, cruise_buttons=None, grade=0.0, publish_model = True) 'INTERCEPTOR_GAS', 'INTERCEPTOR_GAS2', 'IMPERIAL_UNIT', + 'MOTOR_TORQUE', ]) vls = vls_tuple( self.speed_sensor(speed), @@ -304,7 +305,8 @@ def step(self, v_lead=0.0, cruise_buttons=None, grade=0.0, publish_model = True) 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 fdce596e41edb0..14969954c24060 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 @@ def radar_rcv_callback(msg, CP): }, 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 0c0be19b61858f..823608db0ebdac 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 0d18496d52c639..c1aa39a7fa5166 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 @@ def get_route_logs(route_name): #"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 @@ def get_route_logs(route_name): 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 68e35d90bc62f8..27b964c47dd5b4 100644 --- a/selfdrive/test/test_openpilot.py +++ b/selfdrive/test/test_openpilot.py @@ -149,11 +149,11 @@ def expect_athena_starts(timeout=30): 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 athena_post(payload, max_retries=5): 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 expect_athena_registers(timeout=60): "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 expect_athena_registers(timeout=60): "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_thermal(): "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 d78e0011d16dfd..aa4c47a6ee899c 100755 --- a/selfdrive/thermald.py +++ b/selfdrive/thermald.py @@ -6,6 +6,7 @@ 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.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 @@ 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 b3e96e79afe444..ad96cb0a4d6942 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 00000000000000..62531e356da233 --- /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 00000000000000..0728a5eab3b086 --- /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 00000000000000..701fa56b4ce11b --- /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 00000000000000..cc44c1b4b3f514 --- /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 fb22ad790d8e0b..6a36f49198b7c9 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 00000000000000..e520f6eae48d2c --- /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 1ac216c4fee0e3..efde9adcc8cdb0 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 21c042923ee513..d2f66519630610 100644 --- a/selfdrive/version.py +++ b/selfdrive/version.py @@ -48,7 +48,7 @@ def get_git_remote(): 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 @@ def get_git_remote(): pass dirty = True -training_version = b"0.1.0" +training_version = b"0.2.0" terms_version = b"2" if __name__ == "__main__":